Skip to content

Commit 24280f4

Browse files
SH2-0: shape parity gate, coverage fail-fast, and toy recognizer.
Add target-neutral shape-machine contracts, transplant the SH2a toy fixture, and harden Shape AST codegen with emit-time coverage counters, unsupported fail-fast, multi-alt choice backtracking, and the sep/not/opt/call-LED subset needed so calc+toy stay fully generable under the new gate (48/48). Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 97b0fcb commit 24280f4

6 files changed

Lines changed: 1381 additions & 139 deletions

File tree

src/shape-machine.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* Target-neutral data contracts for generated shape recognizers.
3+
*
4+
* This module deliberately contains no target runtime. TS, Rust, and Go emitters
5+
* can share these identities and transaction rules without sharing codegen.
6+
*/
7+
8+
/** Identity path through RD alternatives, nested inline alternatives, and Pratt events. */
9+
export type AltPathPart =
10+
| { kind: 'rd'; rule: string; alt: number }
11+
| { kind: 'inline-alt'; branch: number }
12+
| { kind: 'pratt-nud'; event: 'atom' | 'group' | 'prefix' | 'nudSeq' | 'nudCapped'; index: number }
13+
| { kind: 'pratt-led'; event: 'binary' | 'postfix' | 'postfixTok' | 'led'; index: number };
14+
export type AltPath = readonly AltPathPart[];
15+
16+
/** A visible value channel. Optional holes retain position instead of disappearing. */
17+
export type VisibleSlot<H = unknown> =
18+
| { kind: 'slot'; value: H }
19+
| { kind: 'list'; values: H[] }
20+
| { kind: 'hole'; value: H | null };
21+
22+
export type PrattEvent<H = unknown> =
23+
| { kind: 'atom'; value: H }
24+
| { kind: 'group'; value: H }
25+
| { kind: 'prefix'; operator: string; argument: H }
26+
| { kind: 'binary'; left: H; operator: string; right: H }
27+
| { kind: 'postfix'; left: H; operator: string }
28+
| { kind: 'postfixTok'; left: H; token: H }
29+
| { kind: 'led'; left: H; slots: readonly VisibleSlot<H>[] }
30+
| { kind: 'nudSeq'; slots: readonly VisibleSlot<H>[] }
31+
| { kind: 'nudCapped'; slots: readonly VisibleSlot<H>[] };
32+
33+
/** Length snapshots are valid only for append-only channels. */
34+
export type AppendOnlyCheckpoint = {
35+
pos: number;
36+
kidsLength: number;
37+
listsLength: number;
38+
holesLength: number;
39+
altPathLength: number;
40+
};
41+
42+
/** Prior value for a slot overwritten during a speculative transaction. */
43+
export type UndoEntry<H = unknown> = {
44+
channel: 'slot' | 'state';
45+
index: number;
46+
previous: H;
47+
};
48+
49+
export type ShapeTransaction<H = unknown> = {
50+
checkpoint: AppendOnlyCheckpoint;
51+
undo: UndoEntry<H>[];
52+
status: 'open' | 'committed' | 'rolledBack';
53+
};
54+
55+
/**
56+
* Transaction contract:
57+
* - append-only arrays roll back by restoring their checkpointed lengths;
58+
* - overwrites must be recorded in `undo`, or staged and applied only on commit;
59+
* - parser position and every mutable Pratt/control flag join the same transaction;
60+
* - function-local `left`/`opText` values need no log when assigned only after success.
61+
*/
62+
export const SHAPE_TRANSACTION_CONTRACT = {
63+
appendOnly: 'restore-lengths',
64+
overwrite: 'undo-log-or-commit-on-success',
65+
prattLocals: 'commit-on-success',
66+
} as const;
67+
68+
/** Local custom context (SH2-0). Full AltPathPart form is deferred. */
69+
export type AstCustomCtx = {
70+
kids: readonly unknown[];
71+
altPath: readonly number[];
72+
src: string;
73+
off: number;
74+
end: number;
75+
};
76+
export type AstCustom = (ctx: AstCustomCtx) => unknown;

src/shape-schema.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,26 @@ export const ADJUDICATIONS = {
105105
altHeterogeneous: 'Choice arms partition every RD alternative exactly once.',
106106
ruleKeying: 'Exact IR rule names override inherited cstName mappings.',
107107
} as const;
108+
109+
/** Emit-time static coverage of Shape AST step/pratt rendering. */
110+
export type ShapeStepKind =
111+
| 'lit' | 'tok' | 'rule' | 'ruleBp' | 'star' | 'opt' | 'sep'
112+
| 'altlit' | 'alt' | 'not' | 'seq' | 'sameLine' | 'suppress';
113+
export type ShapePrattKind =
114+
| 'atom' | 'group' | 'prefix' | 'binary' | 'postfix' | 'postfixTok'
115+
| 'led' | 'nudSeq' | 'nudCapped';
116+
export type ShapeUnsupported = { rule: string; construct: string };
117+
export type ShapeCoverage = {
118+
step: Record<ShapeStepKind, number>;
119+
pratt: Record<ShapePrattKind, number>;
120+
unsupported: ShapeUnsupported[];
121+
};
122+
123+
export const SHAPE_STEP_KINDS: readonly ShapeStepKind[] = [
124+
'lit', 'tok', 'rule', 'ruleBp', 'star', 'opt', 'sep',
125+
'altlit', 'alt', 'not', 'seq', 'sameLine', 'suppress',
126+
] as const;
127+
export const SHAPE_PRATT_KINDS: readonly ShapePrattKind[] = [
128+
'atom', 'group', 'prefix', 'binary', 'postfix', 'postfixTok',
129+
'led', 'nudSeq', 'nudCapped',
130+
] as const;

0 commit comments

Comments
 (0)