parseman 0.16.0 → 0.17.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.
@@ -22,4 +22,18 @@ export declare function matchesEmpty(p: Combinator<unknown>, seen?: Set<Combinat
22
22
  * and silently breaks first-char dispatch — see the InterpolatedSelector bug.)
23
23
  */
24
24
  export declare function sequenceFirstSet(parsers: readonly Combinator<unknown>[]): FirstSet;
25
+ /**
26
+ * Deep first-set that RESOLVES `lazy`/`ref` combinators to their targets. The
27
+ * combinators bake `_meta.firstSet` at CONSTRUCTION, when a `ref()` still reads
28
+ * `any()` (define() never updates it) — so a `choice`/`sequence` built over refs
29
+ * caches a spuriously-`any` first-set and loses first-char dispatch. Recomputing
30
+ * here, following refs, recovers the real set. Over-approximates on cycles /
31
+ * unknown constructs (returns `any`) — always sound: a wider set only means "try
32
+ * this arm for more first chars", never skips a real match.
33
+ *
34
+ * SOUND ONLY where refs are FINAL (monolithic compile). Under compose OVERRIDE a
35
+ * referenced rule can be replaced with a WIDER first-set, so a baked deep set
36
+ * would wrongly skip valid input — the compose path defers dispatch to fuse time.
37
+ */
38
+ export declare function firstSetOf(p: Combinator<unknown>, seen?: Set<Combinator<unknown>>): FirstSet;
25
39
  //# sourceMappingURL=first-set.d.ts.map
@@ -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,CAmCxG;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,GAAG,QAAQ,CAOlF"}
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,CAmCxG;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,CAoCvG"}
@@ -1 +1 @@
1
- {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/compiler/codegen.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"codegen.d.ts","sourceRoot":"","sources":["../../src/compiler/codegen.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Serialize a compiled rule map BACK to a compact combinator-construction source
3
+ * expression — the "IR" a composed grammar carries instead of ~1MB of fully
4
+ * lowered `_r_<Name>` function source. At fuse time the expression is evaluated
5
+ * (with the combinator constructors in scope) to reconstruct the rule map, then
6
+ * re-lowered via `compileLinkable` — identical behaviour, a fraction of the bytes.
7
+ *
8
+ * The output mirrors how a grammar is WRITTEN, not how it lowers:
9
+ * - a rule reference (`g.Foo`, a `lazy` carrying `_ruleName`) → `g["Foo"]`
10
+ * - a sub-combinator shared by identity (referenced ≥2×, e.g. a `balanced` const
11
+ * reused across rules) → a hoisted `const _s<N> = …`, referenced by name, so it
12
+ * stays shared through the round trip (and `compileLinkable` re-hoists it)
13
+ * - a self-referential combinator (`balanced`'s internal `self = ref()`) → a
14
+ * `ref()` + `.define()` closure, the same shape the library combinator emits
15
+ * - `transform`/`node` callbacks → their captured source (`fnSrc`/`buildSrc`)
16
+ *
17
+ * Returns null if the map can't be faithfully serialized (a callback without
18
+ * source, or an unsupported construct) — the caller then keeps the lowered source.
19
+ */
20
+ import type { Combinator } from '../types.ts';
21
+ type Comb = Combinator<unknown>;
22
+ export declare function serializeRuleMap(ruleMap: ReadonlyArray<readonly [string, Comb]>): string | null;
23
+ /** Reconstruct a rule map from serialized IR (the inverse of `serializeRuleMap`) —
24
+ * evaluate the combinator-construction expression with every constructor in scope.
25
+ * Used at fuse time (runtime linker + build-time plugin) to re-lower carried IR. */
26
+ export declare function evalRuleMapIR(ir: string): Array<[string, Comb]>;
27
+ export {};
28
+ //# sourceMappingURL=ir-serialize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ir-serialize.d.ts","sourceRoot":"","sources":["../../src/compiler/ir-serialize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,aAAa,CAAA;AAgBxD,KAAK,IAAI,GAAG,UAAU,CAAC,OAAO,CAAC,CAAA;AA0C/B,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,GAC9C,MAAM,GAAG,IAAI,CAUf;AAED;;oFAEoF;AACpF,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAgC/D"}
@@ -40,5 +40,14 @@ export declare function fuseRules(pieces: LinkablePieces[]): Record<string, Fuse
40
40
  * artifact carries runtime-only callback functions.
41
41
  */
42
42
  export declare function emitFusedSource(pieces: LinkablePieces[]): string;
43
+ /** The compact IR form a grammar carries instead of its lowered rule source: the
44
+ * combinator-construction expression, re-lowered here at fuse time. */
45
+ export type IRPiece = {
46
+ ns: string;
47
+ ir: string;
48
+ };
49
+ /** Materialize a carried item to full `LinkablePieces`: an IR piece is evaluated
50
+ * back to a rule map and re-lowered; a full piece passes through. */
51
+ export declare function materializePiece(p: LinkablePieces | IRPiece): LinkablePieces;
43
52
  export declare function compose(items: Array<LinkablePieces | Record<string, unknown>>): Record<string, FusedRule>;
44
53
  //# sourceMappingURL=linker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"linker.d.ts","sourceRoot":"","sources":["../../src/compiler/linker.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,aAAa,CAAA;AAavD,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAC7C,EAAE,CAAC,EAAE,MAAM,GACV,cAAc,CAIhB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,EAChC,YAAY,EAAE,aAAa,CAAC,OAAO,CAAC,EACpC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACpC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,EAC9B,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAIT;AAED,MAAM,MAAM,SAAS,GAAG,CACtB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACzB;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAA;AAE3E;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAClB,OAAO,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAC7D,KAAK,EAAE,MAAM,EAAE,GACd,cAAc,CA2BhB;AAmED;qFACqF;AACrF,wBAAgB,SAAS,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAI7E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,CAMhE;AA8BD,wBAAgB,OAAO,CACrB,KAAK,EAAE,KAAK,CAAC,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACrD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAK3B"}
1
+ {"version":3,"file":"linker.d.ts","sourceRoot":"","sources":["../../src/compiler/linker.ts"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,KAAK,EAAE,UAAU,EAAY,MAAM,aAAa,CAAA;AAavD,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAC7C,EAAE,CAAC,EAAE,MAAM,GACV,cAAc,CAIhB;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,EAChC,YAAY,EAAE,aAAa,CAAC,OAAO,CAAC,EACpC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EACpC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,EAC9B,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAIT;AAED,MAAM,MAAM,SAAS,GAAG,CACtB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACzB;IAAE,EAAE,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAA;AAE3E;;;;;;;GAOG;AACH,wBAAgB,IAAI,CAClB,OAAO,EAAE,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAC7D,KAAK,EAAE,MAAM,EAAE,GACd,cAAc,CA2BhB;AAmED;qFACqF;AACrF,wBAAgB,SAAS,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAI7E;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,CAMhE;AAqBD;uEACuE;AACvE,MAAM,MAAM,OAAO,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAA;AAQhD;qEACqE;AACrE,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,cAAc,GAAG,OAAO,GAAG,cAAc,CAK5E;AAeD,wBAAgB,OAAO,CACrB,KAAK,EAAE,KAAK,CAAC,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACrD,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAK3B"}
package/dist/index.cjs CHANGED
@@ -181,6 +181,54 @@ function sequenceFirstSet(parsers) {
181
181
  }
182
182
  return fs;
183
183
  }
184
+ function firstSetOf(p, seen = /* @__PURE__ */ new Set()) {
185
+ if (seen.has(p)) return any();
186
+ seen.add(p);
187
+ const fs = (c) => firstSetOf(c, seen);
188
+ const d = p._def;
189
+ switch (d.tag) {
190
+ case "literal":
191
+ case "regex":
192
+ case "keywords":
193
+ return p._meta.firstSet;
194
+ // terminals: no refs, cached set is exact
195
+ case "lazy":
196
+ try {
197
+ return fs(d.thunk());
198
+ } catch {
199
+ return any();
200
+ }
201
+ case "choice": {
202
+ let out = empty();
203
+ for (const arm of d.parsers) out = union(out, fs(arm));
204
+ return out;
205
+ }
206
+ case "sequence": {
207
+ let out = empty();
208
+ for (const term of d.parsers) {
209
+ out = union(out, fs(term));
210
+ if (!matchesEmpty(term)) return out;
211
+ }
212
+ return out;
213
+ }
214
+ case "oneOrMore":
215
+ case "many":
216
+ case "optional":
217
+ case "transform":
218
+ case "label":
219
+ case "trivia":
220
+ case "node":
221
+ case "grammar":
222
+ case "expect":
223
+ return fs(d.parser);
224
+ case "sepBy":
225
+ return fs(d.parser);
226
+ case "skip":
227
+ return fs(d.main);
228
+ default:
229
+ return p._meta.firstSet;
230
+ }
231
+ }
184
232
  function mergeRanges(ranges) {
185
233
  if (ranges.length === 0) return [];
186
234
  const sorted = [...ranges].sort((a, b) => a.lo - b.lo);
@@ -3121,16 +3169,12 @@ function namedFnPrelude() {
3121
3169
  function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
3122
3170
  ctx.namedFnDecls.push([
3123
3171
  `function ${fnName}(input, _pos, _ctx) {`,
3124
- ` let _pfok = false, _pfv, _pfe = _pos`,
3125
3172
  ` _pfail: {`,
3126
3173
  ...reindentStmts(bodyStmts, 2),
3127
- ` _pfv = ${valueVar}`,
3128
- ` _pfe = ${endVar}`,
3129
- ` _pfok = true`,
3174
+ ` ${NAMED_FN_END} = ${endVar}`,
3175
+ ` return ${valueVar}`,
3130
3176
  ` }`,
3131
- ` if (!_pfok) return ${NAMED_FN_FAIL}`,
3132
- ` ${NAMED_FN_END} = _pfe`,
3133
- ` return _pfv`,
3177
+ ` return ${NAMED_FN_FAIL}`,
3134
3178
  `}`
3135
3179
  ].join("\n"));
3136
3180
  }
@@ -3831,11 +3875,16 @@ function emitFirstMatch(def, ctx, pos) {
3831
3875
  const atStart = failsAtStart(p);
3832
3876
  const staticFx = armStaticExpected(ctx, p);
3833
3877
  const deferRuleName = ctx.deferFirstSetRefs ? p._ruleName : void 0;
3834
- const fsGuard = deferRuleName !== void 0 ? `/*@FS:${deferRuleName}:${codeV}@*/true` : needsFirstSetGuard(p) ? firstSetCond(codeV, p._meta.firstSet) : null;
3878
+ const fsGuard = deferRuleName !== void 0 ? `/*@FS:${deferRuleName}:${codeV}@*/true` : needsFirstSetGuard(p) ? firstSetCond(codeV, p._meta.firstSet) : (() => {
3879
+ if (p._meta.firstSet.kind !== "any" || matchesEmpty(p)) return null;
3880
+ const deep = firstSetOf(p);
3881
+ return deep.kind === "ranges" ? firstSetCond(codeV, deep) : null;
3882
+ })();
3835
3883
  let gateCond = null;
3836
3884
  if (gate) {
3837
3885
  const gateIdx = ctx.mapFns.length;
3838
3886
  ctx.mapFns.push(gate);
3887
+ ctx.mapFnSrcs.push(null);
3839
3888
  gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
3840
3889
  }
3841
3890
  const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
@@ -3894,13 +3943,21 @@ function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
3894
3943
  return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
3895
3944
  return emitFirstMatch(def, ctx, pos);
3896
3945
  }
3946
+ function pushMapFn(ctx, fn, src) {
3947
+ if (src !== null && ctx.mapFns.length === ctx.mapFnSrcs.length) {
3948
+ const hit = ctx.mapFnSrcs.indexOf(src);
3949
+ if (hit !== -1) return hit;
3950
+ }
3951
+ const idx = ctx.mapFns.length;
3952
+ ctx.mapFns.push(fn);
3953
+ ctx.mapFnSrcs.push(src);
3954
+ return idx;
3955
+ }
3897
3956
  function emitTransformChain(p, baseValue, endV, startPos, ctx) {
3898
3957
  const def = p._def;
3899
3958
  if (def.tag === "transform") {
3900
3959
  const innerR = emitTransformChain(def.parser, baseValue, endV, startPos, ctx);
3901
- const fnIdx = ctx.mapFns.length;
3902
- ctx.mapFns.push(def.fn);
3903
- ctx.mapFnSrcs.push(def.fnSrc ?? null);
3960
+ const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
3904
3961
  const vv = v(ctx);
3905
3962
  return {
3906
3963
  stmts: [...innerR.stmts, `${ind(ctx)}const ${vv} = ${mfRef(ctx)}[${fnIdx}](${innerR.valueVar}, { start: ${startPos}, end: ${endV} })`],
@@ -4083,7 +4140,7 @@ function emitScanTo(def, ctx, pos) {
4083
4140
  `${ind(ctx)}while (${curV} < input.length) {`
4084
4141
  ];
4085
4142
  ctx.indent++;
4086
- const probeCtx = { ...ctx, capturing: false };
4143
+ const probeCtx = { ...ctx, capturing: false, noHoist: true };
4087
4144
  const { stmts: sentStmts, okVar: sentOk } = emitFallible(def.sentinel, probeCtx, curV);
4088
4145
  stmts.push(...sentStmts, `${ind(ctx)}if (${sentOk}) { ${foundV} = true; break }`);
4089
4146
  if (def.skip.length > 0) {
@@ -4274,6 +4331,32 @@ function emitExpect(def, ctx, pos) {
4274
4331
  return { stmts, valueVar: valVar, endVar };
4275
4332
  }
4276
4333
  function emit(p, ctx, pos) {
4334
+ const usage = ctx.lazyUsage;
4335
+ if (usage && !ctx.noHoist && !ctx.capAsTrivia && !ctx.ruleNames?.has(p) && isHoistableTag(p._def.tag) && (usage.counts.get(p) ?? 0) > 1 && // Only hoist subtrees big enough that de-duplicating them beats the call
4336
+ // overhead. A tiny shared wrapper (e.g. `optional(literal(';'))`) inlines
4337
+ // faster than it calls and barely moves the byte count; the size explosion
4338
+ // is all in LARGE choices/sequences referenced from many positions.
4339
+ (usage.sizes.get(p) ?? 0) >= HOIST_MIN_SUBTREE) {
4340
+ const existing = ctx.namedParsers.get(p);
4341
+ if (existing !== void 0) return emitNamedFnCall(ctx, existing, pos);
4342
+ const fnName = `${nsp(ctx)}_pf${ctx.namedParsers.size}`;
4343
+ ctx.namedParsers.set(p, fnName);
4344
+ const savedIndent = ctx.indent;
4345
+ const savedFailLabel = ctx.failLabel;
4346
+ const savedRecord = ctx.recordFail;
4347
+ ctx.indent = 1;
4348
+ ctx.failLabel = "_pfail";
4349
+ ctx.recordFail = true;
4350
+ const r = emitDispatch(p, ctx, "_pos");
4351
+ ctx.indent = savedIndent;
4352
+ ctx.failLabel = savedFailLabel;
4353
+ ctx.recordFail = savedRecord;
4354
+ pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
4355
+ return emitNamedFnCall(ctx, fnName, pos);
4356
+ }
4357
+ return emitDispatch(p, ctx, pos);
4358
+ }
4359
+ function emitDispatch(p, ctx, pos) {
4277
4360
  const def = p._def;
4278
4361
  switch (def.tag) {
4279
4362
  case "literal":
@@ -4319,9 +4402,7 @@ function emit(p, ctx, pos) {
4319
4402
  };
4320
4403
  }
4321
4404
  }
4322
- const fnIdx = ctx.mapFns.length;
4323
- ctx.mapFns.push(def.fn);
4324
- ctx.mapFnSrcs.push(def.fnSrc ?? null);
4405
+ const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
4325
4406
  const mv = v(ctx, "_mapped");
4326
4407
  return {
4327
4408
  stmts: [
@@ -4386,6 +4467,7 @@ function emit(p, ctx, pos) {
4386
4467
  case "guard": {
4387
4468
  const fnIdx = ctx.mapFns.length;
4388
4469
  ctx.mapFns.push(def.predicate);
4470
+ ctx.mapFnSrcs.push(null);
4389
4471
  const vv = v(ctx);
4390
4472
  return {
4391
4473
  stmts: [
@@ -4400,6 +4482,7 @@ function emit(p, ctx, pos) {
4400
4482
  const evIdx = ctx.mapFns.length;
4401
4483
  const extra = def.extra;
4402
4484
  ctx.mapFns.push((() => extra));
4485
+ ctx.mapFnSrcs.push(null);
4403
4486
  const innerParser = def.parser;
4404
4487
  if (!ctx.namedParsers.has(innerParser)) {
4405
4488
  const fnName = `_wcf${ctx.namedParsers.size}`;
@@ -4519,9 +4602,58 @@ function childrenOf(def) {
4519
4602
  return [];
4520
4603
  }
4521
4604
  }
4605
+ var HOISTABLE_TAGS = /* @__PURE__ */ new Set([
4606
+ "sequence",
4607
+ "choice",
4608
+ "many",
4609
+ "oneOrMore",
4610
+ "optional",
4611
+ "sepBy",
4612
+ "transform",
4613
+ "node",
4614
+ "not"
4615
+ ]);
4616
+ function isHoistableTag(tag) {
4617
+ return HOISTABLE_TAGS.has(tag);
4618
+ }
4619
+ var HOIST_MIN_SUBTREE = 3;
4522
4620
  function analyzeLazyUsage(root) {
4523
4621
  return analyzeLazyUsageMulti([root]);
4524
4622
  }
4623
+ function subtreeSizes(roots) {
4624
+ const sizes = /* @__PURE__ */ new Map();
4625
+ const sz = (p) => {
4626
+ const cached = sizes.get(p);
4627
+ if (cached !== void 0) return cached;
4628
+ const def = p._def;
4629
+ let s = 1;
4630
+ if (def.tag !== "lazy") {
4631
+ for (const child of childrenOf(def)) s += child._def.tag === "lazy" ? 1 : sz(child);
4632
+ }
4633
+ sizes.set(p, s);
4634
+ return s;
4635
+ };
4636
+ const visitedLazy = /* @__PURE__ */ new Set();
4637
+ const visit = (p) => {
4638
+ const def = p._def;
4639
+ if (def.tag === "lazy") {
4640
+ if (visitedLazy.has(p)) return;
4641
+ visitedLazy.add(p);
4642
+ let resolved;
4643
+ try {
4644
+ resolved = def.thunk();
4645
+ } catch {
4646
+ return;
4647
+ }
4648
+ visit(resolved);
4649
+ return;
4650
+ }
4651
+ sz(p);
4652
+ for (const child of childrenOf(def)) visit(child);
4653
+ };
4654
+ for (const root of roots) visit(root);
4655
+ return sizes;
4656
+ }
4525
4657
  function analyzeLazyUsageMulti(roots) {
4526
4658
  const counts = /* @__PURE__ */ new Map();
4527
4659
  const recursive = /* @__PURE__ */ new Set();
@@ -4548,10 +4680,14 @@ function analyzeLazyUsageMulti(roots) {
4548
4680
  active.delete(p);
4549
4681
  return;
4550
4682
  }
4683
+ if (isHoistableTag(def.tag)) {
4684
+ counts.set(p, (counts.get(p) ?? 0) + 1);
4685
+ }
4551
4686
  for (const child of childrenOf(def)) walk2(child);
4552
4687
  }
4553
- for (const root of roots) walk2(root);
4554
- return { counts, recursive };
4688
+ const rootsArr = [...roots];
4689
+ for (const root of rootsArr) walk2(root);
4690
+ return { counts, recursive, sizes: subtreeSizes(rootsArr) };
4555
4691
  }
4556
4692
  function ruleDependencies(ruleMap) {
4557
4693
  const nameOf = /* @__PURE__ */ new Map();
@@ -4877,6 +5013,172 @@ function buildInlineExpression(ctx, r, mapFnSources, buildSources) {
4877
5013
  ].join("\n");
4878
5014
  }
4879
5015
 
5016
+ // src/combinators/scanTo.ts
5017
+ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
5018
+ const meta = {
5019
+ firstSet: any(),
5020
+ canMatchNewline: true,
5021
+ isTrivia: false
5022
+ };
5023
+ return {
5024
+ _tag: "scanTo",
5025
+ _meta: meta,
5026
+ _def: { tag: "scanTo", sentinel, skip: skip2, orEOF },
5027
+ parse(input, pos, ctx) {
5028
+ let cur = pos;
5029
+ const probeCtx = {
5030
+ trackLines: ctx.trackLines,
5031
+ state: ctx.state,
5032
+ ...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
5033
+ };
5034
+ const emit2 = (end) => {
5035
+ if (end > pos && cstCaptureActive(ctx)) {
5036
+ const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
5037
+ pushCstLeaf(ctx, leaf);
5038
+ }
5039
+ };
5040
+ while (cur < input.length) {
5041
+ const s = sentinel.parse(input, cur, probeCtx);
5042
+ if (s.ok) {
5043
+ emit2(cur);
5044
+ return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
5045
+ }
5046
+ let advanced = false;
5047
+ for (const skipper of skip2) {
5048
+ const r = skipper.parse(input, cur, probeCtx);
5049
+ if (r.ok && r.span.end > cur) {
5050
+ cur = r.span.end;
5051
+ advanced = true;
5052
+ break;
5053
+ }
5054
+ }
5055
+ if (!advanced) cur++;
5056
+ }
5057
+ if (orEOF) {
5058
+ emit2(cur);
5059
+ return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
5060
+ }
5061
+ const sentDef = sentinel._def;
5062
+ const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
5063
+ return { ok: false, expected, span: { start: pos, end: cur } };
5064
+ }
5065
+ };
5066
+ }
5067
+ function balanced(open, close, options = {}) {
5068
+ const self = ref();
5069
+ const skips = options.skip ?? [];
5070
+ const stop = /* @__PURE__ */ new Set([open, close]);
5071
+ let bounded = true;
5072
+ for (const sk of skips) {
5073
+ const cs = firstSetClassChars(sk);
5074
+ if (cs === null) {
5075
+ bounded = false;
5076
+ break;
5077
+ }
5078
+ for (const ch of cs) stop.add(ch);
5079
+ }
5080
+ const cls = [...stop].map(escapeClassChar).join("");
5081
+ const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
5082
+ const inner = many(choice(self, ...skips, content));
5083
+ const combi = transform(
5084
+ sequence(literal(open), inner, expect(literal(close), close)),
5085
+ // parts: strings (content/self) or arrays (a sequence-shaped skip) or a
5086
+ // ParseError (recovered close). `c` is the close string or a ParseError.
5087
+ ([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
5088
+ );
5089
+ if (combi._def.tag === "transform") {
5090
+ combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
5091
+ }
5092
+ self.define(combi);
5093
+ return combi;
5094
+ }
5095
+ function firstSetClassChars(c) {
5096
+ const fs = c._meta.firstSet;
5097
+ if (fs.kind === "empty") return [];
5098
+ if (fs.kind !== "ranges") return null;
5099
+ const out = [];
5100
+ for (const { lo, hi } of fs.ranges) {
5101
+ if (hi - lo > 8) return null;
5102
+ for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
5103
+ }
5104
+ return out;
5105
+ }
5106
+ function escapeClassChar(ch) {
5107
+ return ch.replace(/[\\\]^-]/g, "\\$&");
5108
+ }
5109
+
5110
+ // src/compiler/ir-serialize.ts
5111
+ function evalRuleMapIR(ir) {
5112
+ const _tf = (child, src) => {
5113
+ let fn2;
5114
+ try {
5115
+ fn2 = (0, eval)(`(${src})`);
5116
+ } catch {
5117
+ fn2 = () => {
5118
+ throw new Error("IR transform fn not materialized");
5119
+ };
5120
+ }
5121
+ const t = transform(child, fn2);
5122
+ t._def.fnSrc = src;
5123
+ return t;
5124
+ };
5125
+ const _nd = (type, child, src, opts) => {
5126
+ const n = node(type, child, void 0, opts);
5127
+ n._def.buildSrc = src;
5128
+ return n;
5129
+ };
5130
+ const fn = new Function(
5131
+ "rules",
5132
+ "ref",
5133
+ "regex",
5134
+ "literal",
5135
+ "keywords",
5136
+ "sequence",
5137
+ "choice",
5138
+ "many",
5139
+ "oneOrMore",
5140
+ "optional",
5141
+ "sepBy",
5142
+ "not",
5143
+ "node",
5144
+ "parser",
5145
+ "scanTo",
5146
+ "transform",
5147
+ "skip",
5148
+ "trivia",
5149
+ "label",
5150
+ "expect",
5151
+ "_tf",
5152
+ "_nd",
5153
+ `return (${ir})`
5154
+ );
5155
+ const map = fn(
5156
+ rules,
5157
+ ref,
5158
+ regex,
5159
+ literal,
5160
+ keywords,
5161
+ sequence,
5162
+ choice,
5163
+ many,
5164
+ oneOrMore,
5165
+ optional,
5166
+ sepBy,
5167
+ not,
5168
+ node,
5169
+ parser,
5170
+ scanTo,
5171
+ transform,
5172
+ skip,
5173
+ trivia,
5174
+ label,
5175
+ expect,
5176
+ _tf,
5177
+ _nd
5178
+ );
5179
+ return Object.entries(map);
5180
+ }
5181
+
4880
5182
  // src/compiler/linker.ts
4881
5183
  var _nsCounter = 0;
4882
5184
  function linkable(rulesMap, ns) {
@@ -4961,9 +5263,18 @@ function fuseRules(pieces) {
4961
5263
  return new Function("_env", body)(env);
4962
5264
  }
4963
5265
  var COMPOSED_PIECES = /* @__PURE__ */ Symbol.for("parseman.composedPieces");
5266
+ function isIRPiece(p) {
5267
+ return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
5268
+ }
5269
+ function materializePiece(p) {
5270
+ if (!isIRPiece(p)) return p;
5271
+ const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns);
5272
+ if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
5273
+ return pieces;
5274
+ }
4964
5275
  function itemPieces(item) {
4965
5276
  const carried = item[COMPOSED_PIECES];
4966
- if (Array.isArray(carried)) return carried;
5277
+ if (Array.isArray(carried)) return carried.map(materializePiece);
4967
5278
  if (item.ruleFns instanceof Map) return [item];
4968
5279
  return [linkable(item)];
4969
5280
  }
@@ -5059,100 +5370,6 @@ function deeperFail(a, b) {
5059
5370
  return a.span.start >= b.span.start ? a : b;
5060
5371
  }
5061
5372
 
5062
- // src/combinators/scanTo.ts
5063
- function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
5064
- const meta = {
5065
- firstSet: any(),
5066
- canMatchNewline: true,
5067
- isTrivia: false
5068
- };
5069
- return {
5070
- _tag: "scanTo",
5071
- _meta: meta,
5072
- _def: { tag: "scanTo", sentinel, skip: skip2, orEOF },
5073
- parse(input, pos, ctx) {
5074
- let cur = pos;
5075
- const probeCtx = {
5076
- trackLines: ctx.trackLines,
5077
- state: ctx.state,
5078
- ...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
5079
- };
5080
- const emit2 = (end) => {
5081
- if (end > pos && cstCaptureActive(ctx)) {
5082
- const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
5083
- pushCstLeaf(ctx, leaf);
5084
- }
5085
- };
5086
- while (cur < input.length) {
5087
- const s = sentinel.parse(input, cur, probeCtx);
5088
- if (s.ok) {
5089
- emit2(cur);
5090
- return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
5091
- }
5092
- let advanced = false;
5093
- for (const skipper of skip2) {
5094
- const r = skipper.parse(input, cur, probeCtx);
5095
- if (r.ok && r.span.end > cur) {
5096
- cur = r.span.end;
5097
- advanced = true;
5098
- break;
5099
- }
5100
- }
5101
- if (!advanced) cur++;
5102
- }
5103
- if (orEOF) {
5104
- emit2(cur);
5105
- return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
5106
- }
5107
- const sentDef = sentinel._def;
5108
- const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
5109
- return { ok: false, expected, span: { start: pos, end: cur } };
5110
- }
5111
- };
5112
- }
5113
- function balanced(open, close, options = {}) {
5114
- const self = ref();
5115
- const skips = options.skip ?? [];
5116
- const stop = /* @__PURE__ */ new Set([open, close]);
5117
- let bounded = true;
5118
- for (const sk of skips) {
5119
- const cs = firstSetClassChars(sk);
5120
- if (cs === null) {
5121
- bounded = false;
5122
- break;
5123
- }
5124
- for (const ch of cs) stop.add(ch);
5125
- }
5126
- const cls = [...stop].map(escapeClassChar).join("");
5127
- const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
5128
- const inner = many(choice(self, ...skips, content));
5129
- const combi = transform(
5130
- sequence(literal(open), inner, expect(literal(close), close)),
5131
- // parts: strings (content/self) or arrays (a sequence-shaped skip) or a
5132
- // ParseError (recovered close). `c` is the close string or a ParseError.
5133
- ([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
5134
- );
5135
- if (combi._def.tag === "transform") {
5136
- combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
5137
- }
5138
- self.define(combi);
5139
- return combi;
5140
- }
5141
- function firstSetClassChars(c) {
5142
- const fs = c._meta.firstSet;
5143
- if (fs.kind === "empty") return [];
5144
- if (fs.kind !== "ranges") return null;
5145
- const out = [];
5146
- for (const { lo, hi } of fs.ranges) {
5147
- if (hi - lo > 8) return null;
5148
- for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
5149
- }
5150
- return out;
5151
- }
5152
- function escapeClassChar(ch) {
5153
- return ch.replace(/[\\\]^-]/g, "\\$&");
5154
- }
5155
-
5156
5373
  // src/combinators/recover-list.ts
5157
5374
  function tolerantElement(item, sentinel, until) {
5158
5375
  const el = transform(