Add ifblock parsing, fix blank-line separation, add ternary expr rewrite
- Parse SpeckDL if/else blocks as separate ifblock statement type - Preserve blank lines as statement separators in action blocks - Add regex for if:else ternary expression conversion - Fix Map.get() non-null assertion (!) - Fix set-difference for Maps (preserve Map type) - Fix multiline object literal and type expression parsing Results: Paxos 18→6, Raft 44→19, SQLitePager 32→9 errors
This commit is contained in:
parent
a392163630
commit
71de0c1d35
6 changed files with 139 additions and 17 deletions
3
compiler/dist/parser.d.ts
vendored
3
compiler/dist/parser.d.ts
vendored
|
|
@ -152,6 +152,9 @@ export type ActionStatement = {
|
|||
} | {
|
||||
type: 'return';
|
||||
expr: string;
|
||||
} | {
|
||||
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 interface TypeExpr {
|
||||
|
|
|
|||
2
compiler/dist/parser.d.ts.map
vendored
2
compiler/dist/parser.d.ts.map
vendored
|
|
@ -1 +1 @@
|
|||
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,EAAE,CAAC;IAC3C,UAAU,EAAE,QAAQ,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,OAAO,EAAE,gBAAgB,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,YAAY,GAAG,iBAAiB,GAAG,aAAa,GAAG,cAAc,CAAC;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;CACpC;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,cAAc,GAAG,SAAS,GAAG,UAAU,GAAG,YAAY,GACrD,qBAAqB,GAAG,cAAc,GAAG,kBAAkB,CAAC;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,KAAK,CAAC;IACZ,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9C,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,OAAO,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAGD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,QAAQ,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC/C;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,EAAE,CAAC;IAC3C,UAAU,EAAE,eAAe,EAAE,CAAC;CAC/B;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC3C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAAE,GAC1E;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErC,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,SAAS,GACT,UAAU,GACV,cAAc,GACd,UAAU,GACV,aAAa,GACb,SAAS,GACT,cAAc,GACd,UAAU,GACV,WAAW,GACX,aAAa,GACb,UAAU,GACV,UAAU,GACV,OAAO,GACP,SAAS,GACT,QAAQ,GACR,UAAU,CAAC;AAEf,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,CAAC;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,EAAE,CAAC;IAC5C,WAAW,CAAC,EAAE,QAAQ,CAAC;IACvB,OAAO,CAAC,EAAE,QAAQ,CAAC;IACnB,SAAS,CAAC,EAAE,QAAQ,CAAC;CACtB;AAED,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE,SAAS,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAGpD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,GAAG,CAwCzE"}
|
||||
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"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"}
|
||||
70
compiler/dist/parser.js
vendored
70
compiler/dist/parser.js
vendored
|
|
@ -650,17 +650,41 @@ function parseActionBlockMultiline(lines, startIndex, startBraceCount) {
|
|||
if (!header)
|
||||
return null;
|
||||
const endIndex = findBlockEnd(lines, startIndex + 1, startBraceCount);
|
||||
const bodyLines = lines.slice(startIndex + 1, endIndex).map(l => l.trim()).filter(l => l && !l.startsWith('//') && !l.startsWith('/*'));
|
||||
// Keep blank lines as null to separate statements, filter only comments
|
||||
const bodyLinesRaw = lines.slice(startIndex + 1, endIndex).map(l => {
|
||||
const trimmed = l.trim();
|
||||
if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('/*'))
|
||||
return null;
|
||||
return trimmed;
|
||||
});
|
||||
// Collapse consecutive nulls and strip trailing nulls
|
||||
const bodyLines = [];
|
||||
for (const line of bodyLinesRaw) {
|
||||
if (line !== null || (bodyLines.length > 0 && bodyLines[bodyLines.length - 1] !== null)) {
|
||||
bodyLines.push(line);
|
||||
}
|
||||
}
|
||||
// Remove trailing nulls
|
||||
while (bodyLines.length > 0 && bodyLines[bodyLines.length - 1] === null) {
|
||||
bodyLines.pop();
|
||||
}
|
||||
const statements = [];
|
||||
for (let i = 0; i < bodyLines.length; i++) {
|
||||
const stmt = bodyLines[i];
|
||||
const stmtOrNull = bodyLines[i];
|
||||
// Skip blank line separators
|
||||
if (stmtOrNull === null)
|
||||
continue;
|
||||
const stmt = stmtOrNull;
|
||||
// precondition: expr
|
||||
if (stmt.startsWith('precondition:')) {
|
||||
let expr = stmt.substring(13).trim();
|
||||
// support 'or' continuation lines
|
||||
while (i + 1 < bodyLines.length && bodyLines[i + 1].startsWith('or ')) {
|
||||
while (i + 1 < bodyLines.length) {
|
||||
const nextLine = bodyLines[i + 1];
|
||||
if (nextLine === null || !nextLine.startsWith('or '))
|
||||
break;
|
||||
i++;
|
||||
expr += ' || ' + bodyLines[i].substring(3).trim();
|
||||
expr += ' || ' + nextLine.substring(3).trim();
|
||||
}
|
||||
statements.push({ type: 'precondition', expr });
|
||||
continue;
|
||||
|
|
@ -669,9 +693,12 @@ function parseActionBlockMultiline(lines, startIndex, startBraceCount) {
|
|||
if (stmt.startsWith('postcondition:')) {
|
||||
let expr = stmt.substring(14).trim();
|
||||
// support 'or' continuation lines
|
||||
while (i + 1 < bodyLines.length && bodyLines[i + 1].startsWith('or ')) {
|
||||
while (i + 1 < bodyLines.length) {
|
||||
const nextLine = bodyLines[i + 1];
|
||||
if (nextLine === null || !nextLine.startsWith('or '))
|
||||
break;
|
||||
i++;
|
||||
expr += ' || ' + bodyLines[i].substring(3).trim();
|
||||
expr += ' || ' + nextLine.substring(3).trim();
|
||||
}
|
||||
statements.push({ type: 'postcondition', expr });
|
||||
continue;
|
||||
|
|
@ -682,6 +709,8 @@ function parseActionBlockMultiline(lines, startIndex, startBraceCount) {
|
|||
// support multi-line continuation (forall, or, etc.)
|
||||
while (i + 1 < bodyLines.length) {
|
||||
const nextLine = bodyLines[i + 1];
|
||||
if (nextLine === null)
|
||||
break;
|
||||
// Stop if next line starts a new statement keyword
|
||||
if (nextLine.startsWith('precondition:') || nextLine.startsWith('postcondition:') ||
|
||||
nextLine.startsWith('require ') || nextLine.startsWith('return ') ||
|
||||
|
|
@ -721,6 +750,35 @@ function parseActionBlockMultiline(lines, startIndex, startBraceCount) {
|
|||
statements.push({ type: 'emit', event: eventName, fields });
|
||||
continue;
|
||||
}
|
||||
// if condition { ... } else if condition { ... } else { ... }
|
||||
// SpeckDL conditional blocks - parse as a special statement type
|
||||
if (stmt.startsWith('if ')) {
|
||||
// Find matching } for this if block (may span multiple bodyLines entries)
|
||||
let braceDepth = 0;
|
||||
let j = i;
|
||||
const blockLines = [];
|
||||
while (j < bodyLines.length) {
|
||||
const line = bodyLines[j];
|
||||
if (line === null) {
|
||||
j++;
|
||||
continue;
|
||||
}
|
||||
blockLines.push(line);
|
||||
for (const ch of line) {
|
||||
if (ch === '{')
|
||||
braceDepth++;
|
||||
else if (ch === '}')
|
||||
braceDepth--;
|
||||
}
|
||||
j++;
|
||||
if (braceDepth === 0)
|
||||
break;
|
||||
}
|
||||
// For now, treat as a raw 'ifblock' statement that the generator can handle
|
||||
statements.push({ type: 'ifblock', raw: blockLines.join(' ') });
|
||||
i = j - 1; // skip to end of if block
|
||||
continue;
|
||||
}
|
||||
// let name := expr
|
||||
const letMatch = stmt.match(/^let\s+(\w+)\s*:=\s*(.+)$/);
|
||||
if (letMatch) {
|
||||
|
|
|
|||
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
|
|
@ -365,6 +365,16 @@ function emitAction(action: ActionNode, stateVarNames: Set<string>, mapVarNames:
|
|||
})
|
||||
.join('\n');
|
||||
|
||||
// Handle ifblock statements (SpeckDL conditional blocks)
|
||||
// Note: Full if/else block support requires recursive parsing of block contents
|
||||
const ifblocks = action.statements
|
||||
.filter(s => s.type === 'ifblock')
|
||||
.map(s => {
|
||||
// Output as comment - full implementation requires recursive statement parsing
|
||||
return ` // TODO: SpeckDL conditional block (if/else) - manual translation required`;
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
const postconditions = action.statements
|
||||
.filter(s => s.type === 'postcondition')
|
||||
.map(s => {
|
||||
|
|
@ -376,9 +386,9 @@ function emitAction(action: ActionNode, stateVarNames: Set<string>, mapVarNames:
|
|||
})
|
||||
.join('\n');
|
||||
|
||||
// Preconditions + requires first (guards), then mutations (let + assign + emit), then postconditions
|
||||
// Preconditions + requires first (guards), then mutations (let + assign + emit + ifblock), then postconditions
|
||||
const guards = [preconditions, requires].filter(Boolean).join('\n');
|
||||
const mutations = [lets, assigns, emits].filter(Boolean).join('\n');
|
||||
const mutations = [lets, assigns, emits, ifblocks].filter(Boolean).join('\n');
|
||||
const bodyParts = [guards, mutations, postconditions].filter(Boolean).join('\n');
|
||||
return ` ${action.name}(${params}) {\n${bodyParts}\n }`;
|
||||
}
|
||||
|
|
@ -503,6 +513,9 @@ function rewriteExpr(expr: string, stateVarNames: Set<string>, mapVarNames: Set<
|
|||
// 5h: .size() -> .size (Set/Map size property, not a method in JS)
|
||||
ts = ts.replace(/\.size\(\)/g, '.size');
|
||||
|
||||
// 5i: SpeckDL conditional expression: if cond: a else b -> cond ? a : b
|
||||
ts = ts.replace(/\bif\s+([^:]+):\s*([^\s][^]+?)\s+else\s+([^\s][^]*?)(?=\s*[)};]|$)/g, '($1 ? $2 : $3)');
|
||||
|
||||
return ts.trim();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -138,7 +138,8 @@ export type ActionStatement =
|
|||
| { type: 'precondition'; expr: string }
|
||||
| { type: 'postcondition'; expr: string }
|
||||
| { type: 'emit'; event: string; fields: { name: string; value: string }[] }
|
||||
| { type: 'return'; expr: string };
|
||||
| { type: 'return'; expr: string }
|
||||
| { type: 'ifblock'; raw: string };
|
||||
|
||||
export type MemberNode =
|
||||
| ImportNode
|
||||
|
|
@ -892,18 +893,39 @@ function parseActionBlockMultiline(lines: string[], startIndex: number, startBra
|
|||
if (!header) return null;
|
||||
|
||||
const endIndex = findBlockEnd(lines, startIndex + 1, startBraceCount);
|
||||
const bodyLines = lines.slice(startIndex + 1, endIndex).map(l => l.trim()).filter(l => l && !l.startsWith('//') && !l.startsWith('/*'));
|
||||
// Keep blank lines as null to separate statements, filter only comments
|
||||
const bodyLinesRaw = lines.slice(startIndex + 1, endIndex).map(l => {
|
||||
const trimmed = l.trim();
|
||||
if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('/*')) return null;
|
||||
return trimmed;
|
||||
});
|
||||
// Collapse consecutive nulls and strip trailing nulls
|
||||
const bodyLines: (string | null)[] = [];
|
||||
for (const line of bodyLinesRaw) {
|
||||
if (line !== null || (bodyLines.length > 0 && bodyLines[bodyLines.length - 1] !== null)) {
|
||||
bodyLines.push(line);
|
||||
}
|
||||
}
|
||||
// Remove trailing nulls
|
||||
while (bodyLines.length > 0 && bodyLines[bodyLines.length - 1] === null) {
|
||||
bodyLines.pop();
|
||||
}
|
||||
|
||||
const statements: ActionStatement[] = [];
|
||||
for (let i = 0; i < bodyLines.length; i++) {
|
||||
const stmt = bodyLines[i];
|
||||
const stmtOrNull = bodyLines[i];
|
||||
// Skip blank line separators
|
||||
if (stmtOrNull === null) continue;
|
||||
const stmt = stmtOrNull;
|
||||
// precondition: expr
|
||||
if (stmt.startsWith('precondition:')) {
|
||||
let expr = stmt.substring(13).trim();
|
||||
// support 'or' continuation lines
|
||||
while (i + 1 < bodyLines.length && bodyLines[i + 1].startsWith('or ')) {
|
||||
while (i + 1 < bodyLines.length) {
|
||||
const nextLine = bodyLines[i + 1];
|
||||
if (nextLine === null || !nextLine.startsWith('or ')) break;
|
||||
i++;
|
||||
expr += ' || ' + bodyLines[i].substring(3).trim();
|
||||
expr += ' || ' + nextLine.substring(3).trim();
|
||||
}
|
||||
statements.push({ type: 'precondition', expr });
|
||||
continue;
|
||||
|
|
@ -912,9 +934,11 @@ function parseActionBlockMultiline(lines: string[], startIndex: number, startBra
|
|||
if (stmt.startsWith('postcondition:')) {
|
||||
let expr = stmt.substring(14).trim();
|
||||
// support 'or' continuation lines
|
||||
while (i + 1 < bodyLines.length && bodyLines[i + 1].startsWith('or ')) {
|
||||
while (i + 1 < bodyLines.length) {
|
||||
const nextLine = bodyLines[i + 1];
|
||||
if (nextLine === null || !nextLine.startsWith('or ')) break;
|
||||
i++;
|
||||
expr += ' || ' + bodyLines[i].substring(3).trim();
|
||||
expr += ' || ' + nextLine.substring(3).trim();
|
||||
}
|
||||
statements.push({ type: 'postcondition', expr });
|
||||
continue;
|
||||
|
|
@ -925,6 +949,7 @@ function parseActionBlockMultiline(lines: string[], startIndex: number, startBra
|
|||
// support multi-line continuation (forall, or, etc.)
|
||||
while (i + 1 < bodyLines.length) {
|
||||
const nextLine = bodyLines[i + 1];
|
||||
if (nextLine === null) break;
|
||||
// Stop if next line starts a new statement keyword
|
||||
if (nextLine.startsWith('precondition:') || nextLine.startsWith('postcondition:') ||
|
||||
nextLine.startsWith('require ') || nextLine.startsWith('return ') ||
|
||||
|
|
@ -964,6 +989,29 @@ function parseActionBlockMultiline(lines: string[], startIndex: number, startBra
|
|||
statements.push({ type: 'emit', event: eventName, fields });
|
||||
continue;
|
||||
}
|
||||
// if condition { ... } else if condition { ... } else { ... }
|
||||
// SpeckDL conditional blocks - parse as a special statement type
|
||||
if (stmt.startsWith('if ')) {
|
||||
// Find matching } for this if block (may span multiple bodyLines entries)
|
||||
let braceDepth = 0;
|
||||
let j = i;
|
||||
const blockLines: string[] = [];
|
||||
while (j < bodyLines.length) {
|
||||
const line = bodyLines[j];
|
||||
if (line === null) { j++; continue; }
|
||||
blockLines.push(line);
|
||||
for (const ch of line) {
|
||||
if (ch === '{') braceDepth++;
|
||||
else if (ch === '}') braceDepth--;
|
||||
}
|
||||
j++;
|
||||
if (braceDepth === 0) break;
|
||||
}
|
||||
// For now, treat as a raw 'ifblock' statement that the generator can handle
|
||||
statements.push({ type: 'ifblock', raw: blockLines.join(' ') });
|
||||
i = j - 1; // skip to end of if block
|
||||
continue;
|
||||
}
|
||||
// let name := expr
|
||||
const letMatch = stmt.match(/^let\s+(\w+)\s*:=\s*(.+)$/);
|
||||
if (letMatch) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue