parseman 0.4.0 → 0.6.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.
Files changed (65) hide show
  1. package/README.md +48 -17
  2. package/dist/combinators/choice.d.ts.map +1 -1
  3. package/dist/combinators/completions.d.ts +1 -1
  4. package/dist/combinators/completions.d.ts.map +1 -1
  5. package/dist/combinators/grammar.d.ts.map +1 -1
  6. package/dist/combinators/keywords.d.ts +22 -0
  7. package/dist/combinators/keywords.d.ts.map +1 -1
  8. package/dist/combinators/literal.d.ts.map +1 -1
  9. package/dist/combinators/map.d.ts +8 -2
  10. package/dist/combinators/map.d.ts.map +1 -1
  11. package/dist/combinators/node.d.ts +10 -11
  12. package/dist/combinators/node.d.ts.map +1 -1
  13. package/dist/combinators/not.d.ts +3 -3
  14. package/dist/combinators/not.d.ts.map +1 -1
  15. package/dist/combinators/recover.d.ts +2 -2
  16. package/dist/combinators/recover.d.ts.map +1 -1
  17. package/dist/combinators/regex.d.ts.map +1 -1
  18. package/dist/combinators/repeat.d.ts +4 -4
  19. package/dist/combinators/repeat.d.ts.map +1 -1
  20. package/dist/combinators/scanTo.d.ts.map +1 -1
  21. package/dist/combinators/sequence.d.ts.map +1 -1
  22. package/dist/combinators/trivia-skip.d.ts +16 -10
  23. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  24. package/dist/combinators/withCtx.d.ts +2 -2
  25. package/dist/combinators/withCtx.d.ts.map +1 -1
  26. package/dist/compiler/codegen.d.ts +4 -2
  27. package/dist/compiler/codegen.d.ts.map +1 -1
  28. package/dist/compiler/inline-build.d.ts +11 -0
  29. package/dist/compiler/inline-build.d.ts.map +1 -0
  30. package/dist/compiler/inline-callback.d.ts +12 -0
  31. package/dist/compiler/inline-callback.d.ts.map +1 -0
  32. package/dist/compiler/trivia-fast-path.d.ts +24 -0
  33. package/dist/compiler/trivia-fast-path.d.ts.map +1 -0
  34. package/dist/cst/capture-buffer.d.ts +46 -0
  35. package/dist/cst/capture-buffer.d.ts.map +1 -0
  36. package/dist/cst/trivia-entries.d.ts +20 -0
  37. package/dist/cst/trivia-entries.d.ts.map +1 -0
  38. package/dist/cst/trivia-index.d.ts +11 -11
  39. package/dist/cst/trivia-index.d.ts.map +1 -1
  40. package/dist/cst/trivia-kinds.d.ts +47 -0
  41. package/dist/cst/trivia-kinds.d.ts.map +1 -0
  42. package/dist/cst/types.d.ts +9 -13
  43. package/dist/cst/types.d.ts.map +1 -1
  44. package/dist/functional/doc.d.ts +2 -20
  45. package/dist/functional/doc.d.ts.map +1 -1
  46. package/dist/index.cjs +1238 -662
  47. package/dist/index.cjs.map +4 -4
  48. package/dist/index.d.ts +4 -5
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +1256 -6241
  51. package/dist/index.js.map +4 -4
  52. package/dist/plugin/evaluator.d.ts +7 -0
  53. package/dist/plugin/evaluator.d.ts.map +1 -1
  54. package/dist/plugin/index.cjs +1249 -369
  55. package/dist/plugin/index.cjs.map +4 -4
  56. package/dist/plugin/index.d.ts.map +1 -1
  57. package/dist/plugin/index.js +1249 -369
  58. package/dist/plugin/index.js.map +4 -4
  59. package/dist/types.d.ts +32 -9
  60. package/dist/types.d.ts.map +1 -1
  61. package/package.json +8 -3
  62. package/dist/cst/grammar.d.ts +0 -115
  63. package/dist/cst/grammar.d.ts.map +0 -1
  64. package/dist/cst/incremental.d.ts +0 -40
  65. package/dist/cst/incremental.d.ts.map +0 -1
@@ -128,6 +128,151 @@ function failAt(ctx, expected, pos) {
128
128
  return r;
129
129
  }
130
130
 
131
+ // src/cst/capture-buffer.ts
132
+ var EMPTY = [];
133
+ var EMPTY_TL = [];
134
+ function cstCaptureActive(ctx) {
135
+ return ctx._cstBuf !== void 0 || ctx._cstLeaves !== void 0;
136
+ }
137
+ function beginCstNodeCapture(ctx) {
138
+ const saved = {
139
+ ch: ctx._cstChildren,
140
+ lv: ctx._cstLeaves,
141
+ raw: ctx._cstRawChildren,
142
+ tl: ctx._cstTriviaLog,
143
+ cap: ctx.captureTrivia,
144
+ buf: ctx._cstBuf
145
+ };
146
+ ctx._cstBuf = {};
147
+ ctx._cstChildren = void 0;
148
+ ctx._cstLeaves = void 0;
149
+ ctx._cstRawChildren = void 0;
150
+ ctx._cstTriviaLog = void 0;
151
+ ctx.captureTrivia = true;
152
+ return saved;
153
+ }
154
+ function finishCstBuf(buf) {
155
+ if (!buf) return { children: EMPTY, rawChildren: EMPTY, triviaLog: EMPTY_TL };
156
+ const children = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
157
+ const rawChildren = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
158
+ const triviaLog = buf.tl ?? EMPTY_TL;
159
+ return { children, rawChildren, triviaLog };
160
+ }
161
+ function endCstNodeCapture(ctx, saved) {
162
+ const materialized = finishCstBuf(ctx._cstBuf);
163
+ ctx._cstBuf = saved.buf;
164
+ ctx._cstChildren = saved.ch;
165
+ ctx._cstLeaves = saved.lv;
166
+ ctx._cstRawChildren = saved.raw;
167
+ ctx._cstTriviaLog = saved.tl;
168
+ ctx.captureTrivia = saved.cap;
169
+ return materialized;
170
+ }
171
+ function pushCstLeaf(ctx, leaf) {
172
+ pushCstChild(ctx, leaf, leaf);
173
+ }
174
+ function pushCstChild(ctx, built, rawEntry) {
175
+ const b = ctx._cstBuf;
176
+ if (b) {
177
+ if (b.ch) b.ch.push(built);
178
+ else if (b.single !== void 0) {
179
+ b.ch = [b.single, built];
180
+ b.single = void 0;
181
+ } else b.single = built;
182
+ if (b.raw) b.raw.push(rawEntry);
183
+ else if (b.rawSingle !== void 0) {
184
+ b.raw = [b.rawSingle, rawEntry];
185
+ b.rawSingle = void 0;
186
+ } else b.rawSingle = rawEntry;
187
+ return;
188
+ }
189
+ if (ctx._cstChildren) ctx._cstChildren.push(built);
190
+ else if (ctx._cstLeaves) ctx._cstLeaves.push(built);
191
+ if (ctx._cstRawChildren) ctx._cstRawChildren.push(rawEntry);
192
+ }
193
+ function cstRawLen(ctx) {
194
+ const b = ctx._cstBuf;
195
+ if (b) {
196
+ if (b.raw) return b.raw.length;
197
+ return b.rawSingle !== void 0 ? 1 : 0;
198
+ }
199
+ return ctx._cstRawChildren?.length ?? 0;
200
+ }
201
+ function cstLeavesLen(ctx) {
202
+ const b = ctx._cstBuf;
203
+ if (b) {
204
+ if (b.ch) return b.ch.length;
205
+ return b.single !== void 0 ? 1 : 0;
206
+ }
207
+ return ctx._cstLeaves?.length ?? 0;
208
+ }
209
+ function cstTlLen(ctx) {
210
+ const b = ctx._cstBuf;
211
+ if (b) return b.tl?.length ?? 0;
212
+ return ctx._cstTriviaLog?.length ?? 0;
213
+ }
214
+ function saveCstMark(ctx) {
215
+ return {
216
+ raw: cstRawLen(ctx),
217
+ tlog: cstTlLen(ctx),
218
+ leaves: cstLeavesLen(ctx)
219
+ };
220
+ }
221
+ function rollbackBufList(b, keyMulti, keySingle, len) {
222
+ const arr = b[keyMulti];
223
+ if (arr) {
224
+ if (len === 0) b[keyMulti] = void 0;
225
+ else if (len === 1) {
226
+ b[keySingle] = arr[0];
227
+ b[keyMulti] = void 0;
228
+ } else arr.length = len;
229
+ return;
230
+ }
231
+ if (len === 0) b[keySingle] = void 0;
232
+ }
233
+ function rollbackCstCapture(ctx, mark) {
234
+ const b = ctx._cstBuf;
235
+ if (b) {
236
+ rollbackBufList(b, "raw", "rawSingle", mark.raw);
237
+ rollbackBufList(b, "ch", "single", mark.leaves);
238
+ if (b.tl) {
239
+ if (mark.tlog === 0) b.tl = void 0;
240
+ else b.tl.length = mark.tlog;
241
+ }
242
+ return;
243
+ }
244
+ if (ctx._cstRawChildren) ctx._cstRawChildren.length = mark.raw;
245
+ if (ctx._cstTriviaLog) ctx._cstTriviaLog.length = mark.tlog;
246
+ if (ctx._cstLeaves) ctx._cstLeaves.length = mark.leaves;
247
+ }
248
+ function pushCstTriviaEntry(ctx, start, end, kindIndex) {
249
+ const insertIdx = cstRawLen(ctx);
250
+ const b = ctx._cstBuf;
251
+ const withKind = ctx.triviaKindLabels !== void 0 && kindIndex !== void 0;
252
+ if (b) {
253
+ if (!b.tl) {
254
+ b.tl = withKind ? [start, end, insertIdx, kindIndex] : [start, end, insertIdx];
255
+ } else if (withKind) {
256
+ b.tl.push(start, end, insertIdx, kindIndex);
257
+ } else {
258
+ b.tl.push(start, end, insertIdx);
259
+ }
260
+ return;
261
+ }
262
+ if (ctx._cstTriviaLog) {
263
+ if (withKind) ctx._cstTriviaLog.push(start, end, insertIdx, kindIndex);
264
+ else ctx._cstTriviaLog.push(start, end, insertIdx);
265
+ }
266
+ }
267
+ function pushTriviaLogEntry(ctx, start, end, kindIndex) {
268
+ if (!ctx._triviaLog) return;
269
+ if (ctx.triviaKindLabels !== void 0 && kindIndex !== void 0) {
270
+ ctx._triviaLog.push(start, end, kindIndex);
271
+ } else {
272
+ ctx._triviaLog.push(start, end);
273
+ }
274
+ }
275
+
131
276
  // src/combinators/literal.ts
132
277
  var _collatorCache = null;
133
278
  function collator() {
@@ -167,8 +312,7 @@ function literal(value, opts = {}) {
167
312
  if (matched) {
168
313
  const span = { start: pos, end };
169
314
  const leaf = { _tag: "leaf", value: slice, span };
170
- if (ctx._cstLeaves) ctx._cstLeaves.push(leaf);
171
- if (ctx._cstRawChildren) ctx._cstRawChildren.push(leaf);
315
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
172
316
  return { ok: true, value: slice, span };
173
317
  }
174
318
  return failAt(ctx, [JSON.stringify(value)], pos);
@@ -310,109 +454,60 @@ function regex(pattern, flags = "") {
310
454
  }
311
455
  const span = { start: pos, end: pos + m[0].length };
312
456
  const leaf = { _tag: "leaf", value: m[0], span };
313
- if (ctx._cstLeaves) ctx._cstLeaves.push(leaf);
314
- if (ctx._cstRawChildren) ctx._cstRawChildren.push(leaf);
457
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
315
458
  return { ok: true, value: m[0], span };
316
459
  }
317
460
  };
318
461
  }
319
462
 
320
- // src/combinators/trivia-skip.ts
321
- var NOOP_COMMIT = () => {
322
- };
323
- function scanTrivia(input, cur, ctx) {
324
- const triviaP = ctx.trivia;
325
- if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
326
- const log = ctx._triviaLog;
327
- if (log !== void 0) {
328
- const tr2 = triviaP.parse(input, cur, { trackLines: false, state: ctx.state });
329
- if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
330
- const end = tr2.span.end;
331
- return {
332
- end,
333
- commit: () => {
334
- log.push(cur, end);
335
- }
336
- };
337
- }
338
- if (ctx.captureTrivia && ctx._cstRawChildren) {
339
- const sink = [];
340
- const tr2 = triviaP.parse(input, cur, {
341
- trackLines: ctx.trackLines,
342
- state: ctx.state,
343
- _cstLeaves: sink
344
- });
345
- if (tr2.ok && tr2.span.end > cur) {
346
- const out = ctx._cstRawChildren;
347
- return {
348
- end: tr2.span.end,
349
- commit: () => {
350
- for (const tok of sink) {
351
- if (tok._tag === "leaf" && tok.span.end > tok.span.start) {
352
- out.push({ _tag: "trivia", value: tok.value, span: tok.span });
353
- }
354
- }
355
- }
356
- };
357
- }
358
- return { end: cur, commit: NOOP_COMMIT };
359
- }
360
- const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
361
- return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
362
- }
363
- function consumeTrivia(input, cur, ctx) {
364
- const scan = scanTrivia(input, cur, ctx);
365
- scan.commit();
366
- return scan.end;
367
- }
368
-
369
- // src/combinators/sequence.ts
370
- function sequence(...parsers) {
371
- const meta = {
372
- firstSet: parsers[0]?._meta.firstSet ?? empty(),
373
- canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
374
- isTrivia: false
375
- };
463
+ // src/combinators/keywords.ts
464
+ function word(str, boundary = "_0-9A-Za-z") {
465
+ return keywords([str], { boundary });
466
+ }
467
+ function escapeRe(s) {
468
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
469
+ }
470
+ function keywords(words, opts = {}) {
471
+ const sorted = [...new Set(words)].sort((a, b) => b.length - a.length);
472
+ const alt = sorted.map(escapeRe).join("|");
473
+ const boundary = opts.boundary ? `(?![${opts.boundary}])` : "";
474
+ const flags = opts.caseInsensitive ? "iuy" : "uy";
475
+ const re = new RegExp(`(?:${alt})${boundary}`, flags);
476
+ let firstSet = empty();
477
+ for (const w of sorted) {
478
+ if (w.length === 0) continue;
479
+ const cp = w.codePointAt(0);
480
+ firstSet = union(firstSet, fromChar(cp));
481
+ if (opts.caseInsensitive) {
482
+ const u = String.fromCodePoint(cp).toUpperCase().codePointAt(0);
483
+ const l = String.fromCodePoint(cp).toLowerCase().codePointAt(0);
484
+ if (u !== void 0) firstSet = union(firstSet, fromChar(u));
485
+ if (l !== void 0) firstSet = union(firstSet, fromChar(l));
486
+ }
487
+ }
488
+ const meta = { firstSet, canMatchNewline: false, isTrivia: false };
376
489
  return {
377
- _tag: "sequence",
490
+ _tag: "keywords",
378
491
  _meta: meta,
379
- _def: { tag: "sequence", parsers },
492
+ _def: { tag: "keywords", words: sorted, caseInsensitive: opts.caseInsensitive ?? false, boundary: opts.boundary },
380
493
  parse(input, pos, ctx) {
381
- const values = [];
382
- let cur = pos;
383
- for (let i = 0; i < parsers.length; i++) {
384
- if (ctx.trivia && i > 0) {
385
- const scan = scanTrivia(input, cur, ctx);
386
- const raw = ctx._cstRawChildren;
387
- const mark = raw ? raw.length : 0;
388
- scan.commit();
389
- const result2 = parsers[i].parse(input, scan.end, ctx);
390
- if (!result2.ok) return result2;
391
- if (result2.span.end > scan.end) {
392
- cur = result2.span.end;
393
- } else if (raw) {
394
- raw.length = mark;
395
- }
396
- values.push(result2.value);
397
- continue;
398
- }
399
- const result = parsers[i].parse(input, cur, ctx);
400
- if (!result.ok) return result;
401
- values.push(result.value);
402
- cur = result.span.end;
494
+ re.lastIndex = pos;
495
+ const m = re.exec(input);
496
+ if (m === null || m.index !== pos) {
497
+ return failAt(ctx, ["keyword"], pos);
403
498
  }
404
- return {
405
- ok: true,
406
- value: values,
407
- span: { start: pos, end: cur }
408
- };
499
+ const value = m[0];
500
+ const span = { start: pos, end: pos + value.length };
501
+ const leaf = { _tag: "leaf", value, span };
502
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
503
+ return { ok: true, value, span };
409
504
  }
410
505
  };
411
506
  }
412
507
 
413
508
  // src/combinators/choice.ts
414
509
  function choice(...args) {
415
- const parsers = args.map((a) => "gate" in a ? a.parser : a);
510
+ const parsers = args.map((a) => "gate" in a ? a.combinator : a);
416
511
  const gates = args.map((a) => "gate" in a ? a.gate : null);
417
512
  const hasGates = gates.some((g) => g !== null);
418
513
  const disjoint = !hasGates && areDisjoint(parsers.map((p) => p._meta.firstSet));
@@ -496,19 +591,19 @@ function choice(...args) {
496
591
  }
497
592
  for (let i = 0; i < parsers.length; i++) {
498
593
  if (gates[i] && !gates[i](ctx.state)) continue;
499
- const leavesLen = ctx._cstLeaves?.length;
500
- const rawLen = ctx._cstRawChildren?.length;
594
+ const mark = saveCstMark(ctx);
595
+ const logLen = ctx._triviaLog?.length;
501
596
  const result = parsers[i].parse(input, pos, ctx);
502
597
  if (!result.ok) {
503
- if (leavesLen !== void 0 && ctx._cstLeaves) ctx._cstLeaves.length = leavesLen;
504
- if (rawLen !== void 0 && ctx._cstRawChildren) ctx._cstRawChildren.length = rawLen;
598
+ rollbackCstCapture(ctx, mark);
599
+ if (logLen !== void 0 && ctx._triviaLog) ctx._triviaLog.length = logLen;
505
600
  expected.push(...result.expected);
506
601
  continue;
507
602
  }
508
603
  const checks = autoNot[i];
509
604
  if (checks && autoNotFires(input, result.span.end, checks)) {
510
- if (leavesLen !== void 0 && ctx._cstLeaves) ctx._cstLeaves.length = leavesLen;
511
- if (rawLen !== void 0 && ctx._cstRawChildren) ctx._cstRawChildren.length = rawLen;
605
+ rollbackCstCapture(ctx, mark);
606
+ if (logLen !== void 0 && ctx._triviaLog) ctx._triviaLog.length = logLen;
512
607
  continue;
513
608
  }
514
609
  return result;
@@ -587,6 +682,7 @@ function getCoreRegexDef(p) {
587
682
  const def = p._def;
588
683
  if (def.tag === "regex") return { source: def.source, flags: def.flags };
589
684
  if (def.tag === "transform") return getCoreRegexDef(def.parser);
685
+ if (def.tag === "label") return getCoreRegexDef(def.parser);
590
686
  return null;
591
687
  }
592
688
  function applyTransforms(p, value, span) {
@@ -640,46 +736,275 @@ function areDisjoint(sets) {
640
736
  return true;
641
737
  }
642
738
 
739
+ // src/cst/trivia-kinds.ts
740
+ function unwrapTrivia(p) {
741
+ let cur = p;
742
+ while (cur._def.tag === "trivia") cur = cur._def.parser;
743
+ return cur;
744
+ }
745
+ function peelLabel(p) {
746
+ if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
747
+ return null;
748
+ }
749
+ function analyzeLabeledTrivia(trivia2) {
750
+ let core = unwrapTrivia(trivia2);
751
+ let minRepeats = 1;
752
+ if (core._def.tag === "oneOrMore") {
753
+ core = core._def.parser;
754
+ minRepeats = 1;
755
+ } else if (core._def.tag === "many") {
756
+ core = core._def.parser;
757
+ minRepeats = 0;
758
+ }
759
+ const arms = [];
760
+ if (core._def.tag === "choice") {
761
+ for (let i = 0; i < core._def.parsers.length; i++) {
762
+ const peeled = peelLabel(core._def.parsers[i]);
763
+ if (!peeled) return null;
764
+ arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
765
+ }
766
+ } else {
767
+ const peeled = peelLabel(core);
768
+ if (!peeled) return null;
769
+ arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
770
+ }
771
+ return { labels: arms.map((a) => a.label), arms, minRepeats };
772
+ }
773
+ function matchArmAt(input, pos, arm) {
774
+ const r = arm.parse(input, pos, { trackLines: false });
775
+ if (!r.ok || r.span.end <= pos) return null;
776
+ return { end: r.span.end };
777
+ }
778
+ function scanLabeledTriviaChunks(input, cur, spec) {
779
+ const chunks = [];
780
+ let pos = cur;
781
+ while (pos < input.length) {
782
+ let matched = null;
783
+ for (const arm of spec.arms) {
784
+ const m = matchArmAt(input, pos, arm.parser);
785
+ if (m) {
786
+ matched = { end: m.end, kindIndex: arm.kindIndex };
787
+ break;
788
+ }
789
+ }
790
+ if (!matched) break;
791
+ chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
792
+ pos = matched.end;
793
+ }
794
+ if (chunks.length < spec.minRepeats) {
795
+ return { end: cur, chunks: [] };
796
+ }
797
+ return { end: pos, chunks };
798
+ }
799
+ function scanFastWsCommentsChunks(input, cur, wsKind, commentKind) {
800
+ const chunks = [];
801
+ let pos = cur;
802
+ while (pos < input.length) {
803
+ const c = input.charCodeAt(pos);
804
+ if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {
805
+ const start = pos;
806
+ pos++;
807
+ while (pos < input.length) {
808
+ const c2 = input.charCodeAt(pos);
809
+ if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) pos++;
810
+ else break;
811
+ }
812
+ chunks.push({ start, end: pos, kindIndex: wsKind });
813
+ continue;
814
+ }
815
+ if (c === 47 && input.charCodeAt(pos + 1) === 42) {
816
+ const start = pos;
817
+ let j = pos + 2;
818
+ while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++;
819
+ pos = j + 2 <= input.length ? j + 2 : input.length;
820
+ chunks.push({ start, end: pos, kindIndex: commentKind });
821
+ continue;
822
+ }
823
+ break;
824
+ }
825
+ return { end: pos, chunks };
826
+ }
827
+ function tryFastLabeledScan(input, cur, trivia2) {
828
+ const spec = analyzeLabeledTrivia(trivia2);
829
+ if (!spec || spec.arms.length !== 2) return null;
830
+ const wsArm = spec.arms.find((a) => {
831
+ const src = getCoreRegexDef(a.parser)?.source;
832
+ return src != null && !src.includes("\\*");
833
+ });
834
+ const commentArm = spec.arms.find((a) => {
835
+ const src = getCoreRegexDef(a.parser)?.source;
836
+ return src != null && src.includes("\\*");
837
+ });
838
+ if (!wsArm || !commentArm) return null;
839
+ const { chunks } = scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
840
+ if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
841
+ return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
842
+ }
843
+ function recordTriviaChunks(ctx, chunks) {
844
+ const kinds = ctx.triviaKindLabels;
845
+ for (const ch of chunks) {
846
+ pushTriviaLogEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
847
+ if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
848
+ pushCstTriviaEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
849
+ }
850
+ }
851
+ }
852
+
853
+ // src/combinators/trivia-skip.ts
854
+ var NOOP_COMMIT = () => {
855
+ };
856
+ function needsDeferredTriviaCommit(ctx) {
857
+ return ctx._triviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
858
+ }
859
+ function saveTriviaMark(ctx) {
860
+ const m = saveCstMark(ctx);
861
+ return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
862
+ }
863
+ function rollbackTrivia(ctx, mark) {
864
+ rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves });
865
+ if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
866
+ }
867
+ function scanWithLabels(input, cur, ctx) {
868
+ const triviaP = ctx.trivia;
869
+ const spec = analyzeLabeledTrivia(triviaP);
870
+ if (!spec) return { end: cur, commit: NOOP_COMMIT };
871
+ const fast = tryFastLabeledScan(input, cur, triviaP);
872
+ const { end, chunks } = fast ?? scanLabeledTriviaChunks(input, cur, spec);
873
+ if (end === cur) return { end: cur, commit: NOOP_COMMIT };
874
+ return {
875
+ end,
876
+ commit: () => recordTriviaChunks(ctx, chunks)
877
+ };
878
+ }
879
+ function advanceTrivia(input, cur, ctx) {
880
+ const triviaP = ctx.trivia;
881
+ if (!triviaP) return cur;
882
+ if (ctx.triviaKindLabels) {
883
+ const scan = scanWithLabels(input, cur, ctx);
884
+ return scan.end;
885
+ }
886
+ const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
887
+ return tr.ok && tr.span.end > cur ? tr.span.end : cur;
888
+ }
889
+ function scanTrivia(input, cur, ctx) {
890
+ const triviaP = ctx.trivia;
891
+ if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
892
+ const log = ctx._triviaLog;
893
+ const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
894
+ if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
895
+ return scanWithLabels(input, cur, ctx);
896
+ }
897
+ if (log !== void 0 || captureTl) {
898
+ const tr2 = triviaP.parse(input, cur, {
899
+ trackLines: log !== void 0 ? false : ctx.trackLines,
900
+ state: ctx.state
901
+ });
902
+ if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
903
+ const end = tr2.span.end;
904
+ return {
905
+ end,
906
+ commit: () => {
907
+ pushTriviaLogEntry(ctx, cur, end);
908
+ if (captureTl) pushCstTriviaEntry(ctx, cur, end);
909
+ }
910
+ };
911
+ }
912
+ const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
913
+ return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
914
+ }
915
+
916
+ // src/combinators/sequence.ts
917
+ function sequence(...parsers) {
918
+ const meta = {
919
+ firstSet: parsers[0]?._meta.firstSet ?? empty(),
920
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
921
+ isTrivia: false
922
+ };
923
+ return {
924
+ _tag: "sequence",
925
+ _meta: meta,
926
+ _def: { tag: "sequence", parsers },
927
+ parse(input, pos, ctx) {
928
+ const values = [];
929
+ let cur = pos;
930
+ for (let i = 0; i < parsers.length; i++) {
931
+ if (ctx.trivia && i > 0) {
932
+ let scanEnd;
933
+ let mark = saveTriviaMark(ctx);
934
+ if (needsDeferredTriviaCommit(ctx)) {
935
+ const scan = scanTrivia(input, cur, ctx);
936
+ scan.commit();
937
+ scanEnd = scan.end;
938
+ } else {
939
+ scanEnd = advanceTrivia(input, cur, ctx);
940
+ }
941
+ const result2 = parsers[i].parse(input, scanEnd, ctx);
942
+ if (!result2.ok) return result2;
943
+ if (result2.span.end > scanEnd) {
944
+ cur = result2.span.end;
945
+ } else {
946
+ rollbackTrivia(ctx, mark);
947
+ }
948
+ values.push(result2.value);
949
+ continue;
950
+ }
951
+ const result = parsers[i].parse(input, cur, ctx);
952
+ if (!result.ok) return result;
953
+ values.push(result.value);
954
+ cur = result.span.end;
955
+ }
956
+ return {
957
+ ok: true,
958
+ value: values,
959
+ span: { start: pos, end: cur }
960
+ };
961
+ }
962
+ };
963
+ }
964
+
643
965
  // src/combinators/repeat.ts
644
- function repItem(parser2, input, cur, ctx) {
645
- const raw = ctx._cstRawChildren;
646
- const mark = raw ? raw.length : 0;
966
+ function repItem(combinator, input, cur, ctx) {
967
+ const mark = saveTriviaMark(ctx);
647
968
  let pos = cur;
648
969
  if (ctx.trivia) {
649
- const scan = scanTrivia(input, cur, ctx);
650
- scan.commit();
651
- pos = scan.end;
970
+ if (needsDeferredTriviaCommit(ctx)) {
971
+ const scan = scanTrivia(input, cur, ctx);
972
+ scan.commit();
973
+ pos = scan.end;
974
+ } else {
975
+ pos = advanceTrivia(input, cur, ctx);
976
+ }
652
977
  }
653
978
  if (pos >= input.length) {
654
- if (raw) raw.length = mark;
979
+ rollbackTrivia(ctx, mark);
655
980
  return "stop";
656
981
  }
657
- const result = parser2.parse(input, pos, ctx);
982
+ const result = combinator.parse(input, pos, ctx);
658
983
  if (!result.ok) {
659
- if (raw) raw.length = mark;
984
+ rollbackTrivia(ctx, mark);
660
985
  return { fail: result };
661
986
  }
662
987
  if (result.span.end === pos) {
663
- if (raw) raw.length = mark;
988
+ rollbackTrivia(ctx, mark);
664
989
  return "stop";
665
990
  }
666
991
  return { value: result.value, end: result.span.end };
667
992
  }
668
- function many(parser2) {
993
+ function many(combinator) {
669
994
  const meta = {
670
- firstSet: parser2._meta.firstSet,
671
- canMatchNewline: parser2._meta.canMatchNewline,
995
+ firstSet: combinator._meta.firstSet,
996
+ canMatchNewline: combinator._meta.canMatchNewline,
672
997
  isTrivia: false
673
998
  };
674
999
  return {
675
1000
  _tag: "many",
676
1001
  _meta: meta,
677
- _def: { tag: "many", parser: parser2, min: 0 },
1002
+ _def: { tag: "many", parser: combinator, min: 0 },
678
1003
  parse(input, pos, ctx) {
679
1004
  const values = [];
680
1005
  let cur = pos;
681
1006
  while (cur < input.length) {
682
- const item = repItem(parser2, input, cur, ctx);
1007
+ const item = repItem(combinator, input, cur, ctx);
683
1008
  if (item === "stop" || "fail" in item) break;
684
1009
  values.push(item.value);
685
1010
  cur = item.end;
@@ -688,23 +1013,23 @@ function many(parser2) {
688
1013
  }
689
1014
  };
690
1015
  }
691
- function oneOrMore(parser2) {
1016
+ function oneOrMore(combinator) {
692
1017
  const meta = {
693
- firstSet: parser2._meta.firstSet,
694
- canMatchNewline: parser2._meta.canMatchNewline,
1018
+ firstSet: combinator._meta.firstSet,
1019
+ canMatchNewline: combinator._meta.canMatchNewline,
695
1020
  isTrivia: false
696
1021
  };
697
1022
  return {
698
1023
  _tag: "oneOrMore",
699
1024
  _meta: meta,
700
- _def: { tag: "oneOrMore", parser: parser2, min: 1 },
1025
+ _def: { tag: "oneOrMore", parser: combinator, min: 1 },
701
1026
  parse(input, pos, ctx) {
702
- const first = parser2.parse(input, pos, ctx);
1027
+ const first = combinator.parse(input, pos, ctx);
703
1028
  if (!first.ok) return first;
704
1029
  const values = [first.value];
705
1030
  let cur = first.span.end;
706
1031
  while (cur < input.length) {
707
- const item = repItem(parser2, input, cur, ctx);
1032
+ const item = repItem(combinator, input, cur, ctx);
708
1033
  if (item === "stop" || "fail" in item) break;
709
1034
  values.push(item.value);
710
1035
  cur = item.end;
@@ -713,45 +1038,71 @@ function oneOrMore(parser2) {
713
1038
  }
714
1039
  };
715
1040
  }
716
- function optional(parser2) {
1041
+ function optional(combinator) {
717
1042
  const meta = {
718
- firstSet: parser2._meta.firstSet,
719
- canMatchNewline: parser2._meta.canMatchNewline,
1043
+ firstSet: combinator._meta.firstSet,
1044
+ canMatchNewline: combinator._meta.canMatchNewline,
720
1045
  isTrivia: false
721
1046
  };
722
1047
  return {
723
1048
  _tag: "optional",
724
1049
  _meta: meta,
725
- _def: { tag: "optional", parser: parser2 },
1050
+ _def: { tag: "optional", parser: combinator },
726
1051
  parse(input, pos, ctx) {
727
- const result = parser2.parse(input, pos, ctx);
1052
+ const result = combinator.parse(input, pos, ctx);
728
1053
  if (result.ok) return result;
729
1054
  return { ok: true, value: null, span: { start: pos, end: pos } };
730
1055
  }
731
1056
  };
732
1057
  }
733
- function sepBy(parser2, separator) {
1058
+ function sepBy(combinator, separator) {
734
1059
  const meta = {
735
- firstSet: parser2._meta.firstSet,
736
- canMatchNewline: parser2._meta.canMatchNewline || separator._meta.canMatchNewline,
1060
+ firstSet: combinator._meta.firstSet,
1061
+ canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
737
1062
  isTrivia: false
738
1063
  };
739
1064
  return {
740
1065
  _tag: "sepBy",
741
1066
  _meta: meta,
742
- _def: { tag: "sepBy", parser: parser2, separator },
1067
+ _def: { tag: "sepBy", parser: combinator, separator },
743
1068
  parse(input, pos, ctx) {
744
- const first = parser2.parse(input, pos, ctx);
1069
+ const first = combinator.parse(input, pos, ctx);
745
1070
  if (!first.ok) return { ok: true, value: [], span: { start: pos, end: pos } };
746
1071
  const values = [first.value];
747
1072
  let cur = first.span.end;
748
1073
  while (cur < input.length) {
749
- const sepPos = ctx.trivia ? consumeTrivia(input, cur, ctx) : cur;
1074
+ let mark = saveTriviaMark(ctx);
1075
+ let sepPos = cur;
1076
+ if (ctx.trivia) {
1077
+ if (needsDeferredTriviaCommit(ctx)) {
1078
+ const scan = scanTrivia(input, cur, ctx);
1079
+ scan.commit();
1080
+ sepPos = scan.end;
1081
+ } else {
1082
+ sepPos = advanceTrivia(input, cur, ctx);
1083
+ }
1084
+ }
750
1085
  const sep = separator.parse(input, sepPos, ctx);
751
- if (!sep.ok) break;
752
- const nextPos = ctx.trivia ? consumeTrivia(input, sep.span.end, ctx) : sep.span.end;
753
- const next = parser2.parse(input, nextPos, ctx);
754
- if (!next.ok) break;
1086
+ if (!sep.ok) {
1087
+ rollbackTrivia(ctx, mark);
1088
+ break;
1089
+ }
1090
+ mark = saveTriviaMark(ctx);
1091
+ let nextPos = sep.span.end;
1092
+ if (ctx.trivia) {
1093
+ if (needsDeferredTriviaCommit(ctx)) {
1094
+ const scan = scanTrivia(input, sep.span.end, ctx);
1095
+ scan.commit();
1096
+ nextPos = scan.end;
1097
+ } else {
1098
+ nextPos = advanceTrivia(input, sep.span.end, ctx);
1099
+ }
1100
+ }
1101
+ const next = combinator.parse(input, nextPos, ctx);
1102
+ if (!next.ok) {
1103
+ rollbackTrivia(ctx, mark);
1104
+ break;
1105
+ }
755
1106
  values.push(next.value);
756
1107
  cur = next.span.end;
757
1108
  }
@@ -761,7 +1112,7 @@ function sepBy(parser2, separator) {
761
1112
  }
762
1113
 
763
1114
  // src/combinators/not.ts
764
- function not(parser2) {
1115
+ function not(combinator) {
765
1116
  const meta = {
766
1117
  firstSet: any(),
767
1118
  // we don't know what NOT matches
@@ -771,11 +1122,11 @@ function not(parser2) {
771
1122
  return {
772
1123
  _tag: "not",
773
1124
  _meta: meta,
774
- _def: { tag: "not", parser: parser2 },
1125
+ _def: { tag: "not", parser: combinator },
775
1126
  parse(input, pos, ctx) {
776
- const result = parser2.parse(input, pos, ctx);
1127
+ const result = combinator.parse(input, pos, ctx);
777
1128
  if (result.ok) {
778
- return { ok: false, expected: [`not(${parser2._tag})`], span: { start: pos, end: pos } };
1129
+ return { ok: false, expected: [`not(${combinator._tag})`], span: { start: pos, end: pos } };
779
1130
  }
780
1131
  return { ok: true, value: null, span: { start: pos, end: pos } };
781
1132
  }
@@ -783,37 +1134,27 @@ function not(parser2) {
783
1134
  }
784
1135
 
785
1136
  // src/combinators/node.ts
786
- function node(type, parser2, build) {
1137
+ function node(type, combinator, build) {
787
1138
  const meta = {
788
- firstSet: parser2._meta.firstSet,
789
- canMatchNewline: parser2._meta.canMatchNewline,
1139
+ firstSet: combinator._meta.firstSet,
1140
+ canMatchNewline: combinator._meta.canMatchNewline,
790
1141
  isTrivia: false
791
1142
  };
792
1143
  return {
793
1144
  _tag: "node",
794
1145
  _meta: meta,
795
- _def: { tag: "node", type, parser: parser2, build },
1146
+ _def: { tag: "node", type, parser: combinator, build },
796
1147
  parse(input, pos, ctx) {
797
- const children = [];
798
- const rawChildren = [];
799
- const innerCtx = {
800
- ...ctx,
801
- // A node() always records the trivia between its terms — the library owns
802
- // capture so grammar authors don't reconstruct it. (Matches the compiler.)
803
- captureTrivia: true,
804
- _cstChildren: children,
805
- _cstLeaves: children,
806
- _cstRawChildren: rawChildren
807
- };
808
- const r = parser2.parse(input, pos, innerCtx);
1148
+ const saved = beginCstNodeCapture(ctx);
1149
+ const r = combinator.parse(input, pos, ctx);
1150
+ const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
809
1151
  if (!r.ok) return r;
810
- const built = build(children, rawChildren, r.span);
1152
+ const state = ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
1153
+ const built = build(children, rawChildren, r.span, triviaLog, state);
811
1154
  const isNodeLike = typeof built === "object" && built !== null && built._tag === "node";
812
- if (ctx._cstChildren) ctx._cstChildren.push(built);
813
- if (ctx._cstRawChildren) {
814
- ctx._cstRawChildren.push(
815
- isNodeLike ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span }
816
- );
1155
+ const rawEntry = isNodeLike ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
1156
+ if (saved.buf !== void 0 || saved.ch !== void 0) {
1157
+ pushCstChild(ctx, built, rawEntry);
817
1158
  }
818
1159
  return { ok: true, value: built, span: r.span };
819
1160
  }
@@ -821,24 +1162,37 @@ function node(type, parser2, build) {
821
1162
  }
822
1163
 
823
1164
  // src/combinators/map.ts
824
- function transform(parser2, fn) {
1165
+ function transform(combinator, fn) {
825
1166
  return {
826
1167
  _tag: "transform",
827
- _meta: parser2._meta,
828
- _def: { tag: "transform", parser: parser2, fn },
1168
+ _meta: combinator._meta,
1169
+ _def: { tag: "transform", parser: combinator, fn },
829
1170
  parse(input, pos, ctx) {
830
- const result = parser2.parse(input, pos, ctx);
1171
+ const result = combinator.parse(input, pos, ctx);
831
1172
  if (!result.ok) return result;
832
1173
  return { ...result, value: fn(result.value, result.span) };
833
1174
  }
834
1175
  };
835
1176
  }
836
- function trivia(parser2) {
1177
+ function trivia(combinator) {
1178
+ const kindLabels = analyzeLabeledTrivia(combinator)?.labels;
1179
+ return {
1180
+ _tag: combinator._tag,
1181
+ _meta: {
1182
+ ...combinator._meta,
1183
+ isTrivia: true,
1184
+ ...kindLabels ? { triviaKindLabels: kindLabels } : {}
1185
+ },
1186
+ _def: { tag: "trivia", parser: combinator },
1187
+ parse: combinator.parse.bind(combinator)
1188
+ };
1189
+ }
1190
+ function label(name, combinator) {
837
1191
  return {
838
- _tag: parser2._tag,
839
- _meta: { ...parser2._meta, isTrivia: true },
840
- _def: { tag: "trivia", parser: parser2 },
841
- parse: parser2.parse.bind(parser2)
1192
+ _tag: combinator._tag,
1193
+ _meta: combinator._meta,
1194
+ _def: { tag: "label", label: name, parser: combinator },
1195
+ parse: combinator.parse.bind(combinator)
842
1196
  };
843
1197
  }
844
1198
 
@@ -889,7 +1243,10 @@ function parser(opts, root) {
889
1243
  const ctx = {
890
1244
  ..._ctx,
891
1245
  trackLines,
892
- ...opts.trivia !== void 0 ? { trivia: opts.trivia } : {},
1246
+ ...opts.trivia !== void 0 ? {
1247
+ trivia: opts.trivia,
1248
+ ...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
1249
+ } : {},
893
1250
  ...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {}
894
1251
  };
895
1252
  const result = root.parse(input, pos ?? 0, ctx);
@@ -902,6 +1259,320 @@ function parser(opts, root) {
902
1259
  };
903
1260
  }
904
1261
 
1262
+ // src/compiler/trivia-fast-path.ts
1263
+ var BLOCK_COMMENT = String.raw`\/\*(?:[^*]|\*(?!\/))*\*\/`;
1264
+ var WS_CLASS_SOURCES = /* @__PURE__ */ new Set([
1265
+ String.raw`[ \t\n\r\f]+`,
1266
+ String.raw`[ \t\n]+`,
1267
+ String.raw`[ \t]+`,
1268
+ String.raw`[\t\n\f\r ]+`
1269
+ ]);
1270
+ function unwrapTrivia2(p) {
1271
+ let cur = p;
1272
+ while (cur._def.tag === "trivia") cur = cur._def.parser;
1273
+ return cur;
1274
+ }
1275
+ function oneOrMoreInner(p) {
1276
+ const d = p._def;
1277
+ if (d.tag === "oneOrMore") return d.parser;
1278
+ if (d.tag === "many" && d.min >= 1) return d.parser;
1279
+ return null;
1280
+ }
1281
+ function choiceArms(p) {
1282
+ if (p._def.tag === "choice") return p._def.parsers;
1283
+ return null;
1284
+ }
1285
+ function isWsClassSource(source) {
1286
+ return WS_CLASS_SOURCES.has(source);
1287
+ }
1288
+ function isBlockCommentSource(source) {
1289
+ return source === BLOCK_COMMENT;
1290
+ }
1291
+ function analyzeTriviaFastPath(trivia2) {
1292
+ const core = unwrapTrivia2(trivia2);
1293
+ const direct = getCoreRegexDef(core)?.source;
1294
+ if (direct) {
1295
+ if (isWsClassSource(direct)) return "wsOnly";
1296
+ return null;
1297
+ }
1298
+ const inner = oneOrMoreInner(core);
1299
+ if (!inner) return null;
1300
+ const innerSrc = getCoreRegexDef(inner)?.source;
1301
+ if (innerSrc && isWsClassSource(innerSrc)) return "wsOnly";
1302
+ const arms = choiceArms(inner);
1303
+ if (!arms || arms.length !== 2) return null;
1304
+ let hasWs = false;
1305
+ let hasComment = false;
1306
+ for (const arm of arms) {
1307
+ const src = getCoreRegexDef(arm)?.source;
1308
+ if (!src) return null;
1309
+ if (isWsClassSource(src)) hasWs = true;
1310
+ else if (isBlockCommentSource(src)) hasComment = true;
1311
+ else return null;
1312
+ }
1313
+ if (hasWs && hasComment) return "wsComments";
1314
+ return null;
1315
+ }
1316
+ var CAP_RECORD = [
1317
+ ` if (_cap && _e > _pos) {`,
1318
+ ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
1319
+ ` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
1320
+ ` }`
1321
+ ].join("\n");
1322
+ var WS_ONLY_LOOP = [
1323
+ ` while (_e < input.length) {`,
1324
+ ` const c = input.charCodeAt(_e)`,
1325
+ ` if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) { _e++; continue }`,
1326
+ ` break`,
1327
+ ` }`
1328
+ ].join("\n");
1329
+ var WS_COMMENTS_LOOP = [
1330
+ ` while (_e < input.length) {`,
1331
+ ` const c = input.charCodeAt(_e)`,
1332
+ ` if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) { _e++; continue }`,
1333
+ ` if (c === 47 && input.charCodeAt(_e + 1) === 42) {`,
1334
+ ` let j = _e + 2`,
1335
+ ` while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++`,
1336
+ ` _e = j + 2 <= input.length ? j + 2 : input.length`,
1337
+ ` continue`,
1338
+ ` }`,
1339
+ ` break`,
1340
+ ` }`
1341
+ ].join("\n");
1342
+ var CAP_CHUNK = (wsKind, commentKind) => [
1343
+ ` if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {`,
1344
+ ` const _cs = _e`,
1345
+ ` _e++`,
1346
+ ` while (_e < input.length) {`,
1347
+ ` const c2 = input.charCodeAt(_e)`,
1348
+ ` if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) _e++`,
1349
+ ` else break`,
1350
+ ` }`,
1351
+ ` if (_cap) {`,
1352
+ ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_cs, _e, ${wsKind})`,
1353
+ ` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_cs, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${wsKind})`,
1354
+ ` }`,
1355
+ ` continue`,
1356
+ ` }`,
1357
+ ` if (c === 47 && input.charCodeAt(_e + 1) === 42) {`,
1358
+ ` const _cs = _e`,
1359
+ ` let j = _e + 2`,
1360
+ ` while (j + 1 < input.length && !(input.charCodeAt(j) === 42 && input.charCodeAt(j + 1) === 47)) j++`,
1361
+ ` _e = j + 2 <= input.length ? j + 2 : input.length`,
1362
+ ` if (_cap) {`,
1363
+ ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_cs, _e, ${commentKind})`,
1364
+ ` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_cs, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${commentKind})`,
1365
+ ` }`,
1366
+ ` continue`,
1367
+ ` }`
1368
+ ].join("\n");
1369
+ var WS_COMMENTS_LOOP_LABELED = (wsKind, commentKind) => [
1370
+ ` while (_e < input.length) {`,
1371
+ ` const c = input.charCodeAt(_e)`,
1372
+ CAP_CHUNK(wsKind, commentKind),
1373
+ ` break`,
1374
+ ` }`
1375
+ ].join("\n");
1376
+ function buildFastTriviaFnDecl(fnName, kind, kindIndices) {
1377
+ const loop = kind === "wsComments" && kindIndices ? WS_COMMENTS_LOOP_LABELED(kindIndices.ws, kindIndices.comment) : kind === "wsComments" ? WS_COMMENTS_LOOP : WS_ONLY_LOOP;
1378
+ const cap = kindIndices ? "" : CAP_RECORD;
1379
+ const lines = [
1380
+ `function ${fnName}(input, _pos, _ctx, _cap) {`,
1381
+ ` let _e = _pos`,
1382
+ loop
1383
+ ];
1384
+ if (cap) lines.push(cap);
1385
+ lines.push(` return _e`, `}`);
1386
+ return lines.join("\n");
1387
+ }
1388
+ function regexArmIndex(spec, isComment) {
1389
+ for (const arm of spec.arms) {
1390
+ const src = getCoreRegexDef(arm.parser)?.source;
1391
+ if (!src) return null;
1392
+ const comment = src.includes("\\*") || src.startsWith("\\/\\/");
1393
+ if (comment === isComment) return arm.kindIndex;
1394
+ }
1395
+ return null;
1396
+ }
1397
+ function buildLabeledRegexTriviaFnDecl(fnName, spec, reNames) {
1398
+ const tryArms = spec.arms.map((arm, i) => {
1399
+ const re = reNames[i];
1400
+ const k = arm.kindIndex;
1401
+ return [
1402
+ ` ${re}.lastIndex = _e`,
1403
+ ` const _m${i} = ${re}.exec(input)`,
1404
+ ` if (_m${i} && _m${i}.index === _e) {`,
1405
+ ` const _ce = _e + _m${i}[0].length`,
1406
+ ` if (_cap) {`,
1407
+ ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
1408
+ ` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
1409
+ ` }`,
1410
+ ` _e = _ce`,
1411
+ ` _matched = true`,
1412
+ ` continue`,
1413
+ ` }`
1414
+ ].join("\n");
1415
+ }).join("\n");
1416
+ return [
1417
+ `function ${fnName}(input, _pos, _ctx, _cap) {`,
1418
+ ` let _e = _pos`,
1419
+ ` while (_e < input.length) {`,
1420
+ ` let _matched = false`,
1421
+ tryArms,
1422
+ ` if (!_matched) break`,
1423
+ ` }`,
1424
+ ` return _e`,
1425
+ `}`
1426
+ ].join("\n");
1427
+ }
1428
+ function labeledTriviaKindIndices(trivia2) {
1429
+ const spec = analyzeLabeledTrivia(trivia2);
1430
+ if (!spec || spec.arms.length !== 2) return null;
1431
+ const ws = regexArmIndex(spec, false);
1432
+ const comment = regexArmIndex(spec, true);
1433
+ if (ws === null || comment === null) return null;
1434
+ return { ws, comment };
1435
+ }
1436
+ function labeledTriviaRegexArms(trivia2) {
1437
+ const spec = analyzeLabeledTrivia(trivia2);
1438
+ if (!spec) return null;
1439
+ for (const arm of spec.arms) {
1440
+ if (!getCoreRegexDef(arm.parser)) return null;
1441
+ }
1442
+ return spec;
1443
+ }
1444
+ function buildLabeledRuntimeTriviaFnDecl(fnName, spec, rpStartIndex) {
1445
+ const tryArms = spec.arms.map((arm, i) => {
1446
+ const k = arm.kindIndex;
1447
+ const ri = rpStartIndex + i;
1448
+ return [
1449
+ ` const _r${i} = _rp[${ri}].parse(input, _e, _ctx)`,
1450
+ ` if (_r${i}.ok && _r${i}.span.end > _e) {`,
1451
+ ` const _ce = _r${i}.span.end`,
1452
+ ` if (_cap) {`,
1453
+ ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_e, _ce, ${k})`,
1454
+ ` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_e, _ce, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0, ${k})`,
1455
+ ` }`,
1456
+ ` _e = _ce`,
1457
+ ` _matched = true`,
1458
+ ` continue`,
1459
+ ` }`
1460
+ ].join("\n");
1461
+ }).join("\n");
1462
+ return [
1463
+ `function ${fnName}(input, _pos, _ctx, _cap) {`,
1464
+ ` let _e = _pos`,
1465
+ ` while (_e < input.length) {`,
1466
+ ` let _matched = false`,
1467
+ tryArms,
1468
+ ` if (!_matched) break`,
1469
+ ` }`,
1470
+ ` return _e`,
1471
+ `}`
1472
+ ].join("\n");
1473
+ }
1474
+
1475
+ // src/compiler/inline-build.ts
1476
+ var MK_BUILD_RE = /^\(\s*(?:\w+\s*,\s*){3}\w+\s*\)\s*=>\s*mk\s*\(\s*(['"])([^'"]+)\1\s*,\s*\w+\s*,\s*\w+\s*,\s*\w+\s*,\s*\w+\s*\)\s*$/;
1477
+ function escapeRegExp(s) {
1478
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1479
+ }
1480
+ function looseMkBuildRe(type) {
1481
+ return new RegExp(
1482
+ String.raw`^\(\s*(?:\w+\s*,\s*){3}\w+\s*\)\s*=>\s*.+\(\s*(['"])${escapeRegExp(type)}\1\s*,\s*\w+\s*,\s*\w+\s*,\s*\w+\s*,\s*\w+\s*\)\s*$`
1483
+ );
1484
+ }
1485
+ function analyzeMkInlineBuild(def) {
1486
+ const src = (def.buildSrc ?? def.build.toString()).trim();
1487
+ const strict = src.match(MK_BUILD_RE);
1488
+ if (strict) {
1489
+ const mkType = strict[2];
1490
+ return mkType === def.type ? def.type : null;
1491
+ }
1492
+ if (looseMkBuildRe(def.type).test(src)) return def.type;
1493
+ return null;
1494
+ }
1495
+ function emitInlineMkNodeExpr(type, chV, rawV, pos, endVar, tlV) {
1496
+ return `{ _tag: 'node', type: ${JSON.stringify(type)}, span: { start: ${pos}, end: ${endVar} }, children: ${chV}, rawCount: ${rawV}.length, localTriviaLen: ${tlV}.length }`;
1497
+ }
1498
+
1499
+ // src/compiler/inline-callback.ts
1500
+ var INLINE_BUILTINS = /* @__PURE__ */ new Set([
1501
+ "parseInt",
1502
+ "parseFloat",
1503
+ "String",
1504
+ "Number",
1505
+ "Boolean",
1506
+ "Object",
1507
+ "Array",
1508
+ "Math",
1509
+ "JSON",
1510
+ "undefined",
1511
+ "null",
1512
+ "true",
1513
+ "false",
1514
+ "NaN",
1515
+ "Infinity"
1516
+ ]);
1517
+ function escapeRegExp2(s) {
1518
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1519
+ }
1520
+ function transformFnSource(fn, fnSrc) {
1521
+ if (fnSrc) return fnSrc.trim();
1522
+ const s = fn.toString().trim();
1523
+ if (s.includes("[native code]")) return null;
1524
+ return s;
1525
+ }
1526
+ function replaceParam(body, param, valueVar) {
1527
+ return body.replace(new RegExp(`\\b${escapeRegExp2(param)}\\b`, "g"), valueVar);
1528
+ }
1529
+ function stripForIdCheck(body) {
1530
+ return body.replace(/'[^'\\]*(?:\\.[^'\\]*)*'|"[^"\\]*(?:\\.[^"\\]*)*"/g, '""').replace(/\bas\s+const\b/g, "").replace(/\b[A-Za-z_$][\w$]*\s*:/g, ":");
1531
+ }
1532
+ function hasFreeIdentifiers(body, allowed) {
1533
+ const stripped = stripForIdCheck(body);
1534
+ const ids = stripped.match(/\b[A-Za-z_$][\w$]*\b/g) ?? [];
1535
+ for (const id of ids) {
1536
+ if (INLINE_BUILTINS.has(id)) continue;
1537
+ if (allowed.has(id)) continue;
1538
+ return true;
1539
+ }
1540
+ return false;
1541
+ }
1542
+ function tryInlineUnaryTransform(src, valueVar) {
1543
+ const allowed = /* @__PURE__ */ new Set([valueVar]);
1544
+ const nullary = src.match(/^\(\s*\)\s*=>\s*(.+)$/);
1545
+ if (nullary) {
1546
+ const body2 = nullary[1].trim();
1547
+ return hasFreeIdentifiers(body2, allowed) ? null : body2;
1548
+ }
1549
+ const m = src.match(/^(\w+)\s*=>\s*(.+)$/);
1550
+ if (!m) return null;
1551
+ const body = replaceParam(m[2].trim(), m[1], valueVar);
1552
+ return hasFreeIdentifiers(body, allowed) ? null : body;
1553
+ }
1554
+ function parseArrayDestructure(pattern, arity) {
1555
+ const slots = [];
1556
+ for (const part of pattern.split(",")) {
1557
+ const name = part.trim();
1558
+ slots.push(name === "" || name === "_" ? null : name);
1559
+ }
1560
+ while (slots.length < arity) slots.push(null);
1561
+ return slots.slice(0, arity);
1562
+ }
1563
+ function tryInlineDestructureTransform(src, valueVars) {
1564
+ const m = src.match(/^\(\s*\[([^\]]*)\]\s*\)\s*=>\s*(.+)$/s);
1565
+ if (!m) return null;
1566
+ const slots = parseArrayDestructure(m[1], valueVars.length);
1567
+ let body = m[2].trim();
1568
+ const allowed = new Set(valueVars);
1569
+ for (let i = 0; i < slots.length; i++) {
1570
+ const name = slots[i];
1571
+ if (name) body = replaceParam(body, name, valueVars[i]);
1572
+ }
1573
+ return hasFreeIdentifiers(body, allowed) ? null : body;
1574
+ }
1575
+
905
1576
  // src/compiler/codegen.ts
906
1577
  function v(ctx, prefix = "_v") {
907
1578
  return `${prefix}${ctx.vars++}`;
@@ -909,12 +1580,42 @@ function v(ctx, prefix = "_v") {
909
1580
  function ind(ctx) {
910
1581
  return " ".repeat(ctx.indent);
911
1582
  }
1583
+ var NAMED_FN_FAIL = "_pfFail";
1584
+ var NAMED_FN_END = "_pfEnd";
1585
+ function namedFnPrelude() {
1586
+ return [`const ${NAMED_FN_FAIL} = {}`, `let ${NAMED_FN_END}`];
1587
+ }
1588
+ function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
1589
+ ctx.namedFnDecls.push([
1590
+ `function ${fnName}(input, _pos, _ctx) {`,
1591
+ ` let _pfok = false, _pfv, _pfe = _pos`,
1592
+ ` _pfail: {`,
1593
+ ...bodyStmts,
1594
+ ` _pfv = ${valueVar}; _pfe = ${endVar}; _pfok = true`,
1595
+ ` }`,
1596
+ ` if (!_pfok) return ${NAMED_FN_FAIL}`,
1597
+ ` ${NAMED_FN_END} = _pfe`,
1598
+ ` return _pfv`,
1599
+ `}`
1600
+ ].join("\n"));
1601
+ }
1602
+ function emitNamedFnCall(ctx, fnName, pos, failExpected) {
1603
+ const vv = v(ctx, "_pfv");
1604
+ const ev = v(ctx, "_pfe");
1605
+ return {
1606
+ stmts: [
1607
+ `${ind(ctx)}const ${vv} = ${fnName}(input, ${pos}, _ctx)`,
1608
+ `${ind(ctx)}if (${vv} === ${NAMED_FN_FAIL}) ${failStmt({ ...ctx, indent: 0 }, failExpected, pos).trim()}`,
1609
+ `${ind(ctx)}const ${ev} = ${NAMED_FN_END}`
1610
+ ],
1611
+ valueVar: vv,
1612
+ endVar: ev
1613
+ };
1614
+ }
912
1615
  function emitLeafCapture(ctx, valExpr, startExpr, endExpr) {
913
1616
  if (!ctx.capturing) return [];
1617
+ if (ctx.capAsTrivia) return [];
914
1618
  const i = ind(ctx);
915
- if (ctx.capAsTrivia) {
916
- return [`${i}if (_ctx._cstRawChildren) _ctx._cstRawChildren.push({ _tag: 'trivia', value: ${valExpr}, span: { start: ${startExpr}, end: ${endExpr} } })`];
917
- }
918
1619
  const lf = v(ctx, "_lf");
919
1620
  return [
920
1621
  `${i}if (_ctx._cstLeaves) {`,
@@ -924,35 +1625,84 @@ function emitLeafCapture(ctx, valExpr, startExpr, endExpr) {
924
1625
  `${i}}`
925
1626
  ];
926
1627
  }
927
- function ensureTriviaCaptureFn(ctx) {
1628
+ function ensureRegexDecl(ctx, optimizedSource, flags) {
1629
+ const f = "y" + flags.replace(/[gy]/g, "");
1630
+ const key = `${optimizedSource}/${f}`;
1631
+ let rName = ctx.regexMap.get(key);
1632
+ if (rName === void 0) {
1633
+ rName = `_re${ctx.regexDecls.length}`;
1634
+ ctx.regexDecls.push(`const ${rName} = /${optimizedSource}/${f}`);
1635
+ ctx.regexMap.set(key, rName);
1636
+ }
1637
+ return rName;
1638
+ }
1639
+ function ensureTriviaFn(ctx) {
928
1640
  const trivia2 = ctx.activeTrivia;
929
- const existing = ctx.triviaCaptureNames.get(trivia2);
1641
+ const existing = ctx.triviaFnNames.get(trivia2);
930
1642
  if (existing) return existing;
931
- const fnName = `_tc${ctx.triviaCaptureNames.size}`;
1643
+ const fnName = `_tf${ctx.triviaFnNames.size}`;
1644
+ ctx.triviaFnNames.set(trivia2, fnName);
932
1645
  ctx.triviaCaptureNames.set(trivia2, fnName);
933
- const saved = { indent: ctx.indent, failLabel: ctx.failLabel, asTrivia: ctx.capAsTrivia, trivia: ctx.activeTrivia };
1646
+ const fastKind = analyzeTriviaFastPath(trivia2);
1647
+ const kindIndices = labeledTriviaKindIndices(trivia2);
1648
+ if (fastKind) {
1649
+ ctx.namedFnDecls.push(buildFastTriviaFnDecl(fnName, fastKind, kindIndices ?? void 0));
1650
+ return fnName;
1651
+ }
1652
+ const labeledSpec = analyzeLabeledTrivia(trivia2);
1653
+ if (labeledSpec) {
1654
+ const regexSpec = labeledTriviaRegexArms(trivia2);
1655
+ if (regexSpec) {
1656
+ const reNames = [];
1657
+ for (const arm of regexSpec.arms) {
1658
+ const def = arm.parser._def;
1659
+ if (def.tag !== "regex") break;
1660
+ reNames.push(ensureRegexDecl(ctx, def.optimizedSource, def.flags));
1661
+ }
1662
+ if (reNames.length === regexSpec.arms.length) {
1663
+ ctx.namedFnDecls.push(buildLabeledRegexTriviaFnDecl(fnName, regexSpec, reNames));
1664
+ return fnName;
1665
+ }
1666
+ }
1667
+ const rpStart = ctx.runtimeParsers.length;
1668
+ for (const arm of labeledSpec.arms) {
1669
+ ctx.runtimeParsers.push(arm.parser);
1670
+ }
1671
+ ctx.namedFnDecls.push(buildLabeledRuntimeTriviaFnDecl(fnName, labeledSpec, rpStart));
1672
+ return fnName;
1673
+ }
1674
+ const savedIndent = ctx.indent;
1675
+ const savedFailLabel = ctx.failLabel;
1676
+ const savedTrivia = ctx.activeTrivia;
1677
+ const savedCapAsTrivia = ctx.capAsTrivia;
934
1678
  ctx.indent = 2;
935
- ctx.failLabel = "_cap";
1679
+ ctx.failLabel = "_triv";
936
1680
  ctx.capAsTrivia = true;
937
- delete ctx.activeTrivia;
1681
+ ctx.activeTrivia = void 0;
938
1682
  const r = emit(trivia2, ctx, "_pos");
939
- ctx.indent = saved.indent;
940
- ctx.failLabel = saved.failLabel;
941
- ctx.capAsTrivia = saved.asTrivia;
942
- if (saved.trivia) ctx.activeTrivia = saved.trivia;
1683
+ ctx.indent = savedIndent;
1684
+ ctx.failLabel = savedFailLabel;
1685
+ ctx.capAsTrivia = savedCapAsTrivia;
1686
+ ctx.activeTrivia = savedTrivia;
943
1687
  ctx.namedFnDecls.push([
944
- `function ${fnName}(input, _pos, _ctx) {`,
1688
+ `function ${fnName}(input, _pos, _ctx, _cap) {`,
945
1689
  ` let _e = _pos`,
946
- ` _cap: {`,
1690
+ ` _triv: {`,
947
1691
  ...r.stmts,
948
1692
  ` _e = ${r.endVar}`,
949
1693
  ` }`,
950
- ` if (_ctx._triviaLog !== undefined && _e > _pos) _ctx._triviaLog.push(_pos, _e)`,
1694
+ ` if (_cap && _e > _pos) {`,
1695
+ ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
1696
+ ` if (_ctx._cstTriviaLog !== undefined) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
1697
+ ` }`,
951
1698
  ` return _e`,
952
1699
  `}`
953
1700
  ].join("\n"));
954
1701
  return fnName;
955
1702
  }
1703
+ function ensureTriviaCaptureFn(ctx) {
1704
+ return ensureTriviaFn(ctx);
1705
+ }
956
1706
  function failStmt(ctx, expected, posExpr) {
957
1707
  if (ctx.failLabel) return `${ind(ctx)}break ${ctx.failLabel}`;
958
1708
  return `${ind(ctx)}return { ok: false, expected: [${expected}], span: { start: ${posExpr}, end: ${posExpr} } }`;
@@ -968,14 +1718,6 @@ function firstSetCond(codeVar, fs) {
968
1718
  (r) => r.lo === r.hi ? `${codeVar} === ${r.lo}` : `(${codeVar} >= ${r.lo} && ${codeVar} <= ${r.hi})`
969
1719
  ).join(" || ");
970
1720
  }
971
- function asIIFE(stmts, valueVar, endVar, startPos, indent) {
972
- return [
973
- `(() => {`,
974
- ...stmts,
975
- `${indent} return { ok: true, value: ${valueVar}, span: { start: ${startPos}, end: ${endVar} } }`,
976
- `${indent}})()`
977
- ].join("\n");
978
- }
979
1721
  function emitFallible(inner, ctx, pos) {
980
1722
  const lbl = v(ctx, "_lbl");
981
1723
  const okV = `${lbl}ok`;
@@ -1041,6 +1783,33 @@ function emitLit(def, ctx, pos) {
1041
1783
  stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
1042
1784
  return { stmts, valueVar: vv, endVar };
1043
1785
  }
1786
+ function escapeKeywordRe(s) {
1787
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1788
+ }
1789
+ function emitKeywords(def, ctx, pos) {
1790
+ const alt = def.words.map(escapeKeywordRe).join("|");
1791
+ const boundary = def.boundary ? `(?![${def.boundary}])` : "";
1792
+ const flags = def.caseInsensitive ? "iuy" : "uy";
1793
+ const source = `(?:${alt})${boundary}`;
1794
+ const key = `${source}/${flags}`;
1795
+ let rName = ctx.regexMap.get(key);
1796
+ if (rName === void 0) {
1797
+ rName = `_re${ctx.regexDecls.length}`;
1798
+ ctx.regexDecls.push(`const ${rName} = /${source}/${flags}`);
1799
+ ctx.regexMap.set(key, rName);
1800
+ }
1801
+ const mv = v(ctx, "_m");
1802
+ const vv = v(ctx);
1803
+ const stmts = [
1804
+ `${ind(ctx)}${rName}.lastIndex = ${pos}`,
1805
+ `${ind(ctx)}const ${mv} = ${rName}.exec(input)`,
1806
+ `${ind(ctx)}if (${mv} === null) ${failStmt({ ...ctx, indent: 0 }, '"keyword"', pos).trim()}`,
1807
+ `${ind(ctx)}const ${vv} = ${mv}[0]`
1808
+ ];
1809
+ const endVar = `${pos} + ${vv}.length`;
1810
+ stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
1811
+ return { stmts, valueVar: vv, endVar };
1812
+ }
1044
1813
  function emitRegex(def, ctx, pos) {
1045
1814
  const flags = "y" + def.flags.replace(/[gy]/g, "");
1046
1815
  const key = `${def.optimizedSource}/${flags}`;
@@ -1063,31 +1832,7 @@ function emitRegex(def, ctx, pos) {
1063
1832
  stmts.push(...emitLeafCapture(ctx, vv, pos, endVar));
1064
1833
  return { stmts, valueVar: vv, endVar };
1065
1834
  }
1066
- function ensureTriviaFn(ctx) {
1067
- const trivia2 = ctx.activeTrivia;
1068
- if (!ctx.namedParsers.has(trivia2)) {
1069
- const fnName = `_pf${ctx.namedParsers.size}`;
1070
- ctx.namedParsers.set(trivia2, fnName);
1071
- const savedIndent = ctx.indent;
1072
- const savedFailLabel = ctx.failLabel;
1073
- const savedTrivia = ctx.activeTrivia;
1074
- ctx.indent = 1;
1075
- ctx.failLabel = void 0;
1076
- delete ctx.activeTrivia;
1077
- const r = emit(trivia2, ctx, "_pos");
1078
- ctx.indent = savedIndent;
1079
- ctx.failLabel = savedFailLabel;
1080
- if (savedTrivia) ctx.activeTrivia = savedTrivia;
1081
- ctx.namedFnDecls.push([
1082
- `function ${fnName}(input, _pos, _ctx) {`,
1083
- ...r.stmts,
1084
- ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
1085
- `}`
1086
- ].join("\n"));
1087
- }
1088
- return ctx.namedParsers.get(trivia2);
1089
- }
1090
- function emitSeq(def, ctx, pos) {
1835
+ function emitSeqValues(def, ctx, pos) {
1091
1836
  const startV = v(ctx, "_start");
1092
1837
  const curV = v(ctx, "_cur");
1093
1838
  const stmts = [
@@ -1099,23 +1844,41 @@ function emitSeq(def, ctx, pos) {
1099
1844
  if (i > 0 && ctx.activeTrivia) {
1100
1845
  if (ctx.capturing) {
1101
1846
  const capFn = ensureTriviaCaptureFn(ctx);
1102
- stmts.push(`${ind(ctx)}${curV} = ${capFn}(input, ${curV}, _ctx)`);
1103
- } else {
1104
- const trivFn = ensureTriviaFn(ctx);
1105
- const tmp = v(ctx, "_trv");
1847
+ const markV = v(ctx, "_mk");
1848
+ const markTl = v(ctx, "_mktl");
1849
+ const markLog = v(ctx, "_mklg");
1850
+ const scanEndV = v(ctx, "_sne");
1106
1851
  stmts.push(
1107
- `${ind(ctx)}const ${tmp} = ${trivFn}(input, ${curV}, _ctx)`,
1108
- `${ind(ctx)}if (${tmp}.ok) ${curV} = ${tmp}.span.end`
1852
+ `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
1853
+ `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
1854
+ `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
1855
+ `${ind(ctx)}const ${scanEndV} = ${capFn}(input, ${curV}, _ctx, 1)`
1109
1856
  );
1857
+ const r2 = emit(def.parsers[i], ctx, scanEndV);
1858
+ stmts.push(...r2.stmts);
1859
+ const endAfterV = v(ctx, "_sea");
1860
+ stmts.push(
1861
+ `${ind(ctx)}const ${endAfterV} = ${r2.endVar}`,
1862
+ `${ind(ctx)}if (${endAfterV} > ${scanEndV}) { ${curV} = ${endAfterV} } else { if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${markLog}; }`
1863
+ );
1864
+ valueVars.push(r2.valueVar);
1865
+ continue;
1866
+ } else {
1867
+ const trivFn = ensureTriviaFn(ctx);
1868
+ stmts.push(`${ind(ctx)}${curV} = ${trivFn}(input, ${curV}, _ctx)`);
1110
1869
  }
1111
1870
  }
1112
1871
  const r = emit(def.parsers[i], ctx, curV);
1113
1872
  stmts.push(...r.stmts, `${ind(ctx)}${curV} = ${r.endVar}`);
1114
1873
  valueVars.push(r.valueVar);
1115
1874
  }
1875
+ return { stmts, valueVar: valueVars[valueVars.length - 1] ?? "null", endVar: curV, valueVars };
1876
+ }
1877
+ function emitSeq(def, ctx, pos) {
1878
+ const { stmts, endVar, valueVars } = emitSeqValues(def, ctx, pos);
1116
1879
  const arrV = v(ctx, "_arr");
1117
1880
  stmts.push(`${ind(ctx)}const ${arrV} = [${valueVars.join(", ")}]`);
1118
- return { stmts, valueVar: arrV, endVar: curV };
1881
+ return { stmts, valueVar: arrV, endVar };
1119
1882
  }
1120
1883
  function emitChoice(def, ctx, pos) {
1121
1884
  const allExpected = JSON.stringify(
@@ -1166,29 +1929,39 @@ function emitGreedyClassify(def, superIndex, allExpected, ctx, pos) {
1166
1929
  const matchV = v(ctx, "_gm");
1167
1930
  const wordV = v(ctx, "_gw");
1168
1931
  const endV = v(ctx, "_ge");
1932
+ const valV = v(ctx, "_gcv");
1169
1933
  const stmts = [
1170
1934
  `${ind(ctx)}${reVar}.lastIndex = ${pos}`,
1171
1935
  `${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
1172
1936
  `${ind(ctx)}if (${matchV} === null) ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`,
1173
1937
  `${ind(ctx)}const ${wordV} = ${matchV}[0]`,
1174
- `${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`
1938
+ `${ind(ctx)}const ${endV} = ${pos} + ${wordV}.length`,
1939
+ `${ind(ctx)}let ${valV}`
1175
1940
  ];
1941
+ let first = true;
1176
1942
  for (let i = 0; i < def.parsers.length; i++) {
1177
1943
  if (i === superIndex) continue;
1178
1944
  const p = def.parsers[i];
1179
1945
  const litVal = getCoreLiteralValue(p);
1180
1946
  if (litVal === null) continue;
1181
- stmts.push(`${ind(ctx)}if (${wordV} === ${JSON.stringify(litVal)}) {`);
1947
+ const kw = first ? "if" : "else if";
1948
+ first = false;
1949
+ stmts.push(`${ind(ctx)}${kw} (${wordV} === ${JSON.stringify(litVal)}) {`);
1182
1950
  ctx.indent++;
1183
1951
  const tR = emitTransformChain(p, JSON.stringify(litVal), endV, pos, ctx);
1184
- stmts.push(...tR.stmts);
1185
- stmts.push(`${ind(ctx)}return { ok: true, value: ${tR.valueVar}, span: { start: ${pos}, end: ${endV} } }`);
1952
+ stmts.push(...emitLeafCapture(ctx, JSON.stringify(litVal), pos, endV));
1953
+ stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}`);
1186
1954
  ctx.indent--;
1187
1955
  stmts.push(`${ind(ctx)}}`);
1188
1956
  }
1189
1957
  const rR = emitTransformChain(superParser, wordV, endV, pos, ctx);
1190
- stmts.push(...rR.stmts);
1191
- return { stmts, valueVar: rR.valueVar, endVar: endV };
1958
+ const regexKw = first ? "if" : "else";
1959
+ stmts.push(`${ind(ctx)}${regexKw} {`);
1960
+ ctx.indent++;
1961
+ stmts.push(...emitLeafCapture(ctx, wordV, pos, endV), ...rR.stmts, `${ind(ctx)}${valV} = ${rR.valueVar}`);
1962
+ ctx.indent--;
1963
+ stmts.push(`${ind(ctx)}}`);
1964
+ return { stmts, valueVar: valV, endVar: endV };
1192
1965
  }
1193
1966
  function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
1194
1967
  const valV = v(ctx, "_llv");
@@ -1202,10 +1975,15 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
1202
1975
  const litCond = emitLiteralCondition(litVal, pos);
1203
1976
  const kw = first ? "if" : "else if";
1204
1977
  first = false;
1978
+ const litEnd = `${pos} + ${litLen}`;
1205
1979
  stmts.push(`${ind(ctx)}${kw} (${litCond}) {`);
1206
1980
  ctx.indent++;
1207
- const tR = emitTransformChain(p, JSON.stringify(litVal), `${pos} + ${litLen}`, pos, ctx);
1208
- stmts.push(...tR.stmts, `${ind(ctx)}${valV} = ${tR.valueVar}; ${endV} = ${pos} + ${litLen}`);
1981
+ const tR = emitTransformChain(p, JSON.stringify(litVal), litEnd, pos, ctx);
1982
+ stmts.push(
1983
+ ...emitLeafCapture(ctx, JSON.stringify(litVal), pos, litEnd),
1984
+ ...tR.stmts,
1985
+ `${ind(ctx)}${valV} = ${tR.valueVar}; ${endV} = ${litEnd}`
1986
+ );
1209
1987
  ctx.indent--;
1210
1988
  stmts.push(`${ind(ctx)}}`);
1211
1989
  }
@@ -1213,67 +1991,66 @@ function emitLiteralsLongestFirst(def, sortedIndices, allExpected, ctx, pos) {
1213
1991
  return { stmts, valueVar: valV, endVar: endV };
1214
1992
  }
1215
1993
  function emitFirstMatch(def, allExpected, ctx, pos) {
1216
- const resV = v(ctx, "_cr");
1217
- const stmts = [`${ind(ctx)}let ${resV}`];
1994
+ const resValV = v(ctx, "_crv");
1995
+ const resEndV = v(ctx, "_cre");
1996
+ const resOkV = v(ctx, "_crok");
1997
+ const ind0 = ind(ctx);
1998
+ const stmts = [
1999
+ `${ind0}let ${resValV}, ${resEndV} = ${pos}, ${resOkV} = false`
2000
+ ];
1218
2001
  for (let i = 0; i < def.parsers.length; i++) {
1219
2002
  const p = def.parsers[i];
1220
2003
  const gate = def.gates[i];
1221
2004
  const autoNot = def.autoNot[i];
1222
- const savedIndent = ctx.indent;
1223
- const savedFailLabel = ctx.failLabel;
1224
- ctx.indent = 0;
1225
- ctx.failLabel = void 0;
1226
- const r = emit(p, ctx, pos);
1227
- ctx.indent = savedIndent;
1228
- ctx.failLabel = savedFailLabel;
1229
- const iife = asIIFE(r.stmts, r.valueVar, r.endVar, pos, ind(ctx));
1230
2005
  let gateCond = null;
1231
2006
  if (gate) {
1232
2007
  const gateIdx = ctx.mapFns.length;
1233
2008
  ctx.mapFns.push(gate);
1234
2009
  gateCond = `_mf[${gateIdx}](_ctx.state)`;
1235
2010
  }
1236
- const skipCond = gateCond ? `!${resV}?.ok && ${gateCond}` : `!${resV}?.ok`;
2011
+ const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
1237
2012
  const markLeaves = ctx.capturing ? v(ctx, "_cml") : null;
1238
2013
  const markRaw = ctx.capturing ? v(ctx, "_cmr") : null;
1239
- const rollback = markLeaves ? `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${markLeaves}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markRaw}` : "";
1240
- const markStmts = markLeaves ? [
1241
- `${ind(ctx)} const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
1242
- `${ind(ctx)} const ${markRaw} = _ctx._cstRawChildren?.length ?? 0`
1243
- ] : [];
1244
- const rollbackStmt = rollback ? `${ind(ctx)} if (!${resV}?.ok) { ${rollback} }` : "";
2014
+ const markTl = ctx.capturing ? v(ctx, "_cmtl") : null;
2015
+ const markLog = ctx.capturing ? v(ctx, "_cmlg") : null;
2016
+ const rollback = markLeaves ? `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${markLeaves}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markRaw}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${markLog}` : "";
2017
+ stmts.push(`${ind0}if (${skipCond}) {`);
2018
+ ctx.indent++;
2019
+ const ind1 = ind(ctx);
2020
+ if (markLeaves) {
2021
+ stmts.push(
2022
+ `${ind1}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
2023
+ `${ind1}const ${markRaw} = _ctx._cstRawChildren?.length ?? 0`,
2024
+ `${ind1}const ${markTl} = _ctx._cstTriviaLog?.length ?? 0`,
2025
+ `${ind1}const ${markLog} = _ctx._triviaLog?.length ?? 0`
2026
+ );
2027
+ }
2028
+ const { stmts: armStmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos);
2029
+ stmts.push(...armStmts);
2030
+ ctx.indent--;
1245
2031
  if (autoNot && autoNot.length > 0) {
1246
- const tmp = v(ctx, "_ct");
1247
2032
  const anCode = v(ctx, "_anc");
1248
2033
  const rejectCond = autoNot.map(
1249
- (check) => check.kind === "firstSet" ? firstSetCond(anCode, check.set) : `input.startsWith(${JSON.stringify(check.value)}, ${tmp}.span.end)`
2034
+ (check) => check.kind === "firstSet" ? firstSetCond(anCode, check.set) : `input.startsWith(${JSON.stringify(check.value)}, ${endVar})`
1250
2035
  ).join(" || ");
1251
- stmts.push(`${ind(ctx)}if (${skipCond}) {`);
1252
- stmts.push(...markStmts);
1253
2036
  stmts.push(
1254
- `${ind(ctx)} const ${tmp} = (() => { try { return ${iife} } catch {} })()`,
1255
- `${ind(ctx)} if (${tmp}?.ok) { const ${anCode} = ${tmp}.span.end < input.length ? input.charCodeAt(${tmp}.span.end) : -1; if (!(${rejectCond})) ${resV} = ${tmp} }`
2037
+ `${ind0} if (${okVar}) { const ${anCode} = ${endVar} < input.length ? input.charCodeAt(${endVar}) : -1; if (!(${rejectCond})) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true } }`
1256
2038
  );
1257
- if (rollbackStmt) stmts.push(rollbackStmt);
1258
- stmts.push(`${ind(ctx)}}`);
2039
+ if (rollback) stmts.push(`${ind0} if (!${resOkV}) { ${rollback} }`);
1259
2040
  } else {
1260
- stmts.push(`${ind(ctx)}if (${skipCond}) {`);
1261
- stmts.push(...markStmts);
1262
- stmts.push(`${ind(ctx)} try { ${resV} = ${iife} } catch {}`);
1263
- if (rollbackStmt) stmts.push(rollbackStmt);
1264
- stmts.push(`${ind(ctx)}}`);
2041
+ stmts.push(`${ind0} if (${okVar}) { ${resValV} = ${valVar}; ${resEndV} = ${endVar}; ${resOkV} = true }`);
2042
+ if (rollback) stmts.push(`${ind0} else { ${rollback} }`);
1265
2043
  }
2044
+ stmts.push(`${ind0}}`);
1266
2045
  }
1267
- stmts.push(`${ind(ctx)}if (!${resV}?.ok) ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`);
1268
- return { stmts, valueVar: `${resV}.value`, endVar: `${resV}.span.end` };
2046
+ stmts.push(`${ind0}if (!${resOkV}) ${failArr({ ...ctx, indent: 0 }, allExpected, pos)}`);
2047
+ return { stmts, valueVar: resValV, endVar: resEndV };
1269
2048
  }
1270
2049
  function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
1271
- if (!ctx.capturing) {
1272
- if (strategy.tag === "greedyClassify")
1273
- return emitGreedyClassify(def, strategy.superIndex, allExpected, ctx, pos);
1274
- if (strategy.tag === "literalsLongestFirst")
1275
- return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
1276
- }
2050
+ if (strategy.tag === "greedyClassify")
2051
+ return emitGreedyClassify(def, strategy.superIndex, allExpected, ctx, pos);
2052
+ if (strategy.tag === "literalsLongestFirst")
2053
+ return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
1277
2054
  return emitFirstMatch(def, allExpected, ctx, pos);
1278
2055
  }
1279
2056
  function emitTransformChain(p, baseValue, endV, startPos, ctx) {
@@ -1326,27 +2103,28 @@ function emitMany(def, ctx, pos) {
1326
2103
  if (ctx.capturing) {
1327
2104
  const capFn = ensureTriviaCaptureFn(ctx);
1328
2105
  const markV = v(ctx, "_mk");
2106
+ const markTl = v(ctx, "_mktl");
2107
+ const markLog = v(ctx, "_mklg");
1329
2108
  const npV = v(ctx, "_np");
1330
2109
  stmts.push(
1331
2110
  `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
1332
- `${ind(ctx)}const ${npV} = ${capFn}(input, ${curV}, _ctx)`
2111
+ `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
2112
+ `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
2113
+ `${ind(ctx)}const ${npV} = ${capFn}(input, ${curV}, _ctx, 1)`
1333
2114
  );
1334
2115
  itemPos = npV;
1335
- rollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; `;
2116
+ rollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${markLog}; `;
1336
2117
  } else {
1337
2118
  const trivFn = ensureTriviaFn(ctx);
1338
2119
  const npV = v(ctx, "_np");
1339
- stmts.push(
1340
- `${ind(ctx)}let ${npV} = ${curV}`,
1341
- `${ind(ctx)}{ const _trv = ${trivFn}(input, ${npV}, _ctx); if (_trv.ok) ${npV} = _trv.span.end }`
1342
- );
2120
+ stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${curV}, _ctx)`);
1343
2121
  itemPos = npV;
1344
2122
  }
1345
2123
  }
1346
2124
  const { stmts: iterStmts, okVar: iterOk, valVar: iterVal, endVar: iterEnd } = emitFallible(def.parser, ctx, itemPos);
1347
2125
  stmts.push(
1348
2126
  ...iterStmts,
1349
- `${ind(ctx)}if (!${iterOk} || ${iterEnd} === ${curV}) { ${rollback}break }`,
2127
+ `${ind(ctx)}if (!${iterOk} || ${iterEnd} <= ${itemPos}) { ${rollback}break }`,
1350
2128
  `${ind(ctx)}${arrV}.push(${iterVal})`,
1351
2129
  `${ind(ctx)}${curV} = ${iterEnd}`
1352
2130
  );
@@ -1383,55 +2161,70 @@ function emitSepBy(_p, def, ctx, pos) {
1383
2161
  `${ind(ctx)}while (${curV} < input.length) {`
1384
2162
  );
1385
2163
  ctx.indent++;
1386
- let rollback = "";
1387
- if (ctx.capturing) {
1388
- const markV = v(ctx, "_mk");
1389
- stmts.push(`${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`);
1390
- rollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; `;
1391
- }
1392
2164
  let sepAtPos = curV;
1393
2165
  if (ctx.activeTrivia) {
1394
2166
  if (ctx.capturing) {
1395
2167
  const capFn = ensureTriviaCaptureFn(ctx);
1396
- const spV = v(ctx, "_sp");
1397
- stmts.push(`${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx)`);
1398
- sepAtPos = spV;
1399
- } else {
1400
- const trivFn = ensureTriviaFn(ctx);
2168
+ const markV = v(ctx, "_mk");
2169
+ const markTl = v(ctx, "_mktl");
2170
+ const markLog = v(ctx, "_mklg");
1401
2171
  const spV = v(ctx, "_sp");
1402
2172
  stmts.push(
1403
- `${ind(ctx)}let ${spV} = ${curV}`,
1404
- `${ind(ctx)}{ const _trv = ${trivFn}(input, ${spV}, _ctx); if (_trv.ok) ${spV} = _trv.span.end }`
2173
+ `${ind(ctx)}const ${markV} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
2174
+ `${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
2175
+ `${ind(ctx)}const ${markLog} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
2176
+ `${ind(ctx)}const ${spV} = ${capFn}(input, ${curV}, _ctx, 1)`
1405
2177
  );
1406
2178
  sepAtPos = spV;
1407
- }
1408
- }
1409
- const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = emitFallible(def.separator, ctx, sepAtPos);
1410
- stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${rollback}break }`);
1411
- let nextAtPos = sepEnd;
1412
- if (ctx.activeTrivia) {
1413
- if (ctx.capturing) {
1414
- const capFn = ensureTriviaCaptureFn(ctx);
2179
+ const sepRollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${markV}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${markTl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${markLog}; `;
2180
+ const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = emitFallible(def.separator, ctx, sepAtPos);
2181
+ stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) { ${sepRollback}break }`);
2182
+ const mark2V = v(ctx, "_mk2");
2183
+ const mark2Tl = v(ctx, "_mktl2");
2184
+ const mark2Log = v(ctx, "_mklg2");
1415
2185
  const npV = v(ctx, "_np");
1416
- stmts.push(`${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx)`);
1417
- nextAtPos = npV;
2186
+ stmts.push(
2187
+ `${ind(ctx)}const ${mark2V} = _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0`,
2188
+ `${ind(ctx)}const ${mark2Tl} = _ctx._cstTriviaLog ? _ctx._cstTriviaLog.length : 0`,
2189
+ `${ind(ctx)}const ${mark2Log} = _ctx._triviaLog ? _ctx._triviaLog.length : 0`,
2190
+ `${ind(ctx)}const ${npV} = ${capFn}(input, ${sepEnd}, _ctx, 1)`
2191
+ );
2192
+ const nextRollback = `if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${mark2V}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${mark2Tl}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${mark2Log}; `;
2193
+ const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV);
2194
+ stmts.push(
2195
+ ...nextStmts,
2196
+ `${ind(ctx)}if (!${nextOk}) { ${nextRollback}break }`,
2197
+ `${ind(ctx)}${arrV}.push(${nextVal})`,
2198
+ `${ind(ctx)}${curV} = ${nextEnd}`
2199
+ );
1418
2200
  } else {
1419
2201
  const trivFn = ensureTriviaFn(ctx);
2202
+ const spV = v(ctx, "_sp");
2203
+ stmts.push(`${ind(ctx)}const ${spV} = ${trivFn}(input, ${curV}, _ctx)`);
2204
+ sepAtPos = spV;
2205
+ const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = emitFallible(def.separator, ctx, sepAtPos);
2206
+ stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) break`);
1420
2207
  const npV = v(ctx, "_np");
2208
+ stmts.push(`${ind(ctx)}const ${npV} = ${trivFn}(input, ${sepEnd}, _ctx)`);
2209
+ const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, npV);
1421
2210
  stmts.push(
1422
- `${ind(ctx)}let ${npV} = ${sepEnd}`,
1423
- `${ind(ctx)}{ const _trv = ${trivFn}(input, ${npV}, _ctx); if (_trv.ok) ${npV} = _trv.span.end }`
2211
+ ...nextStmts,
2212
+ `${ind(ctx)}if (!${nextOk}) break`,
2213
+ `${ind(ctx)}${arrV}.push(${nextVal})`,
2214
+ `${ind(ctx)}${curV} = ${nextEnd}`
1424
2215
  );
1425
- nextAtPos = npV;
1426
2216
  }
2217
+ } else {
2218
+ const { stmts: sepStmts, okVar: sepOk, endVar: sepEnd } = emitFallible(def.separator, ctx, sepAtPos);
2219
+ stmts.push(...sepStmts, `${ind(ctx)}if (!${sepOk}) break`);
2220
+ const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, sepEnd);
2221
+ stmts.push(
2222
+ ...nextStmts,
2223
+ `${ind(ctx)}if (!${nextOk}) break`,
2224
+ `${ind(ctx)}${arrV}.push(${nextVal})`,
2225
+ `${ind(ctx)}${curV} = ${nextEnd}`
2226
+ );
1427
2227
  }
1428
- const { stmts: nextStmts, okVar: nextOk, valVar: nextVal, endVar: nextEnd } = emitFallible(def.parser, ctx, nextAtPos);
1429
- stmts.push(
1430
- ...nextStmts,
1431
- `${ind(ctx)}if (!${nextOk}) { ${rollback}break }`,
1432
- `${ind(ctx)}${arrV}.push(${nextVal})`,
1433
- `${ind(ctx)}${curV} = ${nextEnd}`
1434
- );
1435
2228
  ctx.indent--;
1436
2229
  stmts.push(`${ind(ctx)}}`);
1437
2230
  ctx.indent--;
@@ -1493,27 +2286,33 @@ function emitNot(def, ctx, pos) {
1493
2286
  };
1494
2287
  }
1495
2288
  function emitNode(def, ctx, pos) {
1496
- const fnIdx = ctx.buildFns.length;
1497
- ctx.buildFns.push(def.build);
1498
- ctx.buildSrcs.push(def.buildSrc ?? null);
2289
+ const mkType = analyzeMkInlineBuild(def);
2290
+ let buildIdx = null;
2291
+ if (!mkType) {
2292
+ buildIdx = ctx.buildFns.length;
2293
+ ctx.buildFns.push(def.build);
2294
+ ctx.buildSrcs.push(def.buildSrc ?? null);
2295
+ }
1499
2296
  const i = ind(ctx);
1500
2297
  const chV = v(ctx, "_ch");
1501
2298
  const rawV = v(ctx, "_raw");
1502
- const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st");
2299
+ const tlV = v(ctx, "_tl");
2300
+ const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
1503
2301
  const stmts = [
1504
- `${i}const ${chV} = [], ${rawV} = []`,
1505
- `${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia`,
1506
- `${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true`
2302
+ `${i}const ${chV} = [], ${rawV} = [], ${tlV} = []`,
2303
+ `${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog`,
2304
+ `${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${tlV}`
1507
2305
  ];
1508
2306
  const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
1509
2307
  stmts.push(...innerStmts);
1510
- stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}`);
2308
+ stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}`);
1511
2309
  stmts.push(`${i}if (!${okVar}) ${failStmt({ ...ctx, indent: 0 }, '"node"', pos).trim()}`);
2310
+ const stV = v(ctx, "_nst");
2311
+ stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
1512
2312
  const ndV = v(ctx, "_nd");
2313
+ const ndExpr = mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `_build[${buildIdx}](${chV}, ${rawV}, { start: ${pos}, end: ${endVar} }, ${tlV}, ${stV})`;
1513
2314
  stmts.push(
1514
- `${i}const ${ndV} = _build[${fnIdx}](${chV}, ${rawV}, { start: ${pos}, end: ${endVar} })`,
1515
- // Record into the caller's collectors (the node in children; the node, or a
1516
- // spanned leaf if build collapsed to a non-node value, in rawChildren).
2315
+ `${i}const ${ndV} = ${ndExpr}`,
1517
2316
  `${i}if (${sc}) ${sc}.push(${ndV})`,
1518
2317
  `${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && ${ndV}._tag === 'node') ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : '', span: { start: ${pos}, end: ${endVar} } })`
1519
2318
  );
@@ -1547,31 +2346,14 @@ function emitLazy(p, def, ctx, pos) {
1547
2346
  const savedIndent = ctx.indent;
1548
2347
  const savedFailLabel = ctx.failLabel;
1549
2348
  ctx.indent = 1;
1550
- ctx.failLabel = void 0;
2349
+ ctx.failLabel = "_pfail";
1551
2350
  const r = emit(resolved, ctx, "_pos");
1552
2351
  ctx.indent = savedIndent;
1553
2352
  ctx.failLabel = savedFailLabel;
1554
- ctx.namedFnDecls.push([
1555
- `function ${fnName2}(input, _pos, _ctx) {`,
1556
- ...r.stmts,
1557
- ` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
1558
- `}`
1559
- ].join("\n"));
2353
+ pushNamedFnDecl(ctx, fnName2, r.stmts, r.valueVar, r.endVar);
1560
2354
  }
1561
2355
  const fnName = ctx.namedParsers.get(p);
1562
- const rv = v(ctx, "_pfr");
1563
- const vv = v(ctx, "_pfv");
1564
- const ev = v(ctx, "_pfe");
1565
- return {
1566
- stmts: [
1567
- `${ind(ctx)}const ${rv} = ${fnName}(input, ${pos}, _ctx)`,
1568
- `${ind(ctx)}if (!${rv}.ok) ${failStmt({ ...ctx, indent: 0 }, '"parser"', pos).trim()}`,
1569
- `${ind(ctx)}const ${vv} = ${rv}.value`,
1570
- `${ind(ctx)}const ${ev} = ${rv}.span.end`
1571
- ],
1572
- valueVar: vv,
1573
- endVar: ev
1574
- };
2356
+ return emitNamedFnCall(ctx, fnName, pos, '"parser"');
1575
2357
  }
1576
2358
  function emitRecover(def, ctx, pos) {
1577
2359
  const { stmts: innerStmts, okVar, valVar, endVar } = emitFallible(def.parser, ctx, pos);
@@ -1607,6 +2389,8 @@ function emit(p, ctx, pos) {
1607
2389
  return emitLit(def, ctx, pos);
1608
2390
  case "regex":
1609
2391
  return emitRegex(def, ctx, pos);
2392
+ case "keywords":
2393
+ return emitKeywords(def, ctx, pos);
1610
2394
  case "sequence":
1611
2395
  return emitSeq(def, ctx, pos);
1612
2396
  case "choice":
@@ -1619,7 +2403,31 @@ function emit(p, ctx, pos) {
1619
2403
  case "sepBy":
1620
2404
  return emitSepBy(p, def, ctx, pos);
1621
2405
  case "transform": {
2406
+ const fnSrc = transformFnSource(def.fn, def.fnSrc);
2407
+ if (fnSrc && def.parser._def.tag === "sequence") {
2408
+ const seqR = emitSeqValues(def.parser._def, ctx, pos);
2409
+ const inlined = tryInlineDestructureTransform(fnSrc, seqR.valueVars);
2410
+ if (inlined) {
2411
+ const mv2 = v(ctx, "_mapped");
2412
+ return {
2413
+ stmts: [...seqR.stmts, `${ind(ctx)}const ${mv2} = ${inlined}`],
2414
+ valueVar: mv2,
2415
+ endVar: seqR.endVar
2416
+ };
2417
+ }
2418
+ }
1622
2419
  const inner = emit(def.parser, ctx, pos);
2420
+ if (fnSrc) {
2421
+ const unary = tryInlineUnaryTransform(fnSrc, inner.valueVar);
2422
+ if (unary) {
2423
+ const mv2 = v(ctx, "_mapped");
2424
+ return {
2425
+ stmts: [...inner.stmts, `${ind(ctx)}const ${mv2} = ${unary}`],
2426
+ valueVar: mv2,
2427
+ endVar: inner.endVar
2428
+ };
2429
+ }
2430
+ }
1623
2431
  const fnIdx = ctx.mapFns.length;
1624
2432
  ctx.mapFns.push(def.fn);
1625
2433
  ctx.mapFnSrcs.push(def.fnSrc ?? null);
@@ -1655,12 +2463,20 @@ function emit(p, ctx, pos) {
1655
2463
  return emitLazy(p, def, ctx, pos);
1656
2464
  case "trivia":
1657
2465
  return emit(def.parser, ctx, pos);
2466
+ case "label":
2467
+ return emit(def.parser, ctx, pos);
1658
2468
  case "grammar": {
1659
2469
  const savedTrivia = ctx.activeTrivia;
1660
- if (def.triviaParser) ctx.activeTrivia = def.triviaParser;
2470
+ const savedKindLabels = ctx.triviaKindLabels;
2471
+ if (def.triviaParser) {
2472
+ ctx.activeTrivia = def.triviaParser;
2473
+ if (def.triviaParser._meta.triviaKindLabels) {
2474
+ ctx.triviaKindLabels = def.triviaParser._meta.triviaKindLabels;
2475
+ }
2476
+ }
1661
2477
  const r = emit(def.parser, ctx, pos);
1662
- if (savedTrivia === void 0) delete ctx.activeTrivia;
1663
- else ctx.activeTrivia = savedTrivia;
2478
+ ctx.activeTrivia = savedTrivia;
2479
+ ctx.triviaKindLabels = savedKindLabels;
1664
2480
  return r;
1665
2481
  }
1666
2482
  case "not":
@@ -1695,27 +2511,22 @@ function emit(p, ctx, pos) {
1695
2511
  const savedIndent = ctx.indent;
1696
2512
  const savedFailLabel = ctx.failLabel;
1697
2513
  ctx.indent = 1;
1698
- ctx.failLabel = void 0;
2514
+ ctx.failLabel = "_pfail";
1699
2515
  const innerR = emit(innerParser, ctx, "_pos");
1700
2516
  ctx.indent = savedIndent;
1701
2517
  ctx.failLabel = savedFailLabel;
1702
- ctx.namedFnDecls.push([
1703
- `function ${fnName}(input, _pos, _ctx) {`,
1704
- ...innerR.stmts,
1705
- ` return { ok: true, value: ${innerR.valueVar}, span: { start: _pos, end: ${innerR.endVar} } }`,
1706
- `}`
1707
- ].join("\n"));
2518
+ pushNamedFnDecl(ctx, fnName, innerR.stmts, innerR.valueVar, innerR.endVar);
1708
2519
  }
1709
2520
  const fn = ctx.namedParsers.get(innerParser);
1710
2521
  const rv = v(ctx, "_wcr");
1711
- const vv = v(ctx);
2522
+ const vv = v(ctx, "_wcv");
1712
2523
  const ev = v(ctx, "_wce");
1713
2524
  return {
1714
2525
  stmts: [
1715
- `${ind(ctx)}const ${rv} = ${fn}(input, ${pos}, { ..._ctx, state: _mf[${evIdx}]() })`,
1716
- `${ind(ctx)}if (!${rv}.ok) ${failStmt({ ...ctx, indent: 0 }, '"withCtx"', pos).trim()}`,
1717
- `${ind(ctx)}const ${vv} = ${rv}.value`,
1718
- `${ind(ctx)}const ${ev} = ${rv}.span.end`
2526
+ `${ind(ctx)}const ${rv} = { ..._ctx, state: _mf[${evIdx}]() }`,
2527
+ `${ind(ctx)}const ${vv} = ${fn}(input, ${pos}, ${rv})`,
2528
+ `${ind(ctx)}if (${vv} === ${NAMED_FN_FAIL}) ${failStmt({ ...ctx, indent: 0 }, '"withCtx"', pos).trim()}`,
2529
+ `${ind(ctx)}const ${ev} = ${NAMED_FN_END}`
1719
2530
  ],
1720
2531
  valueVar: vv,
1721
2532
  endVar: ev
@@ -1741,6 +2552,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
1741
2552
  }
1742
2553
  case "grammar":
1743
2554
  case "trivia":
2555
+ case "label":
1744
2556
  case "optional":
1745
2557
  case "many":
1746
2558
  case "oneOrMore":
@@ -1764,7 +2576,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
1764
2576
  return false;
1765
2577
  }
1766
2578
  }
1767
- function compile(parser2, mapFnSources) {
2579
+ function compile(combinator, mapFnSources) {
1768
2580
  const ctx = {
1769
2581
  vars: 0,
1770
2582
  indent: 1,
@@ -1778,15 +2590,18 @@ function compile(parser2, mapFnSources) {
1778
2590
  needsCollator: false,
1779
2591
  namedParsers: /* @__PURE__ */ new Map(),
1780
2592
  triviaCaptureNames: /* @__PURE__ */ new Map(),
2593
+ triviaFnNames: /* @__PURE__ */ new Map(),
1781
2594
  namedFnDecls: [],
1782
- capturing: hasNodeDef(parser2)
2595
+ capturing: hasNodeDef(combinator)
1783
2596
  };
1784
- const r = emit(parser2, ctx, "_pos");
2597
+ const r = emit(combinator, ctx, "_pos");
1785
2598
  const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
1786
2599
  ` : "";
2600
+ const namedPrelude = ctx.namedFnDecls.length > 0 ? [...namedFnPrelude(), ""] : [];
1787
2601
  const source = [
1788
2602
  ...ctx.regexDecls,
1789
2603
  "",
2604
+ ...namedPrelude,
1790
2605
  ...ctx.namedFnDecls,
1791
2606
  `${collatorDecl}function _parse(input, _pos, _rp, _mf, _build, _ctx) {`,
1792
2607
  ` let pos = _pos`,
@@ -1797,12 +2612,16 @@ function compile(parser2, mapFnSources) {
1797
2612
  const fn = new Function("input", "_pos", "_rp", "_mf", "_build", "_ctx", [
1798
2613
  ...ctx.regexDecls,
1799
2614
  collatorDecl,
2615
+ ...namedPrelude,
1800
2616
  ...ctx.namedFnDecls,
1801
2617
  `let pos = _pos`,
1802
2618
  ...r.stmts,
1803
2619
  `return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`
1804
2620
  ].join("\n"));
1805
- const defaultCtx = { trackLines: false };
2621
+ const defaultCtx = {
2622
+ trackLines: false,
2623
+ ...ctx.triviaKindLabels ? { triviaKindLabels: ctx.triviaKindLabels } : {}
2624
+ };
1806
2625
  const derivedSrcs = ctx.mapFnSrcs.length === ctx.mapFns.length && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : void 0;
1807
2626
  const effectiveSources = mapFnSources ?? derivedSrcs;
1808
2627
  const buildCovered = ctx.buildFns.length === 0 || ctx.buildSrcs.every((s) => s !== null);
@@ -1816,6 +2635,9 @@ function compile(parser2, mapFnSources) {
1816
2635
  parse(input, pos = 0) {
1817
2636
  return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, defaultCtx);
1818
2637
  },
2638
+ parseWithContext(input, parseCtx, pos = 0) {
2639
+ return fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, parseCtx);
2640
+ },
1819
2641
  parseWithErrors(input, pos = 0) {
1820
2642
  const errors = [];
1821
2643
  const result = fn(input, pos, ctx.runtimeParsers, ctx.mapFns, ctx.buildFns, { ...defaultCtx, _errors: errors });
@@ -1838,12 +2660,14 @@ function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources)
1838
2660
  const buildDecl = buildSources?.length ? ` const _build = [${buildSources.join(", ")}]` : "";
1839
2661
  const needsWrapper = ctx.regexDecls.length > 0 || !!collatorDecl || ctx.namedFnDecls.length > 0 || !!mfDecl || !!buildDecl;
1840
2662
  if (!needsWrapper) return innerFn;
2663
+ const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
1841
2664
  return [
1842
2665
  `/* @__PURE__ */ (() => {`,
1843
2666
  ...ctx.regexDecls.map((d) => ` ${d}`),
1844
2667
  collatorDecl ? ` ${collatorDecl.trim()}` : "",
1845
2668
  mfDecl,
1846
2669
  buildDecl,
2670
+ ...namedPrelude.map((l) => ` ${l}`),
1847
2671
  ...ctx.namedFnDecls.flatMap((f) => f.split("\n").map((l) => ` ${l}`)),
1848
2672
  ` return ${innerFn}`,
1849
2673
  `})()`
@@ -1865,10 +2689,9 @@ function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
1865
2689
  let cur = pos;
1866
2690
  const probeCtx = { trackLines: ctx.trackLines, state: ctx.state };
1867
2691
  const emit2 = (end) => {
1868
- if (end > pos && (ctx._cstLeaves || ctx._cstRawChildren)) {
2692
+ if (end > pos && cstCaptureActive(ctx)) {
1869
2693
  const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
1870
- if (ctx._cstLeaves) ctx._cstLeaves.push(leaf);
1871
- if (ctx._cstRawChildren) ctx._cstRawChildren.push(leaf);
2694
+ pushCstLeaf(ctx, leaf);
1872
2695
  }
1873
2696
  };
1874
2697
  while (cur < input.length) {
@@ -1911,16 +2734,22 @@ function balanced(open, close, options = {}) {
1911
2734
  }
1912
2735
 
1913
2736
  // src/plugin/evaluator.ts
2737
+ function isWordFactory(v2) {
2738
+ return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
2739
+ }
1914
2740
  var SUPPORTED = {
1915
2741
  literal: (...a) => literal(a[0], a[1]),
1916
2742
  regex: (...a) => regex(a[0], a[1]),
2743
+ keywords: (...a) => keywords(a[0], a[1]),
2744
+ word: (...a) => word(a[0], a[1]),
1917
2745
  sequence: (...a) => sequence(...a),
1918
2746
  choice: (...a) => choice(...a),
1919
2747
  many: (...a) => many(a[0]),
1920
2748
  oneOrMore: (...a) => oneOrMore(a[0]),
1921
2749
  optional: (...a) => optional(a[0]),
1922
2750
  sepBy: (...a) => sepBy(a[0], a[1]),
1923
- trivia: (...a) => trivia(a[0])
2751
+ trivia: (...a) => trivia(a[0]),
2752
+ label: (...a) => label(a[0], a[1])
1924
2753
  };
1925
2754
  function isScopeEntry(v2) {
1926
2755
  return !!v2 && typeof v2 === "object" && "combi" in v2 && "mfSrcs" in v2;
@@ -1942,6 +2771,33 @@ function exprToCombi(node2, scope, code, mfs) {
1942
2771
  if (node2.type === "Identifier") return scopeGet(scope, node2.name, mfs);
1943
2772
  if (node2.type !== "CallExpression") return null;
1944
2773
  const callee = node2.callee;
2774
+ if (callee.type === "CallExpression" && callee.callee.type === "Identifier" && callee.callee.name === "makeWord") {
2775
+ const boundaryArg = callee.arguments[0];
2776
+ const strArg = node2.arguments[0];
2777
+ if (!strArg || strArg.type === "SpreadElement") return null;
2778
+ const boundary = boundaryArg && boundaryArg.type !== "SpreadElement" ? anyValue(boundaryArg, scope, code, mfs) : "_0-9A-Za-z";
2779
+ const str = anyValue(strArg, scope, code, mfs);
2780
+ if (typeof boundary !== "string" || typeof str !== "string") return null;
2781
+ try {
2782
+ return word(str, boundary);
2783
+ } catch {
2784
+ return null;
2785
+ }
2786
+ }
2787
+ if (callee.type === "Identifier") {
2788
+ const factory2 = scope.get(callee.name);
2789
+ if (isWordFactory(factory2)) {
2790
+ const [strArg] = node2.arguments;
2791
+ if (!strArg || strArg.type === "SpreadElement") return null;
2792
+ const str = anyValue(strArg, scope, code, mfs);
2793
+ if (typeof str !== "string") return null;
2794
+ try {
2795
+ return word(str, factory2.boundary);
2796
+ } catch {
2797
+ return null;
2798
+ }
2799
+ }
2800
+ }
1945
2801
  if (callee.type !== "Identifier") return null;
1946
2802
  if (callee.name === "transform" && code !== void 0 && mfs !== void 0) {
1947
2803
  const [parserArg, fnArg] = node2.arguments;
@@ -2118,9 +2974,27 @@ function anyValue(node2, scope, code, mfs) {
2118
2974
  if (!propName) return null;
2119
2975
  return obj[propName] ?? null;
2120
2976
  }
2121
- if (node2.type === "CallExpression") return exprToCombi(node2, scope, code, mfs);
2977
+ if (node2.type === "CallExpression") {
2978
+ const callee = node2.callee;
2979
+ if (callee.type === "Identifier" && callee.name === "makeWord") {
2980
+ const boundaryArg = node2.arguments[0];
2981
+ const boundary = boundaryArg && boundaryArg.type !== "SpreadElement" ? anyValue(boundaryArg, scope, code, mfs) : "_0-9A-Za-z";
2982
+ if (typeof boundary !== "string") return null;
2983
+ return { tag: "wordFactory", boundary };
2984
+ }
2985
+ return exprToCombi(node2, scope, code, mfs);
2986
+ }
2122
2987
  return null;
2123
2988
  }
2989
+ function evaluateWordFactory(node2, scope, code) {
2990
+ if (node2.type !== "CallExpression") return null;
2991
+ const callee = node2.callee;
2992
+ if (callee.type !== "Identifier" || callee.name !== "makeWord") return null;
2993
+ const boundaryArg = node2.arguments[0];
2994
+ const boundary = boundaryArg && boundaryArg.type !== "SpreadElement" ? anyValue(boundaryArg, scope, code) : "_0-9A-Za-z";
2995
+ if (typeof boundary !== "string") return null;
2996
+ return { tag: "wordFactory", boundary };
2997
+ }
2124
2998
  function evaluateExpr(node2, scope, code, mapFnSources) {
2125
2999
  return exprToCombi(node2, scope, code, mapFnSources);
2126
3000
  }
@@ -2278,23 +3152,23 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
2278
3152
  anyUnresolved = true;
2279
3153
  warnings.push(`${id}:${lineOf(pos)} \u2014 ${msg} (running via the interpreter; add the plugin or simplify the declaration to compile it)`);
2280
3154
  };
2281
- const compileRulesFactory = (init, label) => {
3155
+ const compileRulesFactory = (init, label2) => {
2282
3156
  const args = init.arguments;
2283
3157
  const factoryArg = args[0];
2284
3158
  if (!factoryArg) {
2285
- warn(init.start, `${label}: rules() needs a factory argument`);
3159
+ warn(init.start, `${label2}: rules() needs a factory argument`);
2286
3160
  return null;
2287
3161
  }
2288
3162
  const ruleMap = evaluateParserFactory(factoryArg, scope, code, []);
2289
3163
  if (!ruleMap) {
2290
- warn(init.start, `${label}: rules(...) factory isn't statically evaluable`);
3164
+ warn(init.start, `${label2}: rules(...) factory isn't statically evaluable`);
2291
3165
  return null;
2292
3166
  }
2293
3167
  const entries = [];
2294
3168
  for (const [ruleKey, rule] of ruleMap) {
2295
3169
  const compiled = compile(rule);
2296
3170
  if (compiled.inlineExpression === null) {
2297
- warn(init.start, `${label}: rule "${ruleKey}" couldn't be inlined`);
3171
+ warn(init.start, `${label2}: rule "${ruleKey}" couldn't be inlined`);
2298
3172
  return null;
2299
3173
  }
2300
3174
  entries.push([ruleKey, compiled.inlineExpression]);
@@ -2338,6 +3212,12 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
2338
3212
  const mapFnSources = [];
2339
3213
  const parser2 = evaluateExpr(init, scope, code, mapFnSources);
2340
3214
  if (parser2 === null) {
3215
+ const wordFactory = evaluateWordFactory(init, scope, code);
3216
+ if (wordFactory) {
3217
+ ;
3218
+ scope.set(varName, wordFactory);
3219
+ continue;
3220
+ }
2341
3221
  warn(init.start, `"${varName}" references a parseman macro import but isn't a statically-evaluable combinator`);
2342
3222
  continue;
2343
3223
  }