From 9de0a5ca0f1e07f0777dda8667ba47b352de523b Mon Sep 17 00:00:00 2001 From: Scott Scoble Date: Sat, 9 May 2026 09:12:15 -0700 Subject: [PATCH] feat(compiler): parse precondition/postcondition in action blocks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add 'precondition' and 'postcondition' ActionStatement types - Parse precondition: expr and postcondition: expr in action bodies - Support 'or' continuation lines for multi-clause pre/postconditions - TigerBeetleLedger now parses 21 preconditions + 24 postconditions (previously all dropped, resulting in empty action bodies) - All 41 existing tests pass Addresses marcus/engineering#9 (parser gap) Does NOT wire into generators yet — TypeScript/WASM output will be empty for pre/postconditions. Generator wiring is follow-up work. --- compiler/src/parser.ts | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/compiler/src/parser.ts b/compiler/src/parser.ts index 39e5f0e..da82cbb 100644 --- a/compiler/src/parser.ts +++ b/compiler/src/parser.ts @@ -132,6 +132,8 @@ export type ActionStatement = | { type: 'assign'; target: string; expr: string } | { type: 'let'; name: string; expr: string } | { type: 'require'; expr: string } + | { type: 'precondition'; expr: string } + | { type: 'postcondition'; expr: string } | { type: 'emit'; event: string; fields: { name: string; value: string }[] } | { type: 'return'; expr: string }; @@ -728,7 +730,30 @@ function parseActionBlockMultiline(lines: string[], startIndex: number, startBra const bodyLines = lines.slice(startIndex + 1, endIndex).map(l => l.trim()).filter(l => l && !l.startsWith('//') && !l.startsWith('/*')); const statements: ActionStatement[] = []; - for (const stmt of bodyLines) { + for (let i = 0; i < bodyLines.length; i++) { + const stmt = bodyLines[i]; + // 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 ')) { + i++; + expr += ' || ' + bodyLines[i].substring(3).trim(); + } + statements.push({ type: 'precondition', expr }); + continue; + } + // postcondition: expr + if (stmt.startsWith('postcondition:')) { + let expr = stmt.substring(14).trim(); + // support 'or' continuation lines + while (i + 1 < bodyLines.length && bodyLines[i + 1].startsWith('or ')) { + i++; + expr += ' || ' + bodyLines[i].substring(3).trim(); + } + statements.push({ type: 'postcondition', expr }); + continue; + } // require expr if (stmt.startsWith('require ')) { statements.push({ type: 'require', expr: stmt.substring(8).trim() });