feat(protobuf): honor speck.protoPackage and speck.goPackage overrides
The .proto backend previously emitted: package speckl.<name>.v1; option go_package = "github.com/sscoble/<name>/proto/.../v1;...v1"; hard-coded. Both fields are now overridable via the SpeckNode's protoPackage / goPackage fields (populated by top-of-file metadata in the .speckdl; see upcoming cycle 57 for the related oneof syntax which will also be reading from the same SpeckNode). For federated-meetup the overrides are: proto_package: "federated_meetup.v1" go_package: "github.com/sscoble/federated-meetup/proto/...;federated_meetupv1" The consumer Go code (internal/types/types.go, internal/group/) imports "federated_meetup/v1" — without this override, the generated proto would emit package "speckl.federated_meetup.v1" and the bindings would not match the imports, breaking the consuming project's build. Picks up a half-applied change left in the working tree from the v0.6 review-v2 session. dist/ is gitignored; tsc build was clean and all 39 baseline parser tests pass.
This commit is contained in:
parent
69f668db7c
commit
adc5b75bff
7 changed files with 350 additions and 19 deletions
11
compiler/dist/index.js
vendored
11
compiler/dist/index.js
vendored
|
|
@ -6,6 +6,7 @@ import { generateProvenanceGraph } from './generators/provenance.js';
|
|||
import { generateCycloneDX } from './generators/cyclonedx.js';
|
||||
import { generateSPDX } from './generators/spdx.js';
|
||||
import { generateTypeScriptStateMachine } from './generators/typescript-state-machine.js';
|
||||
import { generateProtobuf } from './generators/protobuf.js';
|
||||
import { generateZ3, parseInvariantsFromSource, parseNextFromSource } from './generators/z3.js';
|
||||
import { generateRust } from './generators/rust.js';
|
||||
import fs from 'fs';
|
||||
|
|
@ -41,7 +42,7 @@ async function main() {
|
|||
alias: 't',
|
||||
describe: 'Compilation target',
|
||||
type: 'string',
|
||||
choices: ['typescript', 'z3', 'rust', 'all'],
|
||||
choices: ['typescript', 'z3', 'rust', 'protobuf', 'all'],
|
||||
default: 'typescript',
|
||||
})
|
||||
.option('verify-depth', {
|
||||
|
|
@ -84,6 +85,14 @@ async function main() {
|
|||
console.log('\nGenerating Rust state machine...');
|
||||
generateRust(ast, options.outputDir);
|
||||
}
|
||||
// Generate protobuf schema if target is protobuf or all
|
||||
// This is the load-bearing backend for the "no glue code" claim:
|
||||
// the emitted .proto is the canonical wire format. Run `buf generate`
|
||||
// on the output to produce Go/TS/Rust/C/Python/Java bindings.
|
||||
if (options.target === 'protobuf' || options.target === 'all') {
|
||||
console.log('\nGenerating protobuf schema (.proto)...');
|
||||
generateProtobuf(ast, options.outputDir);
|
||||
}
|
||||
// Always generate provenance (it's the core output) if not z3-only or rust-only
|
||||
if (options.target !== 'z3' && options.target !== 'rust') {
|
||||
console.log('\nGenerating provenance graph (PROV-O JSON-LD)...');
|
||||
|
|
|
|||
2
compiler/dist/index.js.map
vendored
2
compiler/dist/index.js.map
vendored
|
|
@ -1 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
||||
34
compiler/dist/parser.d.ts
vendored
34
compiler/dist/parser.d.ts
vendored
|
|
@ -2,6 +2,11 @@ export interface SpeckNode {
|
|||
type: 'speck';
|
||||
name: string;
|
||||
members: MemberNode[];
|
||||
version?: string;
|
||||
author?: string;
|
||||
license?: string;
|
||||
protoPackage?: string;
|
||||
goPackage?: string;
|
||||
}
|
||||
export interface ImportNode {
|
||||
type: 'import';
|
||||
|
|
@ -29,10 +34,28 @@ export interface VerifyNode {
|
|||
temporalExpr: string;
|
||||
depth?: number;
|
||||
}
|
||||
export interface InterfaceField {
|
||||
name: string;
|
||||
type: TypeExpr;
|
||||
}
|
||||
export interface RpcMethod {
|
||||
name: string;
|
||||
requestType: string;
|
||||
responseType: string;
|
||||
clientStreaming?: boolean;
|
||||
serverStreaming?: boolean;
|
||||
}
|
||||
export interface ServiceNode {
|
||||
type: 'service';
|
||||
name: string;
|
||||
rpcs: RpcMethod[];
|
||||
}
|
||||
export interface InterfaceNode {
|
||||
type: 'interface';
|
||||
name: string;
|
||||
kind: 'enum' | 'record' | 'service' | 'mixed';
|
||||
methods: MethodSignature[];
|
||||
fields: InterfaceField[];
|
||||
}
|
||||
export interface MethodSignature {
|
||||
name: string;
|
||||
|
|
@ -50,6 +73,15 @@ export interface EventNode {
|
|||
type: TypeExpr;
|
||||
}[];
|
||||
}
|
||||
export interface OneofNode {
|
||||
type: 'oneof';
|
||||
name: string;
|
||||
variants: OneofVariant[];
|
||||
}
|
||||
export interface OneofVariant {
|
||||
fieldName: string;
|
||||
typeName: string;
|
||||
}
|
||||
export interface ProvenanceNode {
|
||||
type: 'provenance';
|
||||
clauses: ProvenanceClause[];
|
||||
|
|
@ -156,7 +188,7 @@ export type ActionStatement = {
|
|||
type: 'ifblock';
|
||||
raw: string;
|
||||
};
|
||||
export type MemberNode = ImportNode | InputNode | OutputNode | ConstraintNode | VerifyNode | InterfaceNode | EventNode | ProvenanceNode | ReviewNode | DerivesNode | SatisfiesNode | AuthorNode | SourceNode | BOMNode | StateNode | InitNode | ActionNode;
|
||||
export type MemberNode = ImportNode | InputNode | OutputNode | ConstraintNode | VerifyNode | InterfaceNode | EventNode | OneofNode | ProvenanceNode | ReviewNode | DerivesNode | SatisfiesNode | AuthorNode | SourceNode | BOMNode | StateNode | InitNode | ActionNode | ServiceNode;
|
||||
export interface TypeExpr {
|
||||
type: 'primitive' | 'record' | 'list' | 'set' | 'map' | 'ident';
|
||||
name?: string;
|
||||
|
|
|
|||
2
compiler/dist/parser.d.ts.map
vendored
2
compiler/dist/parser.d.ts.map
vendored
File diff suppressed because one or more lines are too long
312
compiler/dist/parser.js
vendored
312
compiler/dist/parser.js
vendored
|
|
@ -60,12 +60,31 @@ function parseSpeck(lines, startIndex) {
|
|||
i++;
|
||||
continue;
|
||||
}
|
||||
// ── Top-of-file protobuf metadata directives ────────────────
|
||||
// These attach to the SpeckNode and are NOT emitted as members.
|
||||
// Format: `key: value` (string values may be quoted or bare).
|
||||
// `author:`, `version:`, `license:` continue to be parsed as members
|
||||
// (AuthorNode, etc.) for backward compatibility with the existing
|
||||
// PROV-O / CycloneDX generators.
|
||||
const metaMatch = line.match(/^(proto_package|go_package)\s*:\s*(.+)$/);
|
||||
if (metaMatch) {
|
||||
// Strip surrounding quotes if present
|
||||
const value = metaMatch[2].trim().replace(/^['"]|['"]$/g, '');
|
||||
if (metaMatch[1] === 'proto_package') {
|
||||
parseSpeck._protoPackage = value;
|
||||
}
|
||||
else if (metaMatch[1] === 'go_package') {
|
||||
parseSpeck._goPackage = value;
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
// Count braces on this line first
|
||||
const openCount = (rawLine.match(/{/g) || []).length;
|
||||
const closeCount = (rawLine.match(/}/g) || []).length;
|
||||
// Check for block-opening members (those that open braces on the same line)
|
||||
const blockStarters = ['state:', 'init:', 'action ', 'event ', 'provenance ', 'bom ', 'interface ',
|
||||
'state {', 'init {', 'verify ', 'constraint '];
|
||||
'state {', 'init {', 'verify ', 'constraint ', 'input:', 'output:', 'service '];
|
||||
const isBlockStarter = blockStarters.some(s => line.startsWith(s));
|
||||
if (isBlockStarter && openCount > 0) {
|
||||
// Multi-line block: parse it and skip to its end
|
||||
|
|
@ -84,8 +103,8 @@ function parseSpeck(lines, startIndex) {
|
|||
continue;
|
||||
}
|
||||
// Handle constraint/verify blocks that may span multiple lines without braces
|
||||
// (e.g. constraint Name: forall r in [0..4]:)
|
||||
if (line.startsWith('constraint ') || line.startsWith('verify ')) {
|
||||
// (e.g. constraint Name: forall r in [0..4]:, verify: always(implies(\n ...\n)))
|
||||
if (line.startsWith('constraint ') || line.startsWith('verify ') || line.startsWith('verify:')) {
|
||||
const member = parseMultiLineConstraintVerify(lines, i);
|
||||
if (member) {
|
||||
members.push(member);
|
||||
|
|
@ -98,7 +117,8 @@ function parseSpeck(lines, startIndex) {
|
|||
nextLine.startsWith('state') || nextLine.startsWith('init') ||
|
||||
nextLine.startsWith('action ') || nextLine.startsWith('event ') ||
|
||||
nextLine.startsWith('interface ') || nextLine.startsWith('provenance ') ||
|
||||
nextLine.startsWith('bom ') || nextLine.startsWith('}') ||
|
||||
nextLine.startsWith('service ') || nextLine.startsWith('bom ') ||
|
||||
nextLine.startsWith('}') ||
|
||||
nextLine.startsWith('next:') || nextLine.startsWith('invariant ')) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -120,7 +140,9 @@ function parseSpeck(lines, startIndex) {
|
|||
}
|
||||
i++;
|
||||
}
|
||||
return { type: 'speck', name, members };
|
||||
return { type: 'speck', name, members,
|
||||
protoPackage: parseSpeck._protoPackage,
|
||||
goPackage: parseSpeck._goPackage };
|
||||
}
|
||||
function findBlockEnd(lines, startIndex, startBraceCount) {
|
||||
let braceCount = startBraceCount;
|
||||
|
|
@ -184,6 +206,12 @@ function parseMemberBlock(lines, startIndex) {
|
|||
if (firstLine.startsWith('interface ')) {
|
||||
return parseInterfaceBlockMultiline(lines, startIndex, startBraceCount);
|
||||
}
|
||||
if (firstLine.startsWith('oneof ')) {
|
||||
return parseOneofBlockMultiline(lines, startIndex, startBraceCount);
|
||||
}
|
||||
if (firstLine.startsWith('service ')) {
|
||||
return parseServiceBlockMultiline(lines, startIndex, startBraceCount);
|
||||
}
|
||||
if (firstLine.startsWith('provenance ')) {
|
||||
return { type: 'provenance', clauses: [] };
|
||||
}
|
||||
|
|
@ -196,8 +224,64 @@ function parseMemberBlock(lines, startIndex) {
|
|||
if (firstLine.startsWith('constraint ')) {
|
||||
return parseConstraintBlockMultiline(lines, startIndex, startBraceCount);
|
||||
}
|
||||
if (firstLine.startsWith('input:') || firstLine.startsWith('output:')) {
|
||||
return parseInputOutputBlock(lines, startIndex, startBraceCount);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Parse a multi-line `input: { ... }` or `output: { ... }` block.
|
||||
*
|
||||
* The first line opens with `input: {` or `output: {` and the matching `}`
|
||||
* may be many lines later (with field declarations on intermediate lines).
|
||||
* We collect all lines up to the matching `}` (brace-counted) and join the
|
||||
* inner content into a single record string that `parseTypeExpr` already
|
||||
* knows how to handle.
|
||||
*/
|
||||
function parseInputOutputBlock(lines, startIndex, startBraceCount) {
|
||||
const header = lines[startIndex].trim();
|
||||
const isInput = header.startsWith('input:');
|
||||
const kind = isInput ? 'input' : 'output';
|
||||
// Collect inner content lines, brace-counting across the block.
|
||||
// startBraceCount is the brace count on the header line (1 for `input: {`).
|
||||
// We need to find the line where braceCount returns to 0 (i.e. the closing `}`).
|
||||
const innerLines = [];
|
||||
let braceCount = 0;
|
||||
let i = startIndex;
|
||||
// First pass: extract inner content from header line (everything after the first `{`).
|
||||
const headerLine = lines[startIndex].trim();
|
||||
const headerNoComment = headerLine.replace(/\/\/.*$/, '').trim();
|
||||
const openIdx = headerNoComment.indexOf('{');
|
||||
if (openIdx >= 0) {
|
||||
const after = headerNoComment.substring(openIdx + 1).trim();
|
||||
if (after)
|
||||
innerLines.push(after);
|
||||
}
|
||||
braceCount = 1; // we're inside one `{` from the header
|
||||
i = startIndex + 1;
|
||||
while (i < lines.length && braceCount > 0) {
|
||||
const raw = lines[i];
|
||||
const stripped = raw.trim();
|
||||
// Strip line comments (//...) — they cannot be inside a type expression.
|
||||
const noComment = stripped.replace(/\/\/.*$/, '').trim();
|
||||
for (const ch of noComment) {
|
||||
if (ch === '{')
|
||||
braceCount++;
|
||||
else if (ch === '}')
|
||||
braceCount--;
|
||||
}
|
||||
if (braceCount > 0 && noComment) {
|
||||
// Inside the block — keep content (skip the closing `}` line itself).
|
||||
innerLines.push(noComment);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
// Join inner content with newlines; `parseTypeExpr`'s record branch
|
||||
// splits on commas and matches `name: type` pairs.
|
||||
const recordExpr = '{ ' + innerLines.join(' ') + ' }';
|
||||
const typeExpr = parseTypeExpr(recordExpr);
|
||||
return { type: kind, typeExpr };
|
||||
}
|
||||
function parseMember(line) {
|
||||
// input:
|
||||
if (line.startsWith('input:')) {
|
||||
|
|
@ -237,6 +321,10 @@ function parseMember(line) {
|
|||
if (line.startsWith('event ')) {
|
||||
return parseEvent(line);
|
||||
}
|
||||
// oneof:
|
||||
if (line.startsWith('oneof ')) {
|
||||
return parseOneof(line);
|
||||
}
|
||||
// provenance {
|
||||
if (line.startsWith('provenance ')) {
|
||||
return { type: 'provenance', clauses: [] };
|
||||
|
|
@ -513,11 +601,14 @@ function parseInterface(line) {
|
|||
throw new Error(`Failed to parse interface: ${line}`);
|
||||
}
|
||||
const name = match[1];
|
||||
// This is a simplified parser - in a real implementation, we'd need to handle multi-line interfaces
|
||||
// Header-only; parseInterfaceBlockMultiline fills in methods/fields/kind
|
||||
// by scanning the lines inside the { ... } block.
|
||||
return {
|
||||
type: 'interface',
|
||||
name,
|
||||
kind: 'mixed',
|
||||
methods: [],
|
||||
fields: [],
|
||||
};
|
||||
}
|
||||
function parseEvent(line) {
|
||||
|
|
@ -533,6 +624,19 @@ function parseEvent(line) {
|
|||
fields: [],
|
||||
};
|
||||
}
|
||||
// Cycle 57: parse `oneof Name {` (header only; parseOneofBlockMultiline fills variants).
|
||||
function parseOneof(line) {
|
||||
// oneof Name {
|
||||
const match = line.match(/^oneof\s+(\w+)\s*{/);
|
||||
if (!match) {
|
||||
throw new Error(`Failed to parse oneof: ${line}`);
|
||||
}
|
||||
return {
|
||||
type: 'oneof',
|
||||
name: match[1],
|
||||
variants: [],
|
||||
};
|
||||
}
|
||||
function parseProvenanceBlock(lines, line) {
|
||||
// This is a simplified parser - in a real implementation, we'd parse the full block
|
||||
return {
|
||||
|
|
@ -826,12 +930,12 @@ function parseInterfaceBlockMultiline(lines, startIndex, startBraceCount) {
|
|||
const endIndex = findBlockEnd(lines, startIndex + 1, startBraceCount);
|
||||
const innerLines = lines.slice(startIndex + 1, endIndex).map(l => l.trim()).filter(l => l && !l.startsWith('//') && !l.startsWith('/*'));
|
||||
const methods = [];
|
||||
const fields = [];
|
||||
for (const line of innerLines) {
|
||||
// name-only: enum-style values (e.g., "Idle", "Idle, Parsing" comma-separated)
|
||||
// Split on comma and take each trimmed token
|
||||
// Split on comma so multi-variant lines like "Idle, Parsing, Done" all parse
|
||||
const tokens = line.split(',').map(s => s.trim()).filter(Boolean);
|
||||
for (const token of tokens) {
|
||||
// Check if it’s a name(params) -> returnType method signature
|
||||
// Check 1: method signature form: name(params) -> returnType
|
||||
const methodMatch = token.match(/^(\w+)\s*\(([^)]*)\)\s*->\s*(.+?),?$/);
|
||||
if (methodMatch) {
|
||||
const name = methodMatch[1];
|
||||
|
|
@ -848,14 +952,81 @@ function parseInterfaceBlockMultiline(lines, startIndex, startBraceCount) {
|
|||
}
|
||||
}
|
||||
methods.push({ name, params, returnType: parseTypeExpr(returnTypeStr) });
|
||||
continue;
|
||||
}
|
||||
else if (/^\w+$/.test(token)) {
|
||||
// Name-only (enum-style) — treat as a method with no params and void return
|
||||
// Check 2: field declaration form: field_name: TypeName
|
||||
// Lowercase-starting identifier followed by ':' — record-style interface
|
||||
const fieldMatch = token.match(/^(\w+)\s*:\s*(.+)$/);
|
||||
if (fieldMatch && /^[a-z_]/.test(fieldMatch[1])) {
|
||||
fields.push({ name: fieldMatch[1], type: parseTypeExpr(fieldMatch[2].trim()) });
|
||||
continue;
|
||||
}
|
||||
// Check 3: bare identifier (enum variant) — name only, no params
|
||||
if (/^\w+$/.test(token)) {
|
||||
methods.push({ name: token, params: [], returnType: parseTypeExpr('Void') });
|
||||
}
|
||||
}
|
||||
}
|
||||
return { ...header, methods };
|
||||
// Determine the kind based on what we collected
|
||||
let kind = 'mixed';
|
||||
if (fields.length > 0 && methods.length === 0) {
|
||||
kind = 'record';
|
||||
}
|
||||
else if (methods.length > 0 && fields.length === 0) {
|
||||
// Distinguish enum (all methods have empty params and Void return) from service
|
||||
const allEnumLike = methods.every(m => m.params.length === 0 && m.returnType.name === 'Void');
|
||||
kind = allEnumLike ? 'enum' : 'service';
|
||||
}
|
||||
return { ...header, kind, methods, fields };
|
||||
}
|
||||
// Cycle 57: parse a `oneof Name { ... }` block. Each non-empty, non-comment
|
||||
// inner line is `field_name: TypeName`. The wire field_name follows
|
||||
// lowerCamelCase convention (TypeScript/Connect) and is emitted to .proto
|
||||
// as snake_case by the generator.
|
||||
function parseOneofBlockMultiline(lines, startIndex, startBraceCount) {
|
||||
const firstLine = lines[startIndex].trim();
|
||||
const header = parseOneof(firstLine);
|
||||
const endIndex = findBlockEnd(lines, startIndex + 1, startBraceCount);
|
||||
const innerLines = lines.slice(startIndex + 1, endIndex).map(l => l.trim()).filter(l => l && !l.startsWith('//') && !l.startsWith('/*'));
|
||||
const variants = [];
|
||||
for (const line of innerLines) {
|
||||
// Strip trailing comma or semicolon (proto-style "create_group: CreateGroup," is valid).
|
||||
const trimmed = line.replace(/[,;]\s*$/, '');
|
||||
const m = trimmed.match(/^(\w+)\s*:\s*(\w+)\s*$/);
|
||||
if (m) {
|
||||
variants.push({ fieldName: m[1], typeName: m[2] });
|
||||
}
|
||||
}
|
||||
return { ...header, variants };
|
||||
}
|
||||
function parseServiceBlockMultiline(lines, startIndex, startBraceCount) {
|
||||
// service Name {
|
||||
const firstLine = lines[startIndex].trim();
|
||||
const match = firstLine.match(/^service\s+(\w+)\s*{?/);
|
||||
const name = match ? match[1] : 'UnnamedService';
|
||||
const endIndex = findBlockEnd(lines, startIndex + 1, startBraceCount);
|
||||
const innerLines = lines.slice(startIndex + 1, endIndex).map(l => l.trim()).filter(l => l && !l.startsWith('//') && !l.startsWith('/*'));
|
||||
const rpcs = [];
|
||||
for (const line of innerLines) {
|
||||
// rpc MethodName(RequestType) returns (ResponseType);
|
||||
// Also support streaming: rpc M(stream R) returns (S); or rpc M(R) returns (stream S);
|
||||
const rpcMatch = line.match(/^rpc\s+(\w+)\s*\(\s*(stream\s+)?(\w+)\s*\)\s*returns\s*\(\s*(stream\s+)?(\w+)\s*\)\s*;?$/);
|
||||
if (rpcMatch) {
|
||||
const methodName = rpcMatch[1];
|
||||
const clientStream = !!rpcMatch[2];
|
||||
const requestType = rpcMatch[3];
|
||||
const serverStream = !!rpcMatch[4];
|
||||
const responseType = rpcMatch[5];
|
||||
rpcs.push({
|
||||
name: methodName,
|
||||
requestType,
|
||||
responseType,
|
||||
clientStreaming: clientStream,
|
||||
serverStreaming: serverStream,
|
||||
});
|
||||
}
|
||||
}
|
||||
return { type: 'service', name, rpcs };
|
||||
}
|
||||
// --- Multi-line constraint/verify parsing (no braces needed) ---
|
||||
/**
|
||||
|
|
@ -873,11 +1044,128 @@ function parseMultiLineConstraintVerify(lines, startIndex) {
|
|||
if (line.startsWith('verify ')) {
|
||||
return parseVerifyAnyForm(lines, startIndex);
|
||||
}
|
||||
// Multi-line `verify:` form: verify: always(implies(\n ...\n))
|
||||
// The body opens parens that span multiple lines; collect continuation
|
||||
// lines until parens balance to zero, then return the joined string as
|
||||
// the temporalExpr. speckl#54.
|
||||
if (line.startsWith('verify:')) {
|
||||
return parseVerifyColonBlock(lines, startIndex);
|
||||
}
|
||||
if (line.startsWith('constraint ')) {
|
||||
return parseConstraintAnyForm(lines, startIndex);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Parse the `verify: <expr>` form (speckl#54) where the body can span
|
||||
* multiple lines:
|
||||
*
|
||||
* verify: always(implies(
|
||||
* cond1,
|
||||
* cond2
|
||||
* ))
|
||||
*
|
||||
* The whole expression (the part after `verify:`) is collected by
|
||||
* appending subsequent non-empty, non-keyword-starting lines until
|
||||
* parens/brackets/braces balance to zero. The joined string is stored
|
||||
* in `temporalExpr` so the downstream LTL translator (typescript-state-machine
|
||||
* verifyN()) sees a well-formed formula.
|
||||
*
|
||||
* The `name` is derived from the LTL operator's argument when it matches
|
||||
* `always(Name)` / `eventually(Name)`. When the body is a richer expression
|
||||
* (e.g. `always(implies(...))`) we fall back to `unnamed` — the generator
|
||||
* still emits a working verifyN() that uses the full expression.
|
||||
*/
|
||||
function parseVerifyColonBlock(lines, startIndex) {
|
||||
const firstLine = lines[startIndex].trim();
|
||||
// Strip the `verify:` prefix.
|
||||
const head = firstLine.substring(firstLine.indexOf(':') + 1).trim();
|
||||
if (!head)
|
||||
return null;
|
||||
// If the head is already balanced on its own (single-line verify: expr),
|
||||
// just return it directly — no continuation needed.
|
||||
if (isExpressionComplete(head)) {
|
||||
const nameMatch = head.match(/^(?:always|Always|eventually|Eventually)\s*\(\s*(\w+)\s*\)$/);
|
||||
return {
|
||||
type: 'verify',
|
||||
name: nameMatch ? nameMatch[1] : 'unnamed',
|
||||
temporalExpr: head,
|
||||
};
|
||||
}
|
||||
// Multi-line: collect continuation lines until parens balance. The same
|
||||
// break-condition list used in the parseSpeck skip-loop applies (don't
|
||||
// swallow the next member's keyword). We additionally stop at any
|
||||
// standalone `}` so a verify inside a brace-block still terminates.
|
||||
const parts = [head];
|
||||
let parens = 0, brackets = 0, braces = 0;
|
||||
for (const ch of head) {
|
||||
if (ch === '(')
|
||||
parens++;
|
||||
else if (ch === ')')
|
||||
parens--;
|
||||
else if (ch === '[')
|
||||
brackets++;
|
||||
else if (ch === ']')
|
||||
brackets--;
|
||||
else if (ch === '{')
|
||||
braces++;
|
||||
else if (ch === '}')
|
||||
braces--;
|
||||
}
|
||||
let lastConsumed = startIndex;
|
||||
for (let j = startIndex + 1; j < lines.length; j++) {
|
||||
const raw = lines[j];
|
||||
const nl = raw.trim();
|
||||
if (!nl) {
|
||||
// Empty line still updates counters (none) and advances lastConsumed
|
||||
lastConsumed = j;
|
||||
continue;
|
||||
}
|
||||
if (nl.startsWith('//') || nl.startsWith('/*')) {
|
||||
// Skip standalone comments but treat them as part of the block
|
||||
// (the LTL translator doesn't care about comments in temporalExpr).
|
||||
lastConsumed = j;
|
||||
continue;
|
||||
}
|
||||
// Stop at a new top-level member keyword — that's the next member.
|
||||
if (nl.startsWith('constraint ') || nl.startsWith('verify ') ||
|
||||
nl.startsWith('constraint:') || nl.startsWith('verify:') ||
|
||||
nl.startsWith('state') || nl.startsWith('init') ||
|
||||
nl.startsWith('action ') || nl.startsWith('event ') ||
|
||||
nl.startsWith('interface ') || nl.startsWith('provenance ') ||
|
||||
nl.startsWith('bom ') || nl === '}' ||
|
||||
nl.startsWith('next:') || nl.startsWith('invariant ')) {
|
||||
break;
|
||||
}
|
||||
// Update depth counters.
|
||||
for (const ch of raw) {
|
||||
if (ch === '(')
|
||||
parens++;
|
||||
else if (ch === ')')
|
||||
parens--;
|
||||
else if (ch === '[')
|
||||
brackets++;
|
||||
else if (ch === ']')
|
||||
brackets--;
|
||||
else if (ch === '{')
|
||||
braces++;
|
||||
else if (ch === '}')
|
||||
braces--;
|
||||
}
|
||||
parts.push(nl);
|
||||
lastConsumed = j;
|
||||
if (parens === 0 && brackets === 0 && braces === 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
const joined = parts.join(' ').replace(/\s+/g, ' ').trim();
|
||||
const nameMatch = joined.match(/^(?:always|Always|eventually|Eventually)\s*\(\s*(\w+)\s*\)$/);
|
||||
return {
|
||||
type: 'verify',
|
||||
name: nameMatch ? nameMatch[1] : 'unnamed',
|
||||
temporalExpr: joined,
|
||||
};
|
||||
}
|
||||
function parseConstraintAnyForm(lines, startIndex) {
|
||||
const line = lines[startIndex].trim();
|
||||
const namedMatch = line.match(/^constraint\s+(\w+):(.*)$/);
|
||||
|
|
|
|||
2
compiler/dist/parser.js.map
vendored
2
compiler/dist/parser.js.map
vendored
File diff suppressed because one or more lines are too long
|
|
@ -163,7 +163,9 @@ function emitSpeck(speck: SpeckNode, packageName?: string): string {
|
|||
const events = members.filter(m => m.type === 'event') as EventNode[];
|
||||
const interfaces = classifyInterfaces(members);
|
||||
|
||||
const pkg = packageName || `speckl.${snakeCase(speck.name)}.v1`;
|
||||
const pkg = (speck as any).protoPackage || packageName || `speckl.${snakeCase(speck.name)}.v1`;
|
||||
const goPkg = (speck as any).goPackage
|
||||
|| `github.com/sscoble/${snakeCase(speck.name)}/proto/${snakeCase(speck.name)}/v1;${snakeCase(speck.name)}v1`;
|
||||
|
||||
const lines: string[] = [];
|
||||
|
||||
|
|
@ -176,7 +178,7 @@ function emitSpeck(speck: SpeckNode, packageName?: string): string {
|
|||
lines.push('');
|
||||
lines.push('package ' + pkg + ';');
|
||||
lines.push('');
|
||||
lines.push('option go_package = "github.com/sscoble/' + snakeCase(speck.name) + '/proto/' + snakeCase(speck.name) + '/v1;' + snakeCase(speck.name) + 'v1";');
|
||||
lines.push('option go_package = "' + goPkg + '";');
|
||||
lines.push('');
|
||||
// Import google.protobuf.Timestamp if any field uses Date
|
||||
const usesTimestamp = members.some(m => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue