parseman 0.28.1 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"attempt.d.ts","sourceRoot":"","sources":["../../src/combinators/attempt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA6B,MAAM,aAAa,CAAA;AAGxE;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAa/D"}
1
+ {"version":3,"file":"attempt.d.ts","sourceRoot":"","sources":["../../src/combinators/attempt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA6B,MAAM,aAAa,CAAA;AAKxE;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CA2B/D"}
@@ -4,6 +4,17 @@ type UnionArms<T extends (Combinator<unknown> | GatedArm<unknown>)[]> = {
4
4
  [K in keyof T]: ArmParser<T[K]>;
5
5
  }[number] extends Combinator<infer U> ? U : never;
6
6
  export declare function choice<T extends [Combinator<unknown> | GatedArm<unknown>, ...(Combinator<unknown> | GatedArm<unknown>)[]]>(...args: T): Combinator<UnionArms<T>>;
7
+ /**
8
+ * Peel wrappers that neither consume input nor skip trivia before their inner
9
+ * sequence -- `node`, `parser`/`grammar`, `transform`, `label` -- down to the core
10
+ * `sequence` and return its FIRST term (the candidate shared prefix), or null when
11
+ * the arm is not a wrapped-or-bare sequence with >=2 terms. Because none of these
12
+ * wrappers advance the position before the sequence's first term, the term is parsed
13
+ * at the arm's entry position in every arm, so the once-recognized prefix can be
14
+ * replayed there. `attempt`/`optional`/`many`/`choice`/etc. are NOT peeled, so such
15
+ * arms are conservatively excluded.
16
+ */
17
+ export declare function leadingTermOfArm(arm: Combinator<unknown>): Combinator<unknown> | null;
7
18
  /** Walk transform wrappers to find an inner literal's string value. */
8
19
  export declare function getCoreLiteralValue(p: Combinator<unknown>): string | null;
9
20
  /** Walk transform wrappers to find an inner regex's source/flags. */
@@ -1 +1 @@
1
- {"version":3,"file":"choice.d.ts","sourceRoot":"","sources":["../../src/combinators/choice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EAC+B,QAAQ,EAClD,MAAM,aAAa,CAAA;AAKpB,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,KAAK,CAAA;AACvH,KAAK,SAAS,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI;KACrE,CAAC,IAAI,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAChC,CAAC,MAAM,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAEjD,wBAAgB,MAAM,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EACxH,GAAG,IAAI,EAAE,CAAC,GACT,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAwJ1B;AAwFD,uEAAuE;AACvE,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAKzE;AAED,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAMhG"}
1
+ {"version":3,"file":"choice.d.ts","sourceRoot":"","sources":["../../src/combinators/choice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EAC+B,QAAQ,EAClD,MAAM,aAAa,CAAA;AAKpB,KAAK,SAAS,CAAC,CAAC,IAAI,CAAC,SAAS,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,KAAK,CAAA;AACvH,KAAK,SAAS,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,IAAI;KACrE,CAAC,IAAI,MAAM,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAChC,CAAC,MAAM,CAAC,SAAS,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;AAEjD,wBAAgB,MAAM,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,EACxH,GAAG,IAAI,EAAE,CAAC,GACT,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CA2J1B;AA4FD;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,GAAG,IAAI,CAWrF;AA6CD,uEAAuE;AACvE,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,IAAI,CAKzE;AAED,qEAAqE;AACrE,wBAAgB,eAAe,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAMhG"}
@@ -1 +1 @@
1
- {"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../../src/combinators/expect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAyC,UAAU,EAAE,MAAM,aAAa,CAAA;AAGhG,YAAY,EAAE,UAAU,EAAE,CAAA;AAE1B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,MAAM,EAAE,CA8B/D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,GAAG,UAAU,CAAC,CA2B/F;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE"}
1
+ {"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../../src/combinators/expect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAyC,UAAU,EAAE,MAAM,aAAa,CAAA;AAGhG,YAAY,EAAE,UAAU,EAAE,CAAA;AAE1B;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,MAAM,EAAE,CAsC/D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,UAAU,CAAC,CAAC,GAAG,UAAU,CAAC,CA2B/F;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE"}
@@ -2,6 +2,13 @@ import type { FirstSet, Combinator } from '../types.ts';
2
2
  export declare function union(a: FirstSet, b: FirstSet): FirstSet;
3
3
  export declare function intersects(a: FirstSet, b: FirstSet): boolean;
4
4
  export declare function fromChar(code: number): FirstSet;
5
+ /**
6
+ * True when `combinator`'s first set admits the code point at `input[pos]` (or its
7
+ * first set is `any`). The runtime counterpart of codegen's `firstSetCond` guard —
8
+ * used by the interpreter's first-set fail-fast in `optional`/`many`/`attempt`/
9
+ * `node` to reject a doomed sub-parse before doing any setup. Returns `false` at EOF.
10
+ */
11
+ export declare function startsFirstSet(combinator: Combinator<unknown>, input: string, pos: number): boolean;
5
12
  export declare function fromRange(lo: number, hi: number): FirstSet;
6
13
  export declare function any(): FirstSet;
7
14
  export declare function empty(): FirstSet;
@@ -1 +1 @@
1
- {"version":3,"file":"first-set.d.ts","sourceRoot":"","sources":["../../src/combinators/first-set.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,QAAQ,EAAE,UAAU,EAAa,MAAM,aAAa,CAAA;AAE7E,wBAAgB,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAKxD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAS5D;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAE/C;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAE1D;AAED,wBAAgB,GAAG,IAAI,QAAQ,CAE9B;AAED,wBAAgB,KAAK,IAAI,QAAQ,CAEhC;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAqCxG;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,QAAQ,CAOlF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,QAAQ,CAsCvG"}
1
+ {"version":3,"file":"first-set.d.ts","sourceRoot":"","sources":["../../src/combinators/first-set.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,QAAQ,EAAE,UAAU,EAAa,MAAM,aAAa,CAAA;AAE7E,wBAAgB,KAAK,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAKxD;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAS5D;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,CAE/C;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAQnG;AAED,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,QAAQ,CAE1D;AAED,wBAAgB,GAAG,IAAI,QAAQ,CAE9B;AAED,wBAAgB,KAAK,IAAI,QAAQ,CAEhC;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAqCxG;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,QAAQ,CAOlF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,QAAQ,CAsCvG"}
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/combinators/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAoD,MAAM,aAAa,CAAA;AAMzG;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CACzB,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,EAChC,MAAM,EAAE,QAAQ,GAAG,SAAS,EAC5B,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACpC,WAAW,EAAE,aAAa,CAAC,OAAO,CAAC,EACnC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,KAAK,EAAE,OAAO,KACX,CAAC,CAAA;AAEN;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAqBrH,wBAAgB,IAAI,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA;AACjH,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/combinators/node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAoD,MAAM,aAAa,CAAA;AAQzG;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,CACzB,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,EAChC,MAAM,EAAE,QAAQ,GAAG,SAAS,EAC5B,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACpC,WAAW,EAAE,aAAa,CAAC,OAAO,CAAC,EACnC,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,KAAK,EAAE,OAAO,KACX,CAAC,CAAA;AAEN;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,aAAa,CAAC,EAAE,OAAO,CAAC;IAAC,cAAc,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAqBrH,wBAAgB,IAAI,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA;AACjH,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,UAAU,CAAC,CAAC,CAAC,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"repeat.d.ts","sourceRoot":"","sources":["../../src/combinators/repeat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAyC,MAAM,aAAa,CAAA;AAyDpF,wBAAgB,IAAI,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC,CAgDlE;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC,CA4CvE;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,GAAG,IAAI,CAAC,CAwB3E;AAYD,wBAAgB,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC,CAwFhG"}
1
+ {"version":3,"file":"repeat.d.ts","sourceRoot":"","sources":["../../src/combinators/repeat.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAyC,MAAM,aAAa,CAAA;AAqEpF,wBAAgB,IAAI,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC,CAkDlE;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC,CA8CvE;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,GAAG,IAAI,CAAC,CAwB3E;AAED,wBAAgB,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,EAAE,CAAC,CAwFhG"}
@@ -7,6 +7,21 @@
7
7
  * object allocation per node.
8
8
  */
9
9
  import type { Combinator, FirstSet, ParseResult, ParseContext, ParseError } from '../types.ts';
10
+ /**
11
+ * A rule's LEADING first-set as a fuse-resolvable recipe: the concrete leading
12
+ * chars (literals/regex reached through the nullable prefix) kept SEPARATE from the
13
+ * leading rule-REFERENCE names. `fusedBody()` resolves the ref names against the
14
+ * WINNING rules (a fixpoint) and unions the concrete part, so a composed grammar
15
+ * gets the same first-char dispatch a monolithic compile would — WITHOUT baking a
16
+ * referenced rule's first-set (which a compose override could later widen). Kept
17
+ * conservative: an unknown/opaque construct contributes its shallow `_meta.firstSet`
18
+ * (never an under-approximation, so dispatch never drops a valid parse).
19
+ */
20
+ export type FirstSetRecipe = {
21
+ concrete: FirstSet;
22
+ refs: string[];
23
+ };
24
+ export declare function leadingFirstSetRecipe(p: Combinator<unknown>, seen?: Set<Combinator<unknown>>): FirstSetRecipe;
10
25
  import { type GrammarCoveragePlan } from './grammar-coverage-ids.ts';
11
26
  /**
12
27
  * Runtime prelude helper for the structural-node capture gate. Answers "does the
@@ -24,6 +39,7 @@ export declare function beginLoweringCapture(): void;
24
39
  export declare function endLoweringCapture(): string[];
25
40
  export declare function firstSetCond(codeVar: string, fs: FirstSet): string;
26
41
  export declare function __setForceDisjointIf(on: boolean): void;
42
+ export declare function __setForceNoSharedPrefix(on: boolean): void;
27
43
  export type CompiledParser<T> = {
28
44
  parse(input: string, pos?: number): ParseResult<T>;
29
45
  /** Like parse(), but with a caller-supplied ParseContext (e.g. `_triviaLog` for CST grammars). */
@@ -110,6 +126,14 @@ export type LinkablePieces = {
110
126
  * emitted for rule-ref choice arms — sound under compose override.
111
127
  */
112
128
  firstSets: Map<string, FirstSet>;
129
+ /**
130
+ * Per-rule LEADING first-set recipe (concrete chars + leading ref names).
131
+ * `fusedBody()` fixpoint-resolves the ref names over the WINNING rules so a
132
+ * `sequence(ref, …)`-led arm/node dispatches on the ref's real first char —
133
+ * matching a monolithic compile — instead of degrading to always-try because
134
+ * the ref baked `any`. Optional for back-compat with hand-built pieces.
135
+ */
136
+ firstSetRecipes?: Map<string, FirstSetRecipe>;
113
137
  deps: Map<string, string[]>;
114
138
  needsEmptyTl: boolean;
115
139
  needsHostReads: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/compiler/codegen.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,UAAU,EAAa,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,UAAU,EAA4B,MAAM,aAAa,CAAA;AAKnI,OAAO,EAAoB,KAAK,mBAAmB,EAAE,MAAM,2BAA2B,CAAA;AAsBtF;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,uTAC0R,CAAA;AActT,8EAA8E;AAC9E,wBAAgB,oBAAoB,IAAI,IAAI,CAE3C;AAED,+EAA+E;AAC/E,wBAAgB,kBAAkB,IAAI,MAAM,EAAE,CAI7C;AAkeD,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,GAAG,MAAM,CAQlE;AAcD,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAA0B;AAuvEjF,MAAM,MAAM,cAAc,CAAC,CAAC,IAAI;IAC9B,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;IAClD,kGAAkG;IAClG,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,CAAA;IAChF;;;;;OAKG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,GAAG;QAAE,MAAM,EAAE,UAAU,EAAE,CAAA;KAAE,CAAA;IACvF,iEAAiE;IACjE,MAAM,EAAE,MAAM,CAAA;IACd;;;;;;OAMG;IACH,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,4DAA4D;IAC5D,mBAAmB,CAAC,EAAE,SAAS,OAAO,2BAA2B,EAAE,yBAAyB,EAAE,CAAA;CAC/F,CAAA;AAuPD;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAC7D,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CA+BvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,cAAc,CAAC,CAAC,CAAC,CA2InJ;AAsDD,wBAAgB,cAAc,CAC5B,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAC9D,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9E;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,mBAAmB,CAAC,EAAE,SAAS,OAAO,2BAA2B,EAAE,yBAAyB,EAAE,CAAA;CAAE,GAAG,IAAI,CA6IhJ;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,OAAO,EAAE,MAAM,EAAE,CAAA;IACjB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC5B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC7B;;;;OAIG;IACH,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IAChC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;IAC3B,YAAY,EAAE,OAAO,CAAA;IACrB,cAAc,EAAE,OAAO,CAAA;IACvB,6EAA6E;IAC7E,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B,mFAAmF;IACnF,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;;;OAKG;IACH,KAAK,EAAE,aAAa,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,CAAA;IACrD,QAAQ,EAAE,aAAa,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,CAAA;CACzD,CAAA;AAGD,wBAAgB,eAAe,CAC7B,UAAU,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EACjE,EAAE,EAAE,MAAM,EACV,IAAI,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAAC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,mBAAmB,CAAA;CAAE,GACtH,cAAc,GAAG,IAAI,CAwMvB"}
1
+ {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/compiler/codegen.ts"],"names":[],"mappings":"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"}
@@ -50,6 +50,16 @@ export declare function pick(grammar: LinkablePieces | Record<string, Combinator
50
50
  * compose override order). Shared by `pick()` (runtime) and the macro's build-time
51
51
  * `pick(...)` handling, so à-la-carte selection is identical on both paths. */
52
52
  export declare function pickPieces(pieces: LinkablePieces[], names: string[]): LinkablePieces[];
53
+ /**
54
+ * Build the fused-closure body (shared by the runtime `fuseRules` and the
55
+ * build-time `emitFusedSource`). Returns the closure body (which reads `_env`
56
+ * for any non-inlined callbacks) and the `_env` to bind. In macro mode callbacks
57
+ * are inlined from source, so `_env` is empty and the body is fully static.
58
+ */
59
+ export declare function fusedBody(pieces: LinkablePieces[]): {
60
+ body: string;
61
+ env: Record<string, unknown>;
62
+ };
53
63
  /** Fuse at RUNTIME (via `new Function`) — used by `compose()` when not compiled
54
64
  * by the macro (like `compile()`). The macro path uses `emitFusedSource` instead. */
55
65
  export declare function fuseRules(pieces: LinkablePieces[]): Record<string, FusedRule>;
@@ -1 +1 @@
1
- {"version":3,"file":"linker.d.ts","sourceRoot":"","sources":["../../src/compiler/linker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"linker.d.ts","sourceRoot":"","sources":["../../src/compiler/linker.ts"],"names":[],"mappings":"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"}
package/dist/index.cjs CHANGED
@@ -117,6 +117,15 @@ function intersects(a, b) {
117
117
  function fromChar(code) {
118
118
  return { kind: "ranges", ranges: [{ lo: code, hi: code }] };
119
119
  }
120
+ function startsFirstSet(combinator, input, pos) {
121
+ const fs = combinator._meta.firstSet;
122
+ if (fs.kind === "any") return true;
123
+ if (fs.kind === "empty") return false;
124
+ const code = input.codePointAt(pos);
125
+ if (code === void 0) return false;
126
+ for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
127
+ return false;
128
+ }
120
129
  function fromRange(lo, hi) {
121
130
  return { kind: "ranges", ranges: [{ lo, hi }] };
122
131
  }
@@ -1043,6 +1052,17 @@ function deriveExpected(c) {
1043
1052
  return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
1044
1053
  case "attempt":
1045
1054
  return deriveExpected(def.parser);
1055
+ // Delegating wrappers whose first-token failure is their inner parser's — must
1056
+ // pass through so a start-failure (and the first-set-miss fast-path in attempt/
1057
+ // node, which reads this) names the real expected token, not the wrapper tag.
1058
+ case "field":
1059
+ case "withCtx":
1060
+ case "recover":
1061
+ return deriveExpected(def.parser);
1062
+ case "skip":
1063
+ return deriveExpected(def.main);
1064
+ case "expect":
1065
+ return def.expected;
1046
1066
  case "node":
1047
1067
  case "grammar":
1048
1068
  case "trivia":
@@ -1106,7 +1126,7 @@ function choice(...args) {
1106
1126
  disjoint
1107
1127
  };
1108
1128
  const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
1109
- const autoNot = !disjoint && !hasGates && strategy?.tag === "firstMatch" ? computeAutoNot(parsers) : parsers.map(() => null);
1129
+ const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
1110
1130
  let greedyLitMap = null;
1111
1131
  let sortedParsers = null;
1112
1132
  const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
@@ -1232,8 +1252,47 @@ function detectStrategy(parsers) {
1232
1252
  );
1233
1253
  return { tag: "literalsLongestFirst", sortedIndices };
1234
1254
  }
1255
+ const shared = detectSharedPrefix(parsers);
1256
+ if (shared !== null) return shared;
1235
1257
  return { tag: "firstMatch" };
1236
1258
  }
1259
+ function bareLeadingTermKey(term) {
1260
+ const d = term._def;
1261
+ if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
1262
+ if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
1263
+ return null;
1264
+ }
1265
+ function detectSharedPrefix(parsers) {
1266
+ if (parsers.length < 2) return null;
1267
+ let key = null;
1268
+ let prefix = null;
1269
+ const members = [];
1270
+ for (let i = 0; i < parsers.length; i++) {
1271
+ const term0 = leadingTermOfArm(parsers[i]);
1272
+ if (term0 === null) return null;
1273
+ const k = bareLeadingTermKey(term0);
1274
+ if (k === null) return null;
1275
+ if (key === null) {
1276
+ key = k;
1277
+ prefix = term0;
1278
+ } else if (k !== key) return null;
1279
+ members.push(i);
1280
+ }
1281
+ if (prefix === null || members.length < 2) return null;
1282
+ return { tag: "sharedPrefix", prefix, members };
1283
+ }
1284
+ function leadingTermOfArm(arm) {
1285
+ let d = arm._def;
1286
+ for (; ; ) {
1287
+ if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
1288
+ d = d.parser._def;
1289
+ continue;
1290
+ }
1291
+ break;
1292
+ }
1293
+ if (d.tag !== "sequence" || d.parsers.length < 2) return null;
1294
+ return d.parsers[0];
1295
+ }
1237
1296
  function computeAutoNot(parsers) {
1238
1297
  return parsers.map((p, i) => {
1239
1298
  const litVal = getCoreLiteralValue(p);
@@ -1827,11 +1886,20 @@ function sequence(...parsers) {
1827
1886
 
1828
1887
  // src/combinators/attempt.ts
1829
1888
  function attempt(parser2) {
1889
+ const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
1890
+ let failExpected;
1830
1891
  return {
1831
1892
  _tag: "attempt",
1832
1893
  _meta: parser2._meta,
1833
1894
  _def: { tag: "attempt", parser: parser2 },
1834
1895
  parse(input, pos, ctx) {
1896
+ if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(parser2, input, pos)) {
1897
+ if (failExpected === void 0) {
1898
+ const e = deriveExpected(parser2);
1899
+ failExpected = e.length > 0 ? e : [parser2._tag];
1900
+ }
1901
+ return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
1902
+ }
1835
1903
  const mark = saveCstMark(ctx);
1836
1904
  const log = ctx._triviaLog?.length;
1837
1905
  const result = parser2.parse(input, pos, ctx);
@@ -1844,7 +1912,7 @@ function attempt(parser2) {
1844
1912
  }
1845
1913
 
1846
1914
  // src/combinators/repeat.ts
1847
- function repItem(combinator, input, cur, ctx) {
1915
+ function repItem(combinator, input, cur, ctx, guardable) {
1848
1916
  const mark = saveTriviaMark(ctx);
1849
1917
  let pos = cur;
1850
1918
  if (ctx.trivia) {
@@ -1860,6 +1928,10 @@ function repItem(combinator, input, cur, ctx) {
1860
1928
  rollbackTrivia(ctx, mark);
1861
1929
  return "stop";
1862
1930
  }
1931
+ if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
1932
+ rollbackTrivia(ctx, mark);
1933
+ return "stop";
1934
+ }
1863
1935
  const result = combinator.parse(input, pos, ctx);
1864
1936
  if (!result.ok) {
1865
1937
  rollbackTrivia(ctx, mark);
@@ -1879,6 +1951,7 @@ function many(combinator) {
1879
1951
  };
1880
1952
  const def = { tag: "many", parser: combinator, min: 0 };
1881
1953
  let expected;
1954
+ const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
1882
1955
  return {
1883
1956
  _tag: "many",
1884
1957
  _meta: meta,
@@ -1887,7 +1960,7 @@ function many(combinator) {
1887
1960
  const values = def.valueUnused ? void 0 : [];
1888
1961
  let cur = pos;
1889
1962
  while (cur < input.length) {
1890
- const item = repItem(combinator, input, cur, ctx);
1963
+ const item = repItem(combinator, input, cur, ctx, guardable);
1891
1964
  if (item === "stop") break;
1892
1965
  if ("fail" in item) {
1893
1966
  const sync = ctx._tolerant ? ctx._sync : void 0;
@@ -1915,6 +1988,7 @@ function oneOrMore(combinator) {
1915
1988
  };
1916
1989
  const def = { tag: "oneOrMore", parser: combinator, min: 1 };
1917
1990
  let expected;
1991
+ const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
1918
1992
  return {
1919
1993
  _tag: "oneOrMore",
1920
1994
  _meta: meta,
@@ -1925,7 +1999,7 @@ function oneOrMore(combinator) {
1925
1999
  const values = def.valueUnused ? void 0 : [first.value];
1926
2000
  let cur = first.span.end;
1927
2001
  while (cur < input.length) {
1928
- const item = repItem(combinator, input, cur, ctx);
2002
+ const item = repItem(combinator, input, cur, ctx, guardable);
1929
2003
  if (item === "stop") break;
1930
2004
  if ("fail" in item) {
1931
2005
  const sync = ctx._tolerant ? ctx._sync : void 0;
@@ -1968,15 +2042,6 @@ function optional(combinator) {
1968
2042
  }
1969
2043
  };
1970
2044
  }
1971
- function startsFirstSet(combinator, input, pos) {
1972
- const fs = combinator._meta.firstSet;
1973
- if (fs.kind === "any") return true;
1974
- if (fs.kind === "empty") return false;
1975
- const code = input.codePointAt(pos);
1976
- if (code === void 0) return false;
1977
- for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
1978
- return false;
1979
- }
1980
2045
  function sepBy(combinator, separator) {
1981
2046
  const meta = {
1982
2047
  firstSet: combinator._meta.firstSet,
@@ -2510,11 +2575,20 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
2510
2575
  const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : true);
2511
2576
  const clonesState = build ? buildReadsState(def) : true;
2512
2577
  const capturesFields = parserHasOwnFields(combinator) && (build ? buildReadsFields(def) : true);
2578
+ const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
2579
+ let failExpected;
2513
2580
  return {
2514
2581
  _tag: "node",
2515
2582
  _meta: meta,
2516
2583
  _def: def,
2517
2584
  parse(input, pos, ctx) {
2585
+ if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
2586
+ if (failExpected === void 0) {
2587
+ const e = deriveExpected(combinator);
2588
+ failExpected = e.length > 0 ? e : [combinator._tag];
2589
+ }
2590
+ return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
2591
+ }
2518
2592
  const saved = beginCstNodeCapture(ctx);
2519
2593
  const savedFields = ctx._fields;
2520
2594
  ctx._fields = capturesFields ? [] : void 0;
@@ -4239,6 +4313,61 @@ function tryInlineDestructureTransform(src, valueVars) {
4239
4313
  }
4240
4314
 
4241
4315
  // src/compiler/codegen.ts
4316
+ function leadingFirstSetRecipe(p, seen = /* @__PURE__ */ new Set()) {
4317
+ if (seen.has(p)) return { concrete: empty(), refs: [] };
4318
+ seen.add(p);
4319
+ const d = p._def;
4320
+ const rec = (c) => leadingFirstSetRecipe(c, seen);
4321
+ const merge2 = (a, b) => ({ concrete: union(a.concrete, b.concrete), refs: [...a.refs, ...b.refs] });
4322
+ switch (d.tag) {
4323
+ case "lazy": {
4324
+ const name = p._ruleName;
4325
+ if (name !== void 0) return { concrete: empty(), refs: [name] };
4326
+ try {
4327
+ return rec(d.thunk());
4328
+ } catch {
4329
+ return { concrete: any(), refs: [] };
4330
+ }
4331
+ }
4332
+ case "literal":
4333
+ case "regex":
4334
+ case "keywords":
4335
+ return { concrete: p._meta.firstSet, refs: [] };
4336
+ case "choice": {
4337
+ let out = { concrete: empty(), refs: [] };
4338
+ for (const arm of d.parsers) out = merge2(out, rec(arm));
4339
+ return out;
4340
+ }
4341
+ case "sequence": {
4342
+ let out = { concrete: empty(), refs: [] };
4343
+ for (const term of d.parsers) {
4344
+ out = merge2(out, rec(term));
4345
+ if (!matchesEmpty(term)) return out;
4346
+ }
4347
+ return out;
4348
+ }
4349
+ case "oneOrMore":
4350
+ case "many":
4351
+ case "optional":
4352
+ case "transform":
4353
+ case "label":
4354
+ case "field":
4355
+ case "trivia":
4356
+ case "token":
4357
+ case "leaf":
4358
+ case "node":
4359
+ case "grammar":
4360
+ case "expect":
4361
+ return rec(d.parser);
4362
+ case "sepBy":
4363
+ return rec(d.parser);
4364
+ case "skip":
4365
+ return rec(d.main);
4366
+ // not / scanTo / guard / withCtx / recover / unknown → shallow set (safe).
4367
+ default:
4368
+ return { concrete: p._meta.firstSet, refs: [] };
4369
+ }
4370
+ }
4242
4371
  var HOST_READS_DECL = "const _hostReads = (b, n) => { if (b === undefined) return false; let s; try { s = Function.prototype.toString.call(b) } catch (e) { return true } if (/\\barguments\\b/.test(s)) return true; const m = /^[^(]*\\(([\\s\\S]*?)\\)/.exec(s); if (m && /\\.\\.\\.|=/.test(m[1])) return true; return b.length > n }";
4243
4372
  var _loweringSink = null;
4244
4373
  function v(ctx, prefix = "_v") {
@@ -4472,6 +4601,7 @@ var SWITCH_RANGE_LIMIT = 4;
4472
4601
  var SWITCH_MAX_CASES = 48;
4473
4602
  var SWITCH_MIN_CASES = 3;
4474
4603
  var _forceDisjointIf = false;
4604
+ var _forceNoSharedPrefix = false;
4475
4605
  function planDisjointDispatch(parsers) {
4476
4606
  const cases = [];
4477
4607
  let total = 0;
@@ -5107,7 +5237,7 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos, cov
5107
5237
  stmts.push(...emitElseFail(ctx, failArrBody(ctx, allExpected, pos)));
5108
5238
  return { stmts, valueVar: valV, endVar: endV };
5109
5239
  }
5110
- function emitFirstMatch(def, ctx, pos, coverageBase) {
5240
+ function emitFirstMatch(def, ctx, pos, coverageBase, preStmts, armGuardPrefix) {
5111
5241
  const resValV = v(ctx, "_crv");
5112
5242
  const resEndV = v(ctx, "_cre");
5113
5243
  const resOkV = v(ctx, "_crok");
@@ -5121,6 +5251,7 @@ function emitFirstMatch(def, ctx, pos, coverageBase) {
5121
5251
  ...autoRejectedV === void 0 ? [] : [`${ind0}const ${autoRejectedV} = []`],
5122
5252
  `${ind0}const ${codeV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`
5123
5253
  ];
5254
+ if (preStmts) stmts.push(...preStmts);
5124
5255
  for (let i = 0; i < def.parsers.length; i++) {
5125
5256
  const p = def.parsers[i];
5126
5257
  const gate = def.gates[i];
@@ -5128,11 +5259,12 @@ function emitFirstMatch(def, ctx, pos, coverageBase) {
5128
5259
  const atStart = failsAtStart(p);
5129
5260
  const staticFx = armStaticExpected(ctx, p);
5130
5261
  const deferRuleName = ctx.deferFirstSetRefs ? p._ruleName : void 0;
5131
- const fsGuard = deferRuleName !== void 0 ? `/*@FS:${deferRuleName}:${codeV}@*/true` : needsFirstSetGuard(p) ? firstSetCond(codeV, p._meta.firstSet) : (() => {
5262
+ const baseFsGuard = deferRuleName !== void 0 ? `/*@FS:${deferRuleName}:${codeV}@*/true` : needsFirstSetGuard(p) ? firstSetCond(codeV, p._meta.firstSet) : (() => {
5132
5263
  if (p._meta.firstSet.kind !== "any" || matchesEmpty(p)) return null;
5133
5264
  const deep = firstSetOf(p);
5134
5265
  return deep.kind === "ranges" ? firstSetCond(codeV, deep) : null;
5135
5266
  })();
5267
+ const fsGuard = armGuardPrefix === void 0 ? baseFsGuard : baseFsGuard === null ? armGuardPrefix : `${armGuardPrefix} && (${baseFsGuard})`;
5136
5268
  let gateCond = null;
5137
5269
  if (gate) {
5138
5270
  const gateIdx = ctx.mapFns.length;
@@ -5201,11 +5333,64 @@ function emitFirstMatch(def, ctx, pos, coverageBase) {
5201
5333
  stmts.push(...emitIfFail(ctx, `!${resOkV}`, failArrBody(ctx, concatExpr, pos, false)));
5202
5334
  return { stmts, valueVar: resValV, endVar: resEndV };
5203
5335
  }
5336
+ function emitsAsNamedFn(p, ctx) {
5337
+ if (p._def.tag === "lazy") return true;
5338
+ if (ctx.ruleNames?.has(p)) return true;
5339
+ if (ctx.namedParsers.has(p)) return true;
5340
+ const usage = ctx.lazyUsage;
5341
+ return !!usage && !ctx.noHoist && !ctx.capAsTrivia && isHoistableTag(p._def.tag) && (usage.counts.get(p) ?? 0) > 1 && (usage.sizes.get(p) ?? 0) >= HOIST_MIN_SUBTREE;
5342
+ }
5343
+ function armReplayInScope(arm, ctx) {
5344
+ let p = arm;
5345
+ for (; ; ) {
5346
+ if (emitsAsNamedFn(p, ctx)) return false;
5347
+ const d = p._def;
5348
+ if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
5349
+ p = d.parser;
5350
+ continue;
5351
+ }
5352
+ return d.tag === "sequence";
5353
+ }
5354
+ }
5355
+ function emitSharedPrefix(def, strategy, ctx, pos) {
5356
+ const { prefix, members } = strategy;
5357
+ const savedCapturing = ctx.capturing;
5358
+ ctx.capturing = false;
5359
+ const pfx = emitFallible(prefix, ctx, pos, false);
5360
+ ctx.capturing = savedCapturing;
5361
+ const map = ctx.replayPrefix ??= /* @__PURE__ */ new Map();
5362
+ const keys = [];
5363
+ for (const i of members) {
5364
+ const term0 = leadingTermOfArm(def.parsers[i]);
5365
+ if (term0 === null) continue;
5366
+ map.set(term0, { valVar: pfx.valVar, endVar: pfx.endVar });
5367
+ keys.push(term0);
5368
+ }
5369
+ const r = emitFirstMatch(def, ctx, pos, void 0, pfx.stmts, pfx.okVar);
5370
+ for (const k of keys) map.delete(k);
5371
+ return r;
5372
+ }
5373
+ function emitReplayPrefixLeaf(ctx, pos, replay) {
5374
+ const vv = v(ctx);
5375
+ return {
5376
+ stmts: [
5377
+ `${ind(ctx)}const ${vv} = ${replay.valVar}`,
5378
+ ...emitLeafCapture(ctx, vv, pos, replay.endVar)
5379
+ ],
5380
+ valueVar: vv,
5381
+ endVar: replay.endVar
5382
+ };
5383
+ }
5204
5384
  function emitNonDisjoint(def, strategy, allExpected, ctx, pos, coverageBase) {
5205
5385
  if (strategy.tag === "greedyClassify")
5206
5386
  return emitGreedyClassify(def, strategy.superIndex, ctx, pos, coverageBase);
5207
5387
  if (strategy.tag === "literalsLongestFirst")
5208
5388
  return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos, coverageBase);
5389
+ if (strategy.tag === "sharedPrefix") {
5390
+ if (!_forceNoSharedPrefix && coverageBase === void 0 && !ctx.recovery && strategy.members.every((i) => armReplayInScope(def.parsers[i], ctx)))
5391
+ return emitSharedPrefix(def, strategy, ctx, pos);
5392
+ return emitFirstMatch(def, ctx, pos, coverageBase);
5393
+ }
5209
5394
  return emitFirstMatch(def, ctx, pos, coverageBase);
5210
5395
  }
5211
5396
  function pushMapFn(ctx, fn, src) {
@@ -5285,6 +5470,13 @@ function emitMany(def, ctx, pos) {
5285
5470
  itemPos = npV;
5286
5471
  }
5287
5472
  }
5473
+ if (!ctx.recovery && !ctx.coverage && !failsAtStart(def.parser) && needsFirstSetGuard(def.parser)) {
5474
+ const lcV = v(ctx, "_lc");
5475
+ stmts.push(
5476
+ `${ind(ctx)}const ${lcV} = ${itemPos} < input.length ? (input.codePointAt(${itemPos}) ?? -1) : -1`,
5477
+ `${ind(ctx)}if (!(${firstSetCond(lcV, def.parser._meta.firstSet)})) { ${rollback}break }`
5478
+ );
5479
+ }
5288
5480
  const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos, true);
5289
5481
  stmts.push(...iterStmts);
5290
5482
  if (ctx.recovery) {
@@ -5335,8 +5527,19 @@ function emitAttempt(p, def, ctx, pos) {
5335
5527
  const rollback = `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${leaves}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${raw}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${trivia2}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${log}; if (_ctx._fields) _ctx._fields.length = ${fields}; if (_ctx._errors) _ctx._errors.length = ${errors}`;
5336
5528
  const traceId = ctx.coverage?.plan.attempts.get(p);
5337
5529
  const traceRollback = traceId === void 0 ? "" : ` _ctx._grammarTrace?.write({ id: ${JSON.stringify(traceId)}, phase: 'rollback', offset: ${pos} });`;
5530
+ const preGuard = [];
5531
+ if (!ctx.recovery && !ctx.coverage && needsFirstSetGuard(def.parser)) {
5532
+ const gcV = v(ctx, "_agc");
5533
+ const gExp = armStaticExpected(ctx, def.parser);
5534
+ const gFail = ctx.failLabel ? `{ _ctx._fe = ${pos};${ctx.recordFail ? ` _ctx._fx = ${gExp};` : ""} break ${ctx.failLabel} }` : `{ _ctx._fe = ${pos}; ${failReturnArr(gExp, pos)} }`;
5535
+ preGuard.push(
5536
+ `${ind(ctx)}const ${gcV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
5537
+ `${ind(ctx)}if (!(${firstSetCond(gcV, def.parser._meta.firstSet)})) ${gFail}`
5538
+ );
5539
+ }
5338
5540
  return {
5339
5541
  stmts: [
5542
+ ...preGuard,
5340
5543
  `${ind(ctx)}const ${leaves} = _ctx._cstLeaves?.length ?? 0, ${raw} = _ctx._cstRawChildren?.length ?? 0, ${trivia2} = _ctx._cstTriviaLog?.length ?? 0, ${log} = _ctx._triviaLog?.length ?? 0, ${fields} = _ctx._fields?.length ?? 0, ${errors} = _ctx._errors?.length ?? 0`,
5341
5544
  ...inner.stmts,
5342
5545
  ...emitIfFail(ctx, `!${inner.okVar}`, `{ ${rollback};${traceRollback} _ctx._fe = ${pos}; ${propagateFailBody(ctx)} }`)
@@ -5716,7 +5919,18 @@ ${i}const ${chV} = ${profileRecognizer} ? undefined : [], ${rawV} = ${profileRec
5716
5919
  const saveTrivia = needsTriviaFrame ? `, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${smk ? `, ${smk} = _ctx._triviaCaptureMask` : ""}` : "";
5717
5920
  const installTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${capTLv ?? "false"}; _ctx._cstTriviaLog = ${innerTl}${smk ? `; _ctx._triviaCaptureMask = ${capTLv} && _ctx.build !== undefined && _ctx.build._parsemanTriviaKinds !== undefined ? _ctx.build._parsemanTriviaKinds(${JSON.stringify(def.type)}) : ${smk}` : ""}` : "";
5718
5921
  const restoreTrivia = needsTriviaFrame ? `; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${smk ? `; _ctx._triviaCaptureMask = ${smk}` : ""}` : "";
5922
+ const preGuard = [];
5923
+ if (!ctx.recovery && !ctx.coverage && (capturesChildren || structural) && needsFirstSetGuard(def.parser)) {
5924
+ const gcV = v(ctx, "_ngc");
5925
+ const gExp = armStaticExpected(ctx, def.parser);
5926
+ const gFail = ctx.failLabel ? ctx.recordFail ? `{ _ctx._fe = ${pos}; _ctx._fx = ${gExp}; break ${ctx.failLabel} }` : `break ${ctx.failLabel}` : failReturnArr(gExp, pos);
5927
+ preGuard.push(
5928
+ `${i}const ${gcV} = ${pos} < input.length ? (input.codePointAt(${pos}) ?? -1) : -1`,
5929
+ `${i}if (!(${firstSetCond(gcV, def.parser._meta.firstSet)})) ${gFail}`
5930
+ );
5931
+ }
5719
5932
  const stmts = [
5933
+ ...preGuard,
5720
5934
  profHoist,
5721
5935
  allocStmt,
5722
5936
  `${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren${saveTrivia}${sf ? `, ${sf} = _ctx._fields` : ""}`,
@@ -5890,6 +6104,8 @@ function emitExpect(def, ctx, pos) {
5890
6104
  return { stmts, valueVar: valVar, endVar };
5891
6105
  }
5892
6106
  function emit(p, ctx, pos) {
6107
+ const replay = ctx.replayPrefix?.get(p);
6108
+ if (replay !== void 0) return emitReplayPrefixLeaf(ctx, pos, replay);
5893
6109
  const dispatch = (emissionPos = pos) => {
5894
6110
  const savedRule = ctx.activeCoverageRuleId;
5895
6111
  const rule = ctx.coverage?.plan.rules.get(p);
@@ -6633,6 +6849,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
6633
6849
  ].join("\n")));
6634
6850
  }
6635
6851
  const firstSets = /* @__PURE__ */ new Map();
6852
+ const firstSetRecipes = /* @__PURE__ */ new Map();
6636
6853
  for (const [key, rule] of ruleMap) {
6637
6854
  let resolved = rule;
6638
6855
  const d = rule._def;
@@ -6644,6 +6861,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
6644
6861
  }
6645
6862
  }
6646
6863
  firstSets.set(key, canMatchEmptyAtStart(resolved) ? { kind: "any" } : resolved._meta.firstSet);
6864
+ firstSetRecipes.set(key, canMatchEmptyAtStart(resolved) ? { concrete: any(), refs: [] } : leadingFirstSetRecipe(resolved));
6647
6865
  }
6648
6866
  return {
6649
6867
  ns,
@@ -6652,6 +6870,7 @@ function compileLinkable(ruleMapArg, ns, opts) {
6652
6870
  ruleFns,
6653
6871
  wrappers,
6654
6872
  firstSets,
6873
+ firstSetRecipes,
6655
6874
  deps: ruleDependencies(ruleMap),
6656
6875
  needsEmptyTl: !!ctx.needsEmptyTl,
6657
6876
  needsHostReads: !!ctx.needsHostReads,
@@ -7287,10 +7506,30 @@ function fusedBody(pieces) {
7287
7506
  ];
7288
7507
  const wrapperEntries = [...winner].map(([k, p]) => `${JSON.stringify(k)}: ${p.wrappers.get(k)}`);
7289
7508
  const rawBody = [...lines, "return {", wrapperEntries.join(",\n"), "}"].join("\n");
7290
- const finalFS = /* @__PURE__ */ new Map();
7509
+ const ANY2 = { kind: "any" };
7510
+ const recipes = /* @__PURE__ */ new Map();
7511
+ const shallow = /* @__PURE__ */ new Map();
7291
7512
  for (const [k, p] of winner) {
7513
+ const r = p.firstSetRecipes?.get(k);
7514
+ if (r) recipes.set(k, r);
7292
7515
  const fs = p.firstSets?.get(k);
7293
- if (fs) finalFS.set(k, fs);
7516
+ if (fs) shallow.set(k, fs);
7517
+ }
7518
+ const finalFS = /* @__PURE__ */ new Map();
7519
+ for (const [k] of winner) finalFS.set(k, recipes.get(k)?.concrete ?? shallow.get(k) ?? ANY2);
7520
+ for (let iter = 0; iter <= recipes.size; iter++) {
7521
+ let changed = false;
7522
+ for (const [k, r] of recipes) {
7523
+ let fs = r.concrete;
7524
+ for (const ref2 of r.refs) {
7525
+ fs = union(fs, recipes.has(ref2) || shallow.has(ref2) ? finalFS.get(ref2) ?? ANY2 : ANY2);
7526
+ }
7527
+ if (JSON.stringify(finalFS.get(k)) !== JSON.stringify(fs)) {
7528
+ finalFS.set(k, fs);
7529
+ changed = true;
7530
+ }
7531
+ }
7532
+ if (!changed) break;
7294
7533
  }
7295
7534
  const body = rawBody.replace(
7296
7535
  // Rule name + code-point var are both JS identifiers (rule names are validated