parseman 0.36.0 → 0.38.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 (63) hide show
  1. package/README.md +34 -19
  2. package/dist/analysis/duplication.d.ts +421 -0
  3. package/dist/analysis/duplication.d.ts.map +1 -0
  4. package/dist/analysis/gating.d.ts +25 -0
  5. package/dist/analysis/gating.d.ts.map +1 -1
  6. package/dist/analysis/grammar.d.ts +12 -0
  7. package/dist/analysis/grammar.d.ts.map +1 -0
  8. package/dist/combinators/keywords.d.ts +9 -8
  9. package/dist/combinators/keywords.d.ts.map +1 -1
  10. package/dist/combinators/parser.d.ts +26 -0
  11. package/dist/combinators/parser.d.ts.map +1 -1
  12. package/dist/compiler/build-arity.d.ts +12 -0
  13. package/dist/compiler/build-arity.d.ts.map +1 -1
  14. package/dist/compiler/codegen.d.ts +43 -1
  15. package/dist/compiler/codegen.d.ts.map +1 -1
  16. package/dist/compiler/linker.d.ts +64 -7
  17. package/dist/compiler/linker.d.ts.map +1 -1
  18. package/dist/cst/host-mode.d.ts +43 -0
  19. package/dist/cst/host-mode.d.ts.map +1 -0
  20. package/dist/functional/doc.d.ts.map +1 -1
  21. package/dist/functional/run.d.ts.map +1 -1
  22. package/dist/index.cjs +1657 -64
  23. package/dist/index.cjs.map +4 -4
  24. package/dist/index.d.ts +7 -3
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +1657 -64
  27. package/dist/index.js.map +4 -4
  28. package/dist/language-service/index.cjs +37 -1
  29. package/dist/language-service/index.cjs.map +3 -3
  30. package/dist/language-service/index.js +37 -1
  31. package/dist/language-service/index.js.map +3 -3
  32. package/dist/oracle/corpus.d.ts +32 -0
  33. package/dist/oracle/corpus.d.ts.map +1 -0
  34. package/dist/oracle/digest.d.ts +21 -0
  35. package/dist/oracle/digest.d.ts.map +1 -0
  36. package/dist/oracle/identity.d.ts +117 -0
  37. package/dist/oracle/identity.d.ts.map +1 -0
  38. package/dist/oracle/index.cjs +423 -0
  39. package/dist/oracle/index.cjs.map +7 -0
  40. package/dist/oracle/index.d.ts +37 -0
  41. package/dist/oracle/index.d.ts.map +1 -0
  42. package/dist/oracle/index.js +400 -0
  43. package/dist/oracle/index.js.map +7 -0
  44. package/dist/plugin/evaluator.d.ts +2 -1
  45. package/dist/plugin/evaluator.d.ts.map +1 -1
  46. package/dist/plugin/index.cjs +1696 -85
  47. package/dist/plugin/index.cjs.map +4 -4
  48. package/dist/plugin/index.d.ts.map +1 -1
  49. package/dist/plugin/index.js +1696 -85
  50. package/dist/plugin/index.js.map +4 -4
  51. package/dist/run/index.cjs +23 -0
  52. package/dist/run/index.cjs.map +3 -3
  53. package/dist/run/index.js +23 -0
  54. package/dist/run/index.js.map +3 -3
  55. package/dist/spec/index.cjs +3001 -60
  56. package/dist/spec/index.cjs.map +4 -4
  57. package/dist/spec/index.js +3001 -60
  58. package/dist/spec/index.js.map +4 -4
  59. package/dist/spec/model.d.ts.map +1 -1
  60. package/dist/types.d.ts +7 -0
  61. package/dist/types.d.ts.map +1 -1
  62. package/dist/version.d.ts +1 -1
  63. package/package.json +10 -3
@@ -1,8 +1,2939 @@
1
+ // src/combinators/first-set.ts
2
+ function resolveNamedRef(p, resolve) {
3
+ if (resolve === void 0) return void 0;
4
+ const name = p._ruleName;
5
+ return name === void 0 ? void 0 : resolve(name);
6
+ }
7
+ function union(a, b) {
8
+ if (a.kind === "any" || b.kind === "any") return { kind: "any" };
9
+ if (a.kind === "empty") return b;
10
+ if (b.kind === "empty") return a;
11
+ return { kind: "ranges", ranges: mergeRanges([...a.ranges, ...b.ranges]) };
12
+ }
13
+ function intersects(a, b) {
14
+ if (a.kind === "any" || b.kind === "any") return true;
15
+ if (a.kind === "empty" || b.kind === "empty") return false;
16
+ for (const ra of a.ranges) {
17
+ for (const rb of b.ranges) {
18
+ if (ra.lo <= rb.hi && rb.lo <= ra.hi) return true;
19
+ }
20
+ }
21
+ return false;
22
+ }
23
+ function fromChar(code) {
24
+ return { kind: "ranges", ranges: [{ lo: code, hi: code }] };
25
+ }
26
+ function startsFirstSet(combinator, input, pos) {
27
+ const fs = combinator._meta.firstSet;
28
+ if (fs.kind === "any") return true;
29
+ if (fs.kind === "empty") return false;
30
+ const code = input.codePointAt(pos);
31
+ if (code === void 0) return false;
32
+ for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
33
+ return false;
34
+ }
35
+ function any() {
36
+ return { kind: "any" };
37
+ }
38
+ function empty() {
39
+ return { kind: "empty" };
40
+ }
41
+ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
42
+ if (seen.has(p)) return true;
43
+ seen.add(p);
44
+ const me = (c) => matchesEmpty(c, seen, resolve);
45
+ const d = p._def;
46
+ switch (d.tag) {
47
+ case "literal":
48
+ return d.value.length === 0;
49
+ case "keywords":
50
+ return false;
51
+ case "regex":
52
+ try {
53
+ const m = new RegExp(d.source).exec("");
54
+ return m != null && m[0] === "";
55
+ } catch {
56
+ return true;
57
+ }
58
+ case "many":
59
+ case "optional":
60
+ case "not":
61
+ case "peek":
62
+ return true;
63
+ // zero repetitions / absent / lookahead
64
+ // Default `sepBy` is `(item (sep item)*)?` — it MATCHES THE EMPTY STRING.
65
+ // Any `min >= 1` requires that many ITEMS, so it is nullable only when the
66
+ // item is. (Keying this off `min === 1` reported every `{ min: 2 }` list as
67
+ // nullable — safe, but wrong, and it put a bogus `nullable-prefix` note on
68
+ // the gating diagnostic for a list that can never match empty.)
69
+ case "sepBy":
70
+ return d.min >= 1 ? me(d.parser) : true;
71
+ case "oneOrMore":
72
+ return me(d.parser);
73
+ case "sequence":
74
+ return d.parsers.every(me);
75
+ case "choice":
76
+ return d.parsers.some(me);
77
+ case "transform":
78
+ case "label":
79
+ case "trivia":
80
+ case "token":
81
+ case "leaf":
82
+ case "expect":
83
+ case "withCtx":
84
+ case "node":
85
+ case "grammar":
86
+ case "recover":
87
+ return me(d.parser);
88
+ case "skip":
89
+ return me(d.main);
90
+ case "lazy":
91
+ try {
92
+ return me(d.thunk());
93
+ } catch {
94
+ const t = resolveNamedRef(p, resolve);
95
+ return t ? me(t) : true;
96
+ }
97
+ default:
98
+ return true;
99
+ }
100
+ }
101
+ function isZeroWidthAssertion(p) {
102
+ return p._def.tag === "not";
103
+ }
104
+ function isPositiveLookahead(p) {
105
+ return p._def.tag === "peek";
106
+ }
107
+ function narrowBy(acc, constraint) {
108
+ if (constraint.kind === "any") return acc;
109
+ if (acc === null) return constraint;
110
+ if (acc.kind === "any") return constraint;
111
+ if (acc.kind === "empty" || constraint.kind === "empty") return { kind: "empty" };
112
+ const ranges = [];
113
+ for (const a of acc.ranges) for (const b of constraint.ranges) {
114
+ const lo = Math.max(a.lo, b.lo);
115
+ const hi = Math.min(a.hi, b.hi);
116
+ if (lo <= hi) ranges.push({ lo, hi });
117
+ }
118
+ return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
119
+ }
120
+ function applyAssertion(fs, assertion) {
121
+ if (assertion === null) return fs;
122
+ if (fs.kind === "empty") return assertion;
123
+ return narrowBy(fs, assertion) ?? fs;
124
+ }
125
+ function sequenceFirstSet(parsers) {
126
+ let fs = empty();
127
+ let assertion = null;
128
+ for (const p of parsers) {
129
+ if (isPositiveLookahead(p)) {
130
+ assertion = narrowBy(assertion, p._meta.firstSet);
131
+ continue;
132
+ }
133
+ if (!isZeroWidthAssertion(p)) fs = union(fs, p._meta.firstSet);
134
+ if (!matchesEmpty(p)) return applyAssertion(fs, assertion);
135
+ }
136
+ return applyAssertion(fs, assertion);
137
+ }
138
+ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve) {
139
+ if (seen.has(p)) return any();
140
+ seen.add(p);
141
+ const fs = (c) => firstSetOf(c, seen, resolve);
142
+ const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve);
143
+ const d = p._def;
144
+ switch (d.tag) {
145
+ case "literal":
146
+ case "regex":
147
+ case "keywords":
148
+ return p._meta.firstSet;
149
+ // terminals: no refs, cached set is exact
150
+ case "lazy":
151
+ try {
152
+ return fs(d.thunk());
153
+ } catch {
154
+ const t = resolveNamedRef(p, resolve);
155
+ return t ? fs(t) : any();
156
+ }
157
+ case "choice": {
158
+ let out = empty();
159
+ for (const arm of d.parsers) out = union(out, fs(arm));
160
+ return out;
161
+ }
162
+ case "sequence": {
163
+ let out = empty();
164
+ let assertion = null;
165
+ for (const term of d.parsers) {
166
+ if (isPositiveLookahead(term)) {
167
+ assertion = narrowBy(assertion, fs(term));
168
+ continue;
169
+ }
170
+ if (!isZeroWidthAssertion(term)) out = union(out, fs(term));
171
+ if (!empties(term)) return applyAssertion(out, assertion);
172
+ }
173
+ return applyAssertion(out, assertion);
174
+ }
175
+ case "peek": {
176
+ const inner = d.parser;
177
+ return empties(inner) ? any() : fs(inner);
178
+ }
179
+ case "oneOrMore":
180
+ case "many":
181
+ case "optional":
182
+ case "transform":
183
+ case "label":
184
+ case "trivia":
185
+ case "token":
186
+ case "leaf":
187
+ case "node":
188
+ case "grammar":
189
+ case "expect":
190
+ return fs(d.parser);
191
+ case "sepBy":
192
+ return fs(d.parser);
193
+ // both min 0 and min 1 start with the item
194
+ case "skip":
195
+ return fs(d.main);
196
+ default:
197
+ return p._meta.firstSet;
198
+ }
199
+ }
200
+ function mergeRanges(ranges) {
201
+ if (ranges.length === 0) return [];
202
+ const sorted = [...ranges].sort((a, b) => a.lo - b.lo);
203
+ const out = [{ lo: sorted[0].lo, hi: sorted[0].hi }];
204
+ for (let i = 1; i < sorted.length; i++) {
205
+ const top = out[out.length - 1];
206
+ const cur = sorted[i];
207
+ if (cur.lo <= top.hi + 1) {
208
+ if (cur.hi > top.hi) top.hi = cur.hi;
209
+ } else {
210
+ out.push({ lo: cur.lo, hi: cur.hi });
211
+ }
212
+ }
213
+ return out;
214
+ }
215
+
216
+ // src/combinators/ref.ts
217
+ function ref() {
218
+ let resolved = null;
219
+ const meta = {
220
+ firstSet: any(),
221
+ canMatchNewline: true,
222
+ isTrivia: false
223
+ };
224
+ const slot = {
225
+ _tag: "lazy",
226
+ _meta: meta,
227
+ _def: {
228
+ tag: "lazy",
229
+ thunk: () => {
230
+ if (!resolved) throw new Error("ref<T>() used before .define() was called");
231
+ return resolved;
232
+ }
233
+ },
234
+ parse(input, pos, ctx) {
235
+ if (!resolved) throw new Error("ref<T>() used before .define() was called");
236
+ return resolved.parse(input, pos, ctx);
237
+ },
238
+ define(p) {
239
+ if (resolved) throw new Error("ref<T>() already defined");
240
+ resolved = p;
241
+ meta.firstSet = p._meta.firstSet;
242
+ meta.canMatchNewline = p._meta.canMatchNewline;
243
+ meta.isTrivia = p._meta.isTrivia;
244
+ if (p._meta.triviaKindLabels !== void 0) meta.triviaKindLabels = p._meta.triviaKindLabels;
245
+ else delete meta.triviaKindLabels;
246
+ if (p._meta.disjoint !== void 0) meta.disjoint = p._meta.disjoint;
247
+ else delete meta.disjoint;
248
+ }
249
+ };
250
+ return slot;
251
+ }
252
+
253
+ // src/compiler/value-usage.ts
254
+ function markUnusedValues(root) {
255
+ const seenConsumed = /* @__PURE__ */ new WeakSet();
256
+ const seenUnconsumed = /* @__PURE__ */ new WeakSet();
257
+ const mark = (def, consumed) => {
258
+ if (consumed) def.valueUnused = false;
259
+ else if (def.valueUnused !== false) def.valueUnused = true;
260
+ };
261
+ const visit = (c, consumed) => {
262
+ const seen = consumed ? seenConsumed : seenUnconsumed;
263
+ if (seen.has(c)) return;
264
+ seen.add(c);
265
+ const def = c._def;
266
+ switch (def.tag) {
267
+ case "many":
268
+ case "oneOrMore":
269
+ mark(def, consumed);
270
+ visit(def.parser, consumed);
271
+ return;
272
+ case "optional":
273
+ visit(def.parser, consumed);
274
+ return;
275
+ case "sequence":
276
+ mark(def, consumed);
277
+ for (const p of def.parsers) visit(p, consumed);
278
+ return;
279
+ case "choice":
280
+ for (const p of def.parsers) visit(p, consumed);
281
+ return;
282
+ case "node":
283
+ visit(def.parser, false);
284
+ return;
285
+ case "transform":
286
+ visit(def.parser, true);
287
+ return;
288
+ case "field":
289
+ visit(def.parser, true);
290
+ return;
291
+ case "skip":
292
+ visit(def.main, consumed);
293
+ visit(def.skipped, false);
294
+ return;
295
+ case "sepBy":
296
+ visit(def.parser, true);
297
+ visit(def.separator, false);
298
+ return;
299
+ case "not":
300
+ case "peek":
301
+ visit(def.parser, false);
302
+ return;
303
+ case "grammar":
304
+ visit(def.parser, consumed);
305
+ if (def.triviaParser) visit(def.triviaParser, false);
306
+ return;
307
+ case "recover":
308
+ visit(def.parser, consumed);
309
+ visit(def.sentinel, false);
310
+ return;
311
+ case "label":
312
+ case "trivia":
313
+ case "token":
314
+ case "attempt":
315
+ case "withCtx":
316
+ case "expect":
317
+ visit(def.parser, consumed);
318
+ return;
319
+ case "leaf":
320
+ visit(def.parser, true);
321
+ return;
322
+ case "lazy":
323
+ return;
324
+ default:
325
+ return;
326
+ }
327
+ };
328
+ const resolveRoot = (c) => {
329
+ const guard = /* @__PURE__ */ new Set();
330
+ let cur = c;
331
+ while (!guard.has(cur)) {
332
+ const d = cur._def;
333
+ if (d.tag !== "lazy") return cur;
334
+ guard.add(cur);
335
+ try {
336
+ cur = d.thunk();
337
+ } catch {
338
+ return c;
339
+ }
340
+ }
341
+ return cur;
342
+ };
343
+ visit(resolveRoot(root), true);
344
+ }
345
+
1
346
  // src/combinators/parser.ts
2
347
  var RULE_ORDER = "__parsemanRuleOrder";
348
+ function tagRule(r, key) {
349
+ ;
350
+ r._ruleName = key;
351
+ if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
352
+ }
353
+ function isDefinableRef(v) {
354
+ return !!v && typeof v === "object" && "_def" in v && v._def.tag === "lazy" && typeof v.define === "function";
355
+ }
356
+ function ruleNameOf(r) {
357
+ return r._ruleName;
358
+ }
359
+ function isNamedRuleRefForAnotherRule(r, key) {
360
+ const name = r._def.tag === "lazy" ? ruleNameOf(r) : void 0;
361
+ return name !== void 0 && name !== key;
362
+ }
363
+ function rules(a, b) {
364
+ const factory = typeof a === "function" ? a : b;
365
+ const options = typeof a === "function" ? b : a;
366
+ const cache = {};
367
+ const proxy = new Proxy(cache, {
368
+ get(target, key) {
369
+ if (typeof key !== "string") return void 0;
370
+ const record = target;
371
+ if (!(key in record)) {
372
+ const r = ref();
373
+ tagRule(r, key);
374
+ record[key] = r;
375
+ }
376
+ return record[key];
377
+ }
378
+ });
379
+ const definitions = factory(proxy);
380
+ for (const key of Object.keys(definitions)) {
381
+ const placeholder = cache[key];
382
+ const parser2 = definitions[key];
383
+ if (placeholder === parser2) {
384
+ throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
385
+ }
386
+ if (isDefinableRef(placeholder)) {
387
+ if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
388
+ placeholder.define(parser2);
389
+ placeholder._meta.firstSet = parser2._meta.firstSet;
390
+ placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
391
+ } else if (isNamedRuleRefForAnotherRule(parser2, key)) {
392
+ const alias = ref();
393
+ tagRule(alias, key);
394
+ alias.define(parser2);
395
+ alias._meta.firstSet = parser2._meta.firstSet;
396
+ alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
397
+ cache[key] = alias;
398
+ } else {
399
+ tagRule(parser2, key);
400
+ cache[key] = parser2;
401
+ }
402
+ }
403
+ if (options?.trivia != null) {
404
+ for (const key of Object.keys(definitions)) {
405
+ const rule = cache[key];
406
+ if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
407
+ }
408
+ }
409
+ if (options?.scanSkip != null) {
410
+ for (const key of Object.keys(definitions)) {
411
+ const rule = cache[key];
412
+ if (rule && !rule._meta.isTrivia) rule._meta.grammarScanSkip = options.scanSkip;
413
+ }
414
+ }
415
+ if (options?.hostMode === "cst") {
416
+ for (const key of Object.keys(definitions)) {
417
+ const rule = cache[key];
418
+ if (rule && !rule._meta.isTrivia) rule._meta.grammarHostMode = "cst";
419
+ }
420
+ }
421
+ for (const key of Object.keys(definitions)) {
422
+ markUnusedValues(cache[key]);
423
+ }
424
+ Object.defineProperty(cache, RULE_ORDER, {
425
+ value: Object.keys(definitions),
426
+ enumerable: false,
427
+ configurable: true
428
+ });
429
+ return cache;
430
+ }
431
+
432
+ // src/cst/capture-buffer.ts
433
+ var EMPTY = [];
434
+ var EMPTY_TL = [];
435
+ function cstCaptureActive(ctx) {
436
+ return ctx._cstBuf !== void 0 || ctx._cstLeaves !== void 0;
437
+ }
438
+ function beginCstNodeCapture(ctx) {
439
+ const saved = {
440
+ ch: ctx._cstChildren,
441
+ lv: ctx._cstLeaves,
442
+ raw: ctx._cstRawChildren,
443
+ tl: ctx._cstTriviaLog,
444
+ cap: ctx.captureTrivia,
445
+ buf: ctx._cstBuf
446
+ };
447
+ ctx._cstBuf = {};
448
+ ctx._cstChildren = void 0;
449
+ ctx._cstLeaves = void 0;
450
+ ctx._cstRawChildren = void 0;
451
+ ctx._cstTriviaLog = void 0;
452
+ ctx.captureTrivia = true;
453
+ return saved;
454
+ }
455
+ function finishCstBuf(buf) {
456
+ if (!buf) return { children: EMPTY, rawChildren: EMPTY, triviaLog: EMPTY_TL };
457
+ const children = buf.ch ?? (buf.single !== void 0 ? [buf.single] : EMPTY);
458
+ const rawChildren = buf.raw ?? (buf.rawSingle !== void 0 ? [buf.rawSingle] : EMPTY);
459
+ const triviaLog = buf.tl ?? EMPTY_TL;
460
+ return { children, rawChildren, triviaLog };
461
+ }
462
+ function endCstNodeCapture(ctx, saved) {
463
+ const materialized = finishCstBuf(ctx._cstBuf);
464
+ ctx._cstBuf = saved.buf;
465
+ ctx._cstChildren = saved.ch;
466
+ ctx._cstLeaves = saved.lv;
467
+ ctx._cstRawChildren = saved.raw;
468
+ ctx._cstTriviaLog = saved.tl;
469
+ ctx.captureTrivia = saved.cap;
470
+ return materialized;
471
+ }
472
+ function pushCstLeaf(ctx, leaf2) {
473
+ pushCstChild(ctx, leaf2, leaf2);
474
+ }
475
+ function pushCstChild(ctx, built, rawEntry) {
476
+ const b = ctx._cstBuf;
477
+ if (b) {
478
+ if (b.ch) b.ch.push(built);
479
+ else if (b.single !== void 0) {
480
+ b.ch = [b.single, built];
481
+ b.single = void 0;
482
+ } else b.single = built;
483
+ if (b.raw) b.raw.push(rawEntry);
484
+ else if (b.rawSingle !== void 0) {
485
+ b.raw = [b.rawSingle, rawEntry];
486
+ b.rawSingle = void 0;
487
+ } else b.rawSingle = rawEntry;
488
+ return;
489
+ }
490
+ if (ctx._cstChildren) ctx._cstChildren.push(built);
491
+ else if (ctx._cstLeaves) ctx._cstLeaves.push(built);
492
+ if (ctx._cstRawChildren) ctx._cstRawChildren.push(rawEntry);
493
+ }
494
+ function cstRawLen(ctx) {
495
+ const b = ctx._cstBuf;
496
+ if (b) {
497
+ if (b.raw) return b.raw.length;
498
+ return b.rawSingle !== void 0 ? 1 : 0;
499
+ }
500
+ return ctx._cstRawChildren?.length ?? 0;
501
+ }
502
+ function cstLeavesLen(ctx) {
503
+ const b = ctx._cstBuf;
504
+ if (b) {
505
+ if (b.ch) return b.ch.length;
506
+ return b.single !== void 0 ? 1 : 0;
507
+ }
508
+ return ctx._cstLeaves?.length ?? 0;
509
+ }
510
+ function cstTlLen(ctx) {
511
+ const b = ctx._cstBuf;
512
+ if (b) return b.tl?.length ?? 0;
513
+ return ctx._cstTriviaLog?.length ?? 0;
514
+ }
515
+ function saveCstMark(ctx) {
516
+ return {
517
+ raw: cstRawLen(ctx),
518
+ tlog: cstTlLen(ctx),
519
+ leaves: cstLeavesLen(ctx),
520
+ fields: ctx._fields?.length ?? 0,
521
+ // Speculative rollback must truncate the flat recovery-error sink in lockstep
522
+ // with the CST leaves: a branch that recovered (pushing a ParseError to
523
+ // ctx._errors AND embedding it as a CST child via captureError) then failed
524
+ // must remove BOTH, or the flat error survives as a GHOST that a tree walk
525
+ // can't see (flat run().errors would disagree with the embedded set).
526
+ errors: ctx._errors?.length ?? 0
527
+ };
528
+ }
529
+ function rollbackBufList(b, keyMulti, keySingle, len) {
530
+ const arr = b[keyMulti];
531
+ if (arr) {
532
+ if (len === 0) b[keyMulti] = void 0;
533
+ else if (len === 1) {
534
+ b[keySingle] = arr[0];
535
+ b[keyMulti] = void 0;
536
+ } else if (arr.length !== len) arr.length = len;
537
+ return;
538
+ }
539
+ if (len === 0) b[keySingle] = void 0;
540
+ }
541
+ function rollbackCstCapture(ctx, mark) {
542
+ if (ctx._errors && mark.errors !== void 0 && ctx._errors.length !== mark.errors) ctx._errors.length = mark.errors;
543
+ const b = ctx._cstBuf;
544
+ if (b) {
545
+ rollbackBufList(b, "raw", "rawSingle", mark.raw);
546
+ rollbackBufList(b, "ch", "single", mark.leaves);
547
+ if (b.tl) {
548
+ if (mark.tlog === 0) b.tl = void 0;
549
+ else if (b.tl.length !== mark.tlog) b.tl.length = mark.tlog;
550
+ }
551
+ if (ctx._fields && ctx._fields.length !== mark.fields) ctx._fields.length = mark.fields;
552
+ return;
553
+ }
554
+ if (ctx._cstRawChildren && ctx._cstRawChildren.length !== mark.raw) ctx._cstRawChildren.length = mark.raw;
555
+ if (ctx._cstTriviaLog && ctx._cstTriviaLog.length !== mark.tlog) ctx._cstTriviaLog.length = mark.tlog;
556
+ if (ctx._cstLeaves && ctx._cstLeaves.length !== mark.leaves) ctx._cstLeaves.length = mark.leaves;
557
+ if (ctx._fields && ctx._fields.length !== mark.fields) ctx._fields.length = mark.fields;
558
+ }
559
+ function pushCstTriviaEntry(ctx, start, end, kindIndex) {
560
+ const insertIdx = cstRawLen(ctx);
561
+ const b = ctx._cstBuf;
562
+ const withKind = ctx.triviaKindLabels !== void 0 && kindIndex !== void 0;
563
+ if (b) {
564
+ if (!b.tl) {
565
+ b.tl = withKind ? [start, end, insertIdx, kindIndex] : [start, end, insertIdx];
566
+ } else if (withKind) {
567
+ b.tl.push(start, end, insertIdx, kindIndex);
568
+ } else {
569
+ b.tl.push(start, end, insertIdx);
570
+ }
571
+ return;
572
+ }
573
+ if (ctx._cstTriviaLog) {
574
+ if (withKind) ctx._cstTriviaLog.push(start, end, insertIdx, kindIndex);
575
+ else ctx._cstTriviaLog.push(start, end, insertIdx);
576
+ }
577
+ }
578
+ function pushTriviaLogEntry(ctx, start, end, kindIndex) {
579
+ if (!ctx._triviaLog) return;
580
+ if (ctx.triviaKindLabels !== void 0 && kindIndex !== void 0) {
581
+ ctx._triviaLog.push(start, end, kindIndex);
582
+ } else {
583
+ ctx._triviaLog.push(start, end);
584
+ }
585
+ }
586
+
587
+ // src/recovery/scan.ts
588
+ function probeAt(sentinel, input, pos, ctx) {
589
+ const s = {
590
+ _probe: ctx._probe,
591
+ _errors: ctx._errors,
592
+ _cstLeaves: ctx._cstLeaves,
593
+ _cstChildren: ctx._cstChildren,
594
+ _cstRawChildren: ctx._cstRawChildren,
595
+ _cstTriviaLog: ctx._cstTriviaLog,
596
+ _triviaLog: ctx._triviaLog,
597
+ _fields: ctx._fields,
598
+ _cstBuf: ctx._cstBuf,
599
+ _tolerant: ctx._tolerant,
600
+ _sync: ctx._sync
601
+ };
602
+ ctx._probe = void 0;
603
+ ctx._errors = void 0;
604
+ ctx._cstLeaves = void 0;
605
+ ctx._cstChildren = void 0;
606
+ ctx._cstRawChildren = void 0;
607
+ ctx._cstTriviaLog = void 0;
608
+ ctx._triviaLog = void 0;
609
+ ctx._fields = void 0;
610
+ ctx._cstBuf = void 0;
611
+ ctx._tolerant = void 0;
612
+ ctx._sync = void 0;
613
+ try {
614
+ return sentinel.parse(input, pos, ctx).ok;
615
+ } finally {
616
+ ctx._probe = s._probe;
617
+ ctx._errors = s._errors;
618
+ ctx._cstLeaves = s._cstLeaves;
619
+ ctx._cstChildren = s._cstChildren;
620
+ ctx._cstRawChildren = s._cstRawChildren;
621
+ ctx._cstTriviaLog = s._cstTriviaLog;
622
+ ctx._triviaLog = s._triviaLog;
623
+ ctx._fields = s._fields;
624
+ ctx._cstBuf = s._cstBuf;
625
+ ctx._tolerant = s._tolerant;
626
+ ctx._sync = s._sync;
627
+ }
628
+ }
629
+ function orSentinel(a, b) {
630
+ if (b === void 0) return a;
631
+ return {
632
+ _tag: "orSentinel",
633
+ _meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
634
+ _def: { tag: "unknown" },
635
+ parse(input, pos, ctx) {
636
+ const ra = a.parse(input, pos, ctx);
637
+ if (ra.ok) return ra;
638
+ return b.parse(input, pos, ctx);
639
+ }
640
+ };
641
+ }
642
+ function firstSetSentinel(fs) {
643
+ if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
644
+ const ranges = fs.ranges;
645
+ return {
646
+ _tag: "firstSetSentinel",
647
+ _meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
648
+ _def: { tag: "unknown" },
649
+ parse(input, pos) {
650
+ const code = pos < input.length ? input.codePointAt(pos) : void 0;
651
+ if (code !== void 0) {
652
+ for (const r of ranges) {
653
+ if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
654
+ }
655
+ }
656
+ return { ok: false, expected: [], span: { start: pos, end: pos } };
657
+ }
658
+ };
659
+ }
660
+ function recoverScan(input, from, ctx, sync, expected) {
661
+ let scanPos = from;
662
+ while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
663
+ const error = { _tag: "parseError", span: { start: from, end: scanPos }, expected };
664
+ ctx._errors?.push(error);
665
+ return { error, end: scanPos };
666
+ }
667
+ function matchesAt(sentinel, input, pos, ctx) {
668
+ return probeAt(sentinel, input, pos, ctx);
669
+ }
670
+ function captureError(ctx, error) {
671
+ if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
672
+ }
673
+
674
+ // src/combinators/expect.ts
675
+ function deriveExpected(c) {
676
+ return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
677
+ }
678
+ function derive(c, seen) {
679
+ const deriveExpected2 = (p) => derive(p, seen);
680
+ const def = c._def;
681
+ switch (def.tag) {
682
+ case "literal":
683
+ return [JSON.stringify(def.value)];
684
+ case "regex":
685
+ return [`/${def.source}/`];
686
+ case "keywords":
687
+ return def.words.map((w) => JSON.stringify(w));
688
+ case "label":
689
+ return [def.label];
690
+ case "choice":
691
+ return def.parsers.flatMap(deriveExpected2);
692
+ // Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
693
+ // `optional(…)`/`many(…)` can match nothing, so the term after it is equally
694
+ // able to fail first — deriving from term 0 alone named a token the parse
695
+ // never actually required. A leading `not(…)` is zero-width and contributes
696
+ // nothing (its own expectation is about what must NOT be here), but it is
697
+ // nullable, so keep scanning past it. Stop at the first term that must match.
698
+ case "sequence": {
699
+ const out = [];
700
+ for (const term of def.parsers) {
701
+ if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
702
+ if (!matchesEmpty(term)) break;
703
+ }
704
+ return out;
705
+ }
706
+ case "attempt":
707
+ return deriveExpected2(def.parser);
708
+ // Delegating wrappers whose first-token failure is their inner parser's — must
709
+ // pass through so a start-failure (and the first-set-miss fast-path in attempt/
710
+ // node, which reads this) names the real expected token, not the wrapper tag.
711
+ case "field":
712
+ case "withCtx":
713
+ case "recover":
714
+ return deriveExpected2(def.parser);
715
+ case "skip":
716
+ return deriveExpected2(def.main);
717
+ case "expect":
718
+ return def.expected;
719
+ case "node":
720
+ case "grammar":
721
+ case "trivia":
722
+ case "token":
723
+ case "leaf":
724
+ case "optional":
725
+ case "many":
726
+ case "oneOrMore":
727
+ case "transform":
728
+ case "not":
729
+ case "peek":
730
+ return deriveExpected2(def.parser);
731
+ case "lazy": {
732
+ const name = c._ruleName;
733
+ if (seen.has(c)) return name ? [name] : [];
734
+ seen.add(c);
735
+ try {
736
+ return deriveExpected2(def.thunk());
737
+ } catch {
738
+ return name ? [name] : [];
739
+ } finally {
740
+ seen.delete(c);
741
+ }
742
+ }
743
+ default:
744
+ return [];
745
+ }
746
+ }
747
+ function expect(combinator, label2) {
748
+ const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
749
+ const meta = {
750
+ firstSet: combinator._meta.firstSet,
751
+ canMatchNewline: combinator._meta.canMatchNewline,
752
+ isTrivia: false
753
+ };
754
+ return {
755
+ _tag: "expect",
756
+ _meta: meta,
757
+ _def: { tag: "expect", parser: combinator, label: label2, expected },
758
+ parse(input, pos, ctx) {
759
+ const result = combinator.parse(input, pos, ctx);
760
+ if (result.ok) return result;
761
+ const error = { _tag: "parseError", span: { start: pos, end: pos }, expected };
762
+ ctx._errors?.push(error);
763
+ if (ctx._tolerant) captureError(ctx, error);
764
+ return { ok: true, value: error, span: { start: pos, end: pos } };
765
+ }
766
+ };
767
+ }
768
+
769
+ // src/combinators/choice.ts
770
+ function choice(...args) {
771
+ const parsers = args.map((a) => "gate" in a ? a.combinator : a);
772
+ const gates = args.map((a) => "gate" in a ? a.gate : null);
773
+ const hasGates = gates.some((g) => g !== null);
774
+ const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
775
+ let combined = { kind: "empty" };
776
+ for (const p of parsers) combined = union(combined, p._meta.firstSet);
777
+ const meta = {
778
+ firstSet: combined,
779
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
780
+ isTrivia: false,
781
+ disjoint
782
+ };
783
+ const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
784
+ const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
785
+ let greedyLitMap = null;
786
+ let sortedParsers = null;
787
+ const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
788
+ if (strategy?.tag === "greedyClassify") {
789
+ greedyLitMap = /* @__PURE__ */ new Map();
790
+ for (let i = 0; i < parsers.length; i++) {
791
+ if (i === strategy.superIndex) continue;
792
+ const litVal = getCoreLiteralValue(parsers[i]);
793
+ if (litVal !== null) greedyLitMap.set(litVal, i);
794
+ }
795
+ } else if (strategy?.tag === "literalsLongestFirst") {
796
+ sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
797
+ }
798
+ return {
799
+ _tag: "choice",
800
+ _meta: meta,
801
+ _def: {
802
+ tag: "choice",
803
+ parsers,
804
+ gates,
805
+ disjoint,
806
+ strategy: strategy ?? { tag: "firstMatch" },
807
+ autoNot
808
+ },
809
+ parse(input, pos, ctx) {
810
+ const expected = [];
811
+ if (disjoint && pos < input.length) {
812
+ const code = input.codePointAt(pos);
813
+ let idx = code < 128 ? asciiDispatch[code] : -1;
814
+ if (idx < 0) {
815
+ for (let i = 0; i < parsers.length; i++) {
816
+ if (inFirstSet(code, parsers[i]._meta.firstSet)) {
817
+ idx = i;
818
+ break;
819
+ }
820
+ }
821
+ }
822
+ if (idx >= 0) {
823
+ const gate = gates[idx];
824
+ if (gate && !gate(ctx.state)) {
825
+ return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
826
+ }
827
+ const result = parsers[idx].parse(input, pos, ctx);
828
+ if (result.ok) return result;
829
+ expected.push(...result.expected);
830
+ return { ok: false, expected, span: { start: pos, end: pos } };
831
+ }
832
+ return {
833
+ ok: false,
834
+ expected: parsers.flatMap((p) => {
835
+ const r = p.parse(input, pos, ctx);
836
+ return r.ok ? [] : r.expected;
837
+ }),
838
+ span: { start: pos, end: pos }
839
+ };
840
+ }
841
+ if (strategy?.tag === "greedyClassify") {
842
+ const superResult = parsers[strategy.superIndex].parse(input, pos, ctx);
843
+ if (!superResult.ok) return superResult;
844
+ const end = superResult.span.end;
845
+ const litIdx = greedyLitMap.get(input.slice(pos, end));
846
+ if (litIdx !== void 0) {
847
+ const litVal = getCoreLiteralValue(parsers[litIdx]);
848
+ const value = applyTransforms(parsers[litIdx], litVal, { start: pos, end });
849
+ return { ok: true, value, span: { start: pos, end } };
850
+ }
851
+ return superResult;
852
+ }
853
+ if (strategy?.tag === "literalsLongestFirst") {
854
+ for (const p of sortedParsers) {
855
+ const r = p.parse(input, pos, ctx);
856
+ if (r.ok) return r;
857
+ expected.push(...r.expected);
858
+ }
859
+ return { ok: false, expected, span: { start: pos, end: pos } };
860
+ }
861
+ for (let i = 0; i < parsers.length; i++) {
862
+ if (gates[i] && !gates[i](ctx.state)) continue;
863
+ const mark = saveCstMark(ctx);
864
+ const logLen = ctx._triviaLog?.length;
865
+ const result = parsers[i].parse(input, pos, ctx);
866
+ if (!result.ok) {
867
+ rollbackCstCapture(ctx, mark);
868
+ if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
869
+ expected.push(...result.expected);
870
+ continue;
871
+ }
872
+ const checks = autoNot[i];
873
+ if (checks && autoNotFires(input, result.span.end, checks)) {
874
+ rollbackCstCapture(ctx, mark);
875
+ if (logLen !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== logLen) ctx._triviaLog.length = logLen;
876
+ continue;
877
+ }
878
+ return result;
879
+ }
880
+ return { ok: false, expected, span: { start: pos, end: pos } };
881
+ }
882
+ };
883
+ }
884
+ function detectStrategy(parsers) {
885
+ const regexIndices = [];
886
+ const literalIndices = [];
887
+ for (let i = 0; i < parsers.length; i++) {
888
+ if (getCoreRegexDef(parsers[i]) !== null) regexIndices.push(i);
889
+ else if (getCoreLiteralValue(parsers[i]) !== null) literalIndices.push(i);
890
+ }
891
+ if (regexIndices.length === 1 && literalIndices.length === parsers.length - 1 && literalIndices.length > 0) {
892
+ const superIndex = regexIndices[0];
893
+ const regexDef = getCoreRegexDef(parsers[superIndex]);
894
+ const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
895
+ const re = new RegExp(regexDef.source, flags);
896
+ const allSubsumed = literalIndices.every((i) => {
897
+ const litVal = getCoreLiteralValue(parsers[i]);
898
+ re.lastIndex = 0;
899
+ const m = re.exec(litVal);
900
+ return m !== null && m[0] === litVal;
901
+ });
902
+ if (allSubsumed) return { tag: "greedyClassify", superIndex };
903
+ }
904
+ if (parsers.length === literalIndices.length) {
905
+ const sortedIndices = [...literalIndices].sort(
906
+ (a, b) => getCoreLiteralValue(parsers[b]).length - getCoreLiteralValue(parsers[a]).length
907
+ );
908
+ return { tag: "literalsLongestFirst", sortedIndices };
909
+ }
910
+ const shared = detectSharedPrefix(parsers);
911
+ if (shared !== null) return shared;
912
+ return { tag: "firstMatch" };
913
+ }
914
+ function bareLeadingTermKey(term) {
915
+ const d = term._def;
916
+ if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
917
+ if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
918
+ return null;
919
+ }
920
+ function detectSharedPrefix(parsers) {
921
+ if (parsers.length < 2) return null;
922
+ let key = null;
923
+ let prefix = null;
924
+ const members = [];
925
+ for (let i = 0; i < parsers.length; i++) {
926
+ const term0 = leadingTermOfArm(parsers[i]);
927
+ if (term0 === null) return null;
928
+ const k = bareLeadingTermKey(term0);
929
+ if (k === null) return null;
930
+ if (key === null) {
931
+ key = k;
932
+ prefix = term0;
933
+ } else if (k !== key) return null;
934
+ members.push(i);
935
+ }
936
+ if (prefix === null || members.length < 2) return null;
937
+ return { tag: "sharedPrefix", prefix, members };
938
+ }
939
+ function leadingTermOfArm(arm) {
940
+ let d = arm._def;
941
+ for (; ; ) {
942
+ if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
943
+ d = d.parser._def;
944
+ continue;
945
+ }
946
+ break;
947
+ }
948
+ if (d.tag !== "sequence" || d.parsers.length < 2) return null;
949
+ return d.parsers[0];
950
+ }
951
+ function computeAutoNot(parsers) {
952
+ return parsers.map((p, i) => {
953
+ const litVal = getCoreLiteralValue(p);
954
+ if (litVal === null) return null;
955
+ const checks = [];
956
+ for (let j2 = i + 1; j2 < parsers.length; j2++) {
957
+ const other = parsers[j2];
958
+ const otherLit = getCoreLiteralValue(other);
959
+ if (otherLit !== null && otherLit.startsWith(litVal) && otherLit.length > litVal.length) {
960
+ checks.push({ kind: "startsWith", value: otherLit.slice(litVal.length) });
961
+ continue;
962
+ }
963
+ const regexDef = getCoreRegexDef(other);
964
+ if (regexDef !== null) {
965
+ const contSet = continuationFirstSet(litVal, regexDef.source, regexDef.flags);
966
+ if (contSet !== null) checks.push({ kind: "firstSet", set: contSet });
967
+ }
968
+ }
969
+ return checks.length > 0 ? checks : null;
970
+ });
971
+ }
972
+ function autoNotFires(input, end, checks) {
973
+ for (const check of checks) {
974
+ if (check.kind === "firstSet") {
975
+ const code = end < input.length ? input.codePointAt(end) ?? -1 : -1;
976
+ if (inFirstSet(code, check.set)) return true;
977
+ } else {
978
+ if (input.startsWith(check.value, end)) return true;
979
+ }
980
+ }
981
+ return false;
982
+ }
983
+ function getCoreLiteralValue(p) {
984
+ const def = p._def;
985
+ if (def.tag === "literal" && !def.caseInsensitive) return def.value;
986
+ if (def.tag === "transform") return getCoreLiteralValue(def.parser);
987
+ return null;
988
+ }
989
+ function getCoreRegexDef(p) {
990
+ const def = p._def;
991
+ if (def.tag === "regex") return { source: def.source, flags: def.flags };
992
+ if (def.tag === "transform") return getCoreRegexDef(def.parser);
993
+ if (def.tag === "label") return getCoreRegexDef(def.parser);
994
+ return null;
995
+ }
996
+ function applyTransforms(p, value, span) {
997
+ const def = p._def;
998
+ if (def.tag === "transform") {
999
+ const inner = applyTransforms(def.parser, value, span);
1000
+ return def.fn(inner, span);
1001
+ }
1002
+ return value;
1003
+ }
1004
+ function continuationFirstSet(lit, source, flags) {
1005
+ const re = new RegExp(source, "y" + flags.replace(/[gy]/g, ""));
1006
+ re.lastIndex = 0;
1007
+ const base = re.exec(lit);
1008
+ if (!base || base[0] !== lit) return null;
1009
+ const contCodes = [];
1010
+ for (let code = 1; code < 128; code++) {
1011
+ re.lastIndex = 0;
1012
+ const m = re.exec(lit + String.fromCharCode(code));
1013
+ if (m && m[0].length > lit.length) contCodes.push(code);
1014
+ }
1015
+ if (contCodes.length === 0) return null;
1016
+ return codesToFirstSet(contCodes);
1017
+ }
1018
+ function codesToFirstSet(codes) {
1019
+ codes.sort((a, b) => a - b);
1020
+ const ranges = [];
1021
+ let lo = codes[0], hi = codes[0];
1022
+ for (let i = 1; i < codes.length; i++) {
1023
+ if (codes[i] === hi + 1) {
1024
+ hi = codes[i];
1025
+ } else {
1026
+ ranges.push({ lo, hi });
1027
+ lo = hi = codes[i];
1028
+ }
1029
+ }
1030
+ ranges.push({ lo, hi });
1031
+ return { kind: "ranges", ranges };
1032
+ }
1033
+ function inFirstSet(code, fs) {
1034
+ if (fs.kind === "any") return true;
1035
+ if (fs.kind === "empty") return false;
1036
+ for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
1037
+ return false;
1038
+ }
1039
+ function areDisjoint(sets) {
1040
+ if (sets.some((s) => s.kind === "any")) return false;
1041
+ for (let i = 0; i < sets.length; i++)
1042
+ for (let j2 = i + 1; j2 < sets.length; j2++)
1043
+ if (intersects(sets[i], sets[j2])) return false;
1044
+ return true;
1045
+ }
1046
+ function buildAsciiDispatch(parsers) {
1047
+ const table = Array(128).fill(-1);
1048
+ for (let i = 0; i < parsers.length; i++) {
1049
+ const fs = parsers[i]._meta.firstSet;
1050
+ if (fs.kind !== "ranges") continue;
1051
+ for (const { lo, hi } of fs.ranges) {
1052
+ for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
1053
+ table[code] = i;
1054
+ }
1055
+ }
1056
+ }
1057
+ return table;
1058
+ }
1059
+
1060
+ // src/analysis/duplication.ts
1061
+ var WORD_RE_SRC = "-?[A-Za-z][A-Za-z0-9_-]*";
1062
+ var WORDS_RE = new RegExp(`^${WORD_RE_SRC}(?:\\|${WORD_RE_SRC})*$`);
1063
+
1064
+ // src/combinators/probe.ts
1065
+ function failAt(ctx, expected, pos) {
1066
+ const r = { ok: false, expected, span: { start: pos, end: pos } };
1067
+ const probe = ctx._probe;
1068
+ if (probe !== void 0 && pos <= probe.offset) {
1069
+ const best = probe.best;
1070
+ if (best === null || pos > best.span.start) {
1071
+ probe.best = r;
1072
+ } else if (pos === best.span.start) {
1073
+ probe.best = { ...best, expected: [...best.expected, ...expected] };
1074
+ }
1075
+ }
1076
+ return r;
1077
+ }
1078
+
1079
+ // src/combinators/literal.ts
1080
+ function asciiFoldEq(a, b) {
1081
+ if (a.length !== b.length) return false;
1082
+ for (let i = 0; i < a.length; i++) {
1083
+ let ca = a.charCodeAt(i);
1084
+ let cb = b.charCodeAt(i);
1085
+ if (ca >= 65 && ca <= 90) ca += 32;
1086
+ if (cb >= 65 && cb <= 90) cb += 32;
1087
+ if (ca !== cb) return false;
1088
+ }
1089
+ return true;
1090
+ }
1091
+ function literal(value, opts = {}) {
1092
+ const caseInsensitive = opts.caseInsensitive ?? false;
1093
+ const firstSet = value.length > 0 ? fromChar(value.codePointAt(0)) : empty();
1094
+ const meta = {
1095
+ firstSet,
1096
+ canMatchNewline: value.includes("\n"),
1097
+ isTrivia: false
1098
+ };
1099
+ if (caseInsensitive) {
1100
+ const upper = value.toUpperCase();
1101
+ const lower = value.toLowerCase();
1102
+ const firstUpper = upper.codePointAt(0);
1103
+ const firstLower = lower.codePointAt(0);
1104
+ meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? firstLower === firstUpper ? { kind: "ranges", ranges: [{ lo: firstLower, hi: firstLower }] } : { kind: "ranges", ranges: [
1105
+ { lo: firstLower, hi: firstLower },
1106
+ { lo: firstUpper, hi: firstUpper }
1107
+ ] } : firstSet;
1108
+ }
1109
+ const expected = [JSON.stringify(value)];
1110
+ const parse = !caseInsensitive && value.length === 1 ? (() => {
1111
+ const code = value.charCodeAt(0);
1112
+ return function parse2(input, pos, ctx) {
1113
+ if (input.charCodeAt(pos) === code) {
1114
+ const span = { start: pos, end: pos + 1 };
1115
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
1116
+ return { ok: true, value, span };
1117
+ }
1118
+ return failAt(ctx, expected, pos);
1119
+ };
1120
+ })() : function parse2(input, pos, ctx) {
1121
+ const end = pos + value.length;
1122
+ if (end > input.length) {
1123
+ return failAt(ctx, expected, pos);
1124
+ }
1125
+ const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
1126
+ if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
1127
+ const span = { start: pos, end };
1128
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
1129
+ return { ok: true, value: matchedValue, span };
1130
+ }
1131
+ return failAt(ctx, expected, pos);
1132
+ };
1133
+ return {
1134
+ _tag: "literal",
1135
+ _meta: meta,
1136
+ _def: { tag: "literal", value, caseInsensitive },
1137
+ parse
1138
+ };
1139
+ }
1140
+
1141
+ // src/regex/classes.ts
1142
+ var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
1143
+ var SPACE_RANGES = [
1144
+ [9, 13],
1145
+ [32, 32],
1146
+ [160, 160],
1147
+ [5760, 5760],
1148
+ [8192, 8202],
1149
+ [8232, 8232],
1150
+ [8233, 8233],
1151
+ [8239, 8239],
1152
+ [8287, 8287],
1153
+ [12288, 12288],
1154
+ [65279, 65279]
1155
+ ];
1156
+ function shorthandRanges(ch) {
1157
+ if (ch === "d") return [[48, 57]];
1158
+ if (ch === "s") return SPACE_RANGES;
1159
+ return [[48, 57], [65, 90], [97, 122], [95, 95]];
1160
+ }
1161
+ function readUnicodeEscape(body, i) {
1162
+ if (body[i] !== "\\" || body[i + 1] !== "u") return null;
1163
+ const hex = body.slice(i + 2, i + 6);
1164
+ if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
1165
+ return { cp: Number.parseInt(hex, 16), next: i + 6 };
1166
+ }
1167
+ function parseClassRanges(body) {
1168
+ const ranges = [];
1169
+ let i = 0;
1170
+ const readAtom = () => {
1171
+ const ch = body[i];
1172
+ if (ch === void 0) return null;
1173
+ if (ch === "\\") {
1174
+ const uni = readUnicodeEscape(body, i);
1175
+ if (uni) {
1176
+ i = uni.next;
1177
+ return { cp: uni.cp };
1178
+ }
1179
+ const e = body[i + 1];
1180
+ if (e === void 0) return null;
1181
+ i += 2;
1182
+ if (e in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[e] };
1183
+ if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges(e) };
1184
+ if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
1185
+ return { cp: e.codePointAt(0) };
1186
+ }
1187
+ i += ch.length;
1188
+ return { cp: ch.codePointAt(0) };
1189
+ };
1190
+ while (i < body.length) {
1191
+ const lo = readAtom();
1192
+ if (lo === null) return null;
1193
+ if ("set" in lo) {
1194
+ ranges.push(...lo.set);
1195
+ continue;
1196
+ }
1197
+ if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
1198
+ i += 1;
1199
+ const hi = readAtom();
1200
+ if (hi === null || "set" in hi) return null;
1201
+ ranges.push([lo.cp, hi.cp]);
1202
+ } else {
1203
+ ranges.push([lo.cp, lo.cp]);
1204
+ }
1205
+ }
1206
+ return ranges.length ? ranges : null;
1207
+ }
1208
+
1209
+ // src/combinators/regex.ts
1210
+ var firstSetAnalyzer = null;
1211
+ var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
1212
+ var SCAN_BAIL_AT = 64;
1213
+ function inRanges(cp, ranges) {
1214
+ for (let i = 0; i < ranges.length; i++) {
1215
+ const [lo, hi] = ranges[i];
1216
+ if (cp >= lo && cp <= hi) return true;
1217
+ }
1218
+ return false;
1219
+ }
1220
+ function readClassRanges(body) {
1221
+ if (body.startsWith("^")) return null;
1222
+ return parseClassRanges(body);
1223
+ }
1224
+ function shortScanner(source, flags) {
1225
+ if (/[imsuvy]/.test(flags)) return null;
1226
+ let ranges = null;
1227
+ let quant = "";
1228
+ if (source[0] === "[") {
1229
+ let end = 1;
1230
+ while (end < source.length && source[end] !== "]") {
1231
+ if (source[end] === "\\") end += 2;
1232
+ else end++;
1233
+ }
1234
+ if (source[end] !== "]") return null;
1235
+ ranges = readClassRanges(source.slice(1, end));
1236
+ quant = source.slice(end + 1);
1237
+ } else if (source[0] === "\\" && (source[1] === "d" || source[1] === "w" || source[1] === "s")) {
1238
+ ranges = shorthandRanges(source[1]);
1239
+ quant = source.slice(2);
1240
+ }
1241
+ if (!ranges || quant !== "+" && quant !== "*") return null;
1242
+ const minOne = quant === "+";
1243
+ return (input, pos) => {
1244
+ let end = pos;
1245
+ while (end < input.length && inRanges(input.charCodeAt(end), ranges)) {
1246
+ end++;
1247
+ if (end - pos >= SCAN_BAIL_AT) return void 0;
1248
+ }
1249
+ return minOne && end === pos ? null : end;
1250
+ };
1251
+ }
1252
+ function asciiCaseFold(fs) {
1253
+ if (fs.kind !== "ranges") return fs;
1254
+ const ranges = fs.ranges.map((r) => ({ lo: r.lo, hi: r.hi }));
1255
+ const add = (lo, hi) => {
1256
+ if (lo <= hi) ranges.push({ lo, hi });
1257
+ };
1258
+ for (const r of fs.ranges) {
1259
+ const uLo = Math.max(r.lo, 65), uHi = Math.min(r.hi, 90);
1260
+ add(uLo + 32, uHi + 32);
1261
+ const lLo = Math.max(r.lo, 97), lHi = Math.min(r.hi, 122);
1262
+ add(lLo - 32, lHi - 32);
1263
+ }
1264
+ ranges.sort((a, b) => a.lo - b.lo);
1265
+ const merged = [];
1266
+ for (const r of ranges) {
1267
+ const last = merged[merged.length - 1];
1268
+ if (last && r.lo <= last.hi + 1) last.hi = Math.max(last.hi, r.hi);
1269
+ else merged.push({ lo: r.lo, hi: r.hi });
1270
+ }
1271
+ return { kind: "ranges", ranges: merged };
1272
+ }
1273
+ function regex(pattern, flags = "") {
1274
+ const source = typeof pattern === "string" ? pattern : pattern.source;
1275
+ const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
1276
+ const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
1277
+ const scan = shortScanner(source, resolvedFlags);
1278
+ const raw = (firstSetAnalyzer ?? permissiveFirstSet)(source);
1279
+ const firstSet = !resolvedFlags.includes("i") ? raw.firstSet : resolvedFlags.includes("u") || resolvedFlags.includes("v") ? any() : asciiCaseFold(raw.firstSet);
1280
+ const canMatchNewline = raw.canMatchNewline;
1281
+ const meta = { firstSet, canMatchNewline, isTrivia: false };
1282
+ return {
1283
+ _tag: "regex",
1284
+ _meta: meta,
1285
+ _def: { tag: "regex", source, flags: resolvedFlags },
1286
+ parse(input, pos, ctx) {
1287
+ const scanEnd = scan?.(input, pos);
1288
+ if (scanEnd !== void 0) {
1289
+ if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
1290
+ const value = input.slice(pos, scanEnd);
1291
+ const span2 = { start: pos, end: scanEnd };
1292
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span: span2 });
1293
+ return { ok: true, value, span: span2 };
1294
+ }
1295
+ anchored.lastIndex = pos;
1296
+ const m = anchored.exec(input);
1297
+ if (m === null) {
1298
+ return failAt(ctx, [`/${source}/`], pos);
1299
+ }
1300
+ const span = { start: pos, end: pos + m[0].length };
1301
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: m[0], span });
1302
+ return { ok: true, value: m[0], span };
1303
+ }
1304
+ };
1305
+ }
1306
+
1307
+ // src/cst/trivia-kinds.ts
1308
+ function unwrapTrivia(p) {
1309
+ let cur = p;
1310
+ while (cur._def.tag === "trivia") cur = cur._def.parser;
1311
+ return cur;
1312
+ }
1313
+ function peelLabel(p) {
1314
+ if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
1315
+ return null;
1316
+ }
1317
+ function analyzeLabeledTrivia(trivia2) {
1318
+ let core = unwrapTrivia(trivia2);
1319
+ let minRepeats = 1;
1320
+ if (core._def.tag === "oneOrMore") {
1321
+ core = core._def.parser;
1322
+ minRepeats = 1;
1323
+ } else if (core._def.tag === "many") {
1324
+ core = core._def.parser;
1325
+ minRepeats = 0;
1326
+ }
1327
+ const arms = [];
1328
+ if (core._def.tag === "choice") {
1329
+ for (let i = 0; i < core._def.parsers.length; i++) {
1330
+ const peeled = peelLabel(core._def.parsers[i]);
1331
+ if (!peeled) return null;
1332
+ arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
1333
+ }
1334
+ } else {
1335
+ const peeled = peelLabel(core);
1336
+ if (!peeled) return null;
1337
+ arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
1338
+ }
1339
+ return { labels: arms.map((a) => a.label), arms, minRepeats };
1340
+ }
1341
+ function matchArmAt(input, pos, arm) {
1342
+ const r = arm.parse(input, pos, { trackLines: false });
1343
+ if (!r.ok || r.span.end <= pos) return null;
1344
+ return { end: r.span.end };
1345
+ }
1346
+ function scanLabeledTriviaChunks(input, cur, spec) {
1347
+ const chunks = [];
1348
+ let pos = cur;
1349
+ while (pos < input.length) {
1350
+ let matched = null;
1351
+ for (const arm of spec.arms) {
1352
+ const m = matchArmAt(input, pos, arm.parser);
1353
+ if (m) {
1354
+ matched = { end: m.end, kindIndex: arm.kindIndex };
1355
+ break;
1356
+ }
1357
+ }
1358
+ if (!matched) break;
1359
+ chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
1360
+ pos = matched.end;
1361
+ }
1362
+ if (chunks.length < spec.minRepeats) {
1363
+ return { end: cur, chunks: [] };
1364
+ }
1365
+ return { end: pos, chunks };
1366
+ }
1367
+ function scanFastWsCommentsChunks(input, cur, wsKind, commentKind) {
1368
+ const chunks = [];
1369
+ let pos = cur;
1370
+ while (pos < input.length) {
1371
+ const c = input.charCodeAt(pos);
1372
+ if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {
1373
+ const start = pos;
1374
+ pos++;
1375
+ while (pos < input.length) {
1376
+ const c2 = input.charCodeAt(pos);
1377
+ if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) pos++;
1378
+ else break;
1379
+ }
1380
+ chunks.push({ start, end: pos, kindIndex: wsKind });
1381
+ continue;
1382
+ }
1383
+ if (c === 47 && input.charCodeAt(pos + 1) === 42) {
1384
+ let j2 = pos + 2;
1385
+ while (j2 + 1 < input.length && !(input.charCodeAt(j2) === 42 && input.charCodeAt(j2 + 1) === 47)) j2++;
1386
+ if (j2 + 1 < input.length && input.charCodeAt(j2) === 42 && input.charCodeAt(j2 + 1) === 47) {
1387
+ const start = pos;
1388
+ pos = j2 + 2;
1389
+ chunks.push({ start, end: pos, kindIndex: commentKind });
1390
+ continue;
1391
+ }
1392
+ break;
1393
+ }
1394
+ break;
1395
+ }
1396
+ return { end: pos, chunks };
1397
+ }
1398
+ function tryFastLabeledScan(input, cur, trivia2) {
1399
+ const spec = analyzeLabeledTrivia(trivia2);
1400
+ if (!spec || spec.arms.length !== 2) return null;
1401
+ const wsArm = spec.arms.find((a) => {
1402
+ const src = getCoreRegexDef(a.parser)?.source;
1403
+ return src != null && !src.includes("\\*");
1404
+ });
1405
+ const commentArm = spec.arms.find((a) => {
1406
+ const src = getCoreRegexDef(a.parser)?.source;
1407
+ return src != null && src.includes("\\*");
1408
+ });
1409
+ if (!wsArm || !commentArm) return null;
1410
+ const { chunks } = scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1411
+ if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
1412
+ return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
1413
+ }
1414
+ function recordTriviaChunks(ctx, chunks) {
1415
+ const kinds = ctx.triviaKindLabels;
1416
+ const mask = ctx._triviaCaptureMask;
1417
+ for (const ch of chunks) {
1418
+ pushTriviaLogEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
1419
+ if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
1420
+ if (mask === void 0 || kinds === void 0 || (mask & 1 << ch.kindIndex) !== 0) {
1421
+ pushCstTriviaEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
1422
+ }
1423
+ }
1424
+ }
1425
+ }
1426
+ function triviaKindMask(labels, keep) {
1427
+ if (!labels) return void 0;
1428
+ let mask = 0;
1429
+ for (const name of keep) {
1430
+ const idx = labels.indexOf(name);
1431
+ if (idx >= 0) mask |= 1 << idx;
1432
+ }
1433
+ return mask;
1434
+ }
1435
+
1436
+ // src/combinators/trivia-skip.ts
1437
+ var NOOP_COMMIT = () => {
1438
+ };
1439
+ var fastTriviaCache = /* @__PURE__ */ new WeakMap();
1440
+ function needsDeferredTriviaCommit(ctx) {
1441
+ return ctx._triviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
1442
+ }
1443
+ function saveTriviaMark(ctx) {
1444
+ const m = saveCstMark(ctx);
1445
+ return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, errors: m.errors, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
1446
+ }
1447
+ function rollbackTrivia(ctx, mark) {
1448
+ rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
1449
+ if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1450
+ }
1451
+ function saveLookaheadMark(ctx) {
1452
+ return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
1453
+ }
1454
+ function rollbackLookahead(ctx, mark) {
1455
+ rollbackTrivia(ctx, mark);
1456
+ if (ctx._probe) ctx._probe.best = mark.probeBest;
1457
+ }
1458
+ function scanWithLabels(input, cur, ctx) {
1459
+ const triviaP = ctx.trivia;
1460
+ const spec = analyzeLabeledTrivia(triviaP);
1461
+ if (!spec) return { end: cur, commit: NOOP_COMMIT };
1462
+ const fast = tryFastLabeledScan(input, cur, triviaP);
1463
+ const { end, chunks } = fast ?? scanLabeledTriviaChunks(input, cur, spec);
1464
+ if (end === cur) return { end: cur, commit: NOOP_COMMIT };
1465
+ return {
1466
+ end,
1467
+ commit: () => recordTriviaChunks(ctx, chunks)
1468
+ };
1469
+ }
1470
+ function advanceTrivia(input, cur, ctx) {
1471
+ const triviaP = ctx.trivia;
1472
+ if (!triviaP) return cur;
1473
+ const fast = fastTriviaScanner(triviaP);
1474
+ if (fast) return fast(input, cur);
1475
+ if (ctx.triviaKindLabels) {
1476
+ const scan = scanWithLabels(input, cur, ctx);
1477
+ return scan.end;
1478
+ }
1479
+ const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1480
+ return tr.ok && tr.span.end > cur ? tr.span.end : cur;
1481
+ }
1482
+ function scanTrivia(input, cur, ctx) {
1483
+ const triviaP = ctx.trivia;
1484
+ if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
1485
+ const log = ctx._triviaLog;
1486
+ const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
1487
+ const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
1488
+ if (fast && log === void 0 && !captureTl) {
1489
+ return { end: fast(input, cur), commit: NOOP_COMMIT };
1490
+ }
1491
+ if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
1492
+ return scanWithLabels(input, cur, ctx);
1493
+ }
1494
+ if (log !== void 0 || captureTl) {
1495
+ const tr2 = triviaP.parse(input, cur, {
1496
+ trackLines: log !== void 0 ? false : ctx.trackLines,
1497
+ state: ctx.state
1498
+ });
1499
+ if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
1500
+ const end = tr2.span.end;
1501
+ return {
1502
+ end,
1503
+ commit: () => {
1504
+ pushTriviaLogEntry(ctx, cur, end);
1505
+ if (captureTl) pushCstTriviaEntry(ctx, cur, end);
1506
+ }
1507
+ };
1508
+ }
1509
+ const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
1510
+ return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
1511
+ }
1512
+ function consumeTrivia(input, cur, ctx) {
1513
+ if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
1514
+ const scan = scanTrivia(input, cur, ctx);
1515
+ scan.commit();
1516
+ return scan.end;
1517
+ }
1518
+ function fastTriviaScanner(trivia2) {
1519
+ const cached = fastTriviaCache.get(trivia2);
1520
+ if (cached !== void 0) return cached;
1521
+ const scanner = buildFastTriviaScanner(trivia2);
1522
+ fastTriviaCache.set(trivia2, scanner);
1523
+ return scanner;
1524
+ }
1525
+ function buildFastTriviaScanner(trivia2) {
1526
+ const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
1527
+ const direct = regexTriviaScanner(core);
1528
+ if (direct) return direct;
1529
+ const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
1530
+ if (!repeat) return null;
1531
+ const one = regexTriviaScanner(repeat);
1532
+ if (one) return loopScanner([one]);
1533
+ if (repeat._def.tag !== "choice") return null;
1534
+ const arms = repeat._def.parsers.map(regexTriviaScanner);
1535
+ if (arms.some((s) => s === null)) return null;
1536
+ return loopScanner(arms);
1537
+ }
1538
+ function loopScanner(arms) {
1539
+ return (input, cur) => {
1540
+ let pos = cur;
1541
+ scan: while (pos < input.length) {
1542
+ for (const arm of arms) {
1543
+ const end = arm(input, pos);
1544
+ if (end > pos) {
1545
+ pos = end;
1546
+ continue scan;
1547
+ }
1548
+ }
1549
+ break;
1550
+ }
1551
+ return pos;
1552
+ };
1553
+ }
1554
+ function regexTriviaScanner(parser2) {
1555
+ if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
1556
+ const source = parser2._def.source;
1557
+ return classRunSource(source) ?? altStarSource(source) ?? (blockCommentSource(source) ? scanBlockComment : null);
1558
+ }
1559
+ function inRanges2(cp, ranges) {
1560
+ for (let i = 0; i < ranges.length; i++) {
1561
+ const r = ranges[i];
1562
+ if (cp >= r[0] && cp <= r[1]) return true;
1563
+ }
1564
+ return false;
1565
+ }
1566
+ function classScanner(classBody) {
1567
+ const ranges = parseClassRanges(classBody);
1568
+ if (!ranges) return null;
1569
+ return (input, cur) => {
1570
+ let pos = cur;
1571
+ while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
1572
+ return pos;
1573
+ };
1574
+ }
1575
+ function lineCommentScanner(commentCode) {
1576
+ return (input, cur) => {
1577
+ if (input.charCodeAt(cur) !== commentCode) return cur;
1578
+ let pos = cur + 1;
1579
+ while (pos < input.length) {
1580
+ const cc = input.charCodeAt(pos);
1581
+ if (cc === 10 || cc === 13) break;
1582
+ pos++;
1583
+ }
1584
+ return pos;
1585
+ };
1586
+ }
1587
+ function classRunSource(source) {
1588
+ const m = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]$/.exec(source);
1589
+ return m ? classScanner(m[1]) : null;
1590
+ }
1591
+ function classifyTriviaArm(arm) {
1592
+ const cls = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]?$/.exec(arm);
1593
+ if (cls) {
1594
+ const ranges = parseClassRanges(cls[1]);
1595
+ return ranges ? { kind: "class", ranges } : null;
1596
+ }
1597
+ const lc = /^(\\?.)\[\^\\n\\r\]\*$/.exec(arm);
1598
+ if (lc) {
1599
+ const marker = lc[1];
1600
+ return { kind: "comment", code: (marker.length === 2 ? marker[1] : marker[0]).charCodeAt(0) };
1601
+ }
1602
+ return null;
1603
+ }
1604
+ function armScanner(arm) {
1605
+ if (arm.kind === "comment") return lineCommentScanner(arm.code);
1606
+ const ranges = arm.ranges;
1607
+ return (input, cur) => {
1608
+ let pos = cur;
1609
+ while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
1610
+ return pos;
1611
+ };
1612
+ }
1613
+ function fusedTriviaScanner(ranges, commentCodes) {
1614
+ const c0 = commentCodes[0];
1615
+ const single = commentCodes.length === 1;
1616
+ return (input, cur) => {
1617
+ let pos = cur;
1618
+ const len = input.length;
1619
+ for (; ; ) {
1620
+ const c = input.charCodeAt(pos);
1621
+ if (pos < len && inRanges2(c, ranges)) {
1622
+ pos++;
1623
+ continue;
1624
+ }
1625
+ if (single ? c === c0 : commentCodes.includes(c)) {
1626
+ pos++;
1627
+ while (pos < len) {
1628
+ const cc = input.charCodeAt(pos);
1629
+ if (cc === 10 || cc === 13) break;
1630
+ pos++;
1631
+ }
1632
+ continue;
1633
+ }
1634
+ break;
1635
+ }
1636
+ return pos;
1637
+ };
1638
+ }
1639
+ function splitTopLevelAlts(body) {
1640
+ const arms = [];
1641
+ let inClass = false;
1642
+ let start = 0;
1643
+ for (let i = 0; i < body.length; i++) {
1644
+ const c = body[i];
1645
+ if (c === "\\") {
1646
+ i++;
1647
+ continue;
1648
+ }
1649
+ if (inClass) {
1650
+ if (c === "]") inClass = false;
1651
+ continue;
1652
+ }
1653
+ if (c === "[") inClass = true;
1654
+ else if (c === "(") return null;
1655
+ else if (c === "|") {
1656
+ arms.push(body.slice(start, i));
1657
+ start = i + 1;
1658
+ }
1659
+ }
1660
+ arms.push(body.slice(start));
1661
+ return arms;
1662
+ }
1663
+ function altStarSource(source) {
1664
+ const m = /^\(\?:(.*)\)[*+]$/.exec(source);
1665
+ if (!m) return null;
1666
+ const armSrcs = splitTopLevelAlts(m[1]);
1667
+ if (!armSrcs || armSrcs.length < 2) return null;
1668
+ const arms = [];
1669
+ for (const src of armSrcs) {
1670
+ const arm = classifyTriviaArm(src);
1671
+ if (!arm) return null;
1672
+ arms.push(arm);
1673
+ }
1674
+ const ranges = [];
1675
+ const commentCodes = [];
1676
+ for (const arm of arms) {
1677
+ if (arm.kind === "class") ranges.push(...arm.ranges);
1678
+ else commentCodes.push(arm.code);
1679
+ }
1680
+ if (commentCodes.some((code) => inRanges2(code, ranges))) {
1681
+ return loopScanner(arms.map(armScanner));
1682
+ }
1683
+ if (commentCodes.length === 0) return armScanner({ kind: "class", ranges });
1684
+ return fusedTriviaScanner(ranges, commentCodes);
1685
+ }
1686
+ function blockCommentSource(source) {
1687
+ return source === "\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/" || source === "\\/\\*[^]*?\\*\\/";
1688
+ }
1689
+ function scanBlockComment(input, cur) {
1690
+ if (input.charCodeAt(cur) !== 47 || input.charCodeAt(cur + 1) !== 42) return cur;
1691
+ const close = input.indexOf("*/", cur + 2);
1692
+ return close === -1 ? cur : close + 2;
1693
+ }
1694
+
1695
+ // src/combinators/sequence.ts
1696
+ function sequence(...parsers) {
1697
+ const meta = {
1698
+ // Union through the nullable prefix — a leading optional()/many() lets a later
1699
+ // term's first char start the sequence. Just `parsers[0]` under-approximates.
1700
+ firstSet: sequenceFirstSet(parsers),
1701
+ canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
1702
+ isTrivia: false
1703
+ };
1704
+ const def = { tag: "sequence", parsers };
1705
+ let followSentinels;
1706
+ function parseTolerant(input, pos, ctx) {
1707
+ followSentinels ??= parsers.map((_, i) => {
1708
+ const fs = parsers.slice(i + 1).reduce(
1709
+ (acc, p) => union(acc, firstSetOf(p)),
1710
+ { kind: "empty" }
1711
+ );
1712
+ return firstSetSentinel(fs);
1713
+ });
1714
+ const values = def.valueUnused ? void 0 : [];
1715
+ let cur = pos;
1716
+ const inheritedSync = ctx._sync;
1717
+ try {
1718
+ for (let i = 0; i < parsers.length; i++) {
1719
+ ctx._sync = followSentinels[i] ?? inheritedSync;
1720
+ if (ctx.trivia && i > 0) {
1721
+ const mark = saveTriviaMark(ctx);
1722
+ let scanEnd;
1723
+ if (needsDeferredTriviaCommit(ctx)) {
1724
+ const scan = scanTrivia(input, cur, ctx);
1725
+ scan.commit();
1726
+ scanEnd = scan.end;
1727
+ } else {
1728
+ scanEnd = advanceTrivia(input, cur, ctx);
1729
+ }
1730
+ const result2 = parsers[i].parse(input, scanEnd, ctx);
1731
+ if (!result2.ok) return result2;
1732
+ if (result2.span.end > scanEnd) cur = result2.span.end;
1733
+ else rollbackTrivia(ctx, mark);
1734
+ if (values !== void 0) values.push(result2.value);
1735
+ continue;
1736
+ }
1737
+ const result = parsers[i].parse(input, cur, ctx);
1738
+ if (!result.ok) return result;
1739
+ if (values !== void 0) values.push(result.value);
1740
+ cur = result.span.end;
1741
+ }
1742
+ } finally {
1743
+ ctx._sync = inheritedSync;
1744
+ }
1745
+ return {
1746
+ ok: true,
1747
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
1748
+ value: values ?? void 0,
1749
+ span: { start: pos, end: cur }
1750
+ };
1751
+ }
1752
+ return {
1753
+ _tag: "sequence",
1754
+ _meta: meta,
1755
+ _def: def,
1756
+ parse(input, pos, ctx) {
1757
+ if (ctx._tolerant) return parseTolerant(input, pos, ctx);
1758
+ const values = def.valueUnused ? void 0 : [];
1759
+ let cur = pos;
1760
+ for (let i = 0; i < parsers.length; i++) {
1761
+ if (ctx.trivia && i > 0) {
1762
+ let scanEnd;
1763
+ let mark = saveTriviaMark(ctx);
1764
+ if (needsDeferredTriviaCommit(ctx)) {
1765
+ const scan = scanTrivia(input, cur, ctx);
1766
+ scan.commit();
1767
+ scanEnd = scan.end;
1768
+ } else {
1769
+ scanEnd = advanceTrivia(input, cur, ctx);
1770
+ }
1771
+ const result2 = parsers[i].parse(input, scanEnd, ctx);
1772
+ if (!result2.ok) return result2;
1773
+ if (result2.span.end > scanEnd) {
1774
+ cur = result2.span.end;
1775
+ } else {
1776
+ rollbackTrivia(ctx, mark);
1777
+ }
1778
+ if (values !== void 0) values.push(result2.value);
1779
+ continue;
1780
+ }
1781
+ const result = parsers[i].parse(input, cur, ctx);
1782
+ if (!result.ok) return result;
1783
+ if (values !== void 0) values.push(result.value);
1784
+ cur = result.span.end;
1785
+ }
1786
+ return {
1787
+ ok: true,
1788
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
1789
+ value: values ?? void 0,
1790
+ span: { start: pos, end: cur }
1791
+ };
1792
+ }
1793
+ };
1794
+ }
1795
+
1796
+ // src/combinators/repeat.ts
1797
+ function repItem(combinator, input, cur, ctx, guardable) {
1798
+ const mark = saveTriviaMark(ctx);
1799
+ let pos = cur;
1800
+ if (ctx.trivia) {
1801
+ if (needsDeferredTriviaCommit(ctx)) {
1802
+ const scan = scanTrivia(input, cur, ctx);
1803
+ scan.commit();
1804
+ pos = scan.end;
1805
+ } else {
1806
+ pos = advanceTrivia(input, cur, ctx);
1807
+ }
1808
+ }
1809
+ if (pos >= input.length) {
1810
+ rollbackTrivia(ctx, mark);
1811
+ return "stop";
1812
+ }
1813
+ if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
1814
+ rollbackTrivia(ctx, mark);
1815
+ return "stop";
1816
+ }
1817
+ const result = combinator.parse(input, pos, ctx);
1818
+ if (!result.ok) {
1819
+ rollbackTrivia(ctx, mark);
1820
+ return { fail: result, failPos: pos };
1821
+ }
1822
+ if (result.span.end === pos) {
1823
+ rollbackTrivia(ctx, mark);
1824
+ return "stop";
1825
+ }
1826
+ return { value: result.value, end: result.span.end };
1827
+ }
1828
+ function resolveBounds(what, opts) {
1829
+ const min = opts.min ?? 0;
1830
+ const max = opts.max ?? Infinity;
1831
+ const bad = (msg) => {
1832
+ throw new RangeError(`parseman: ${what} ${msg}`);
1833
+ };
1834
+ if (!Number.isInteger(min) || min < 0) bad(`min must be a non-negative integer (got ${String(opts.min)})`);
1835
+ if (max !== Infinity && (!Number.isInteger(max) || max < 1)) bad(`max must be a positive integer (got ${String(opts.max)})`);
1836
+ if (max < min) bad(`max (${max}) is less than min (${min}) \u2014 the combinator could never succeed`);
1837
+ return { min, max };
1838
+ }
1839
+ function many(combinator, opts = {}) {
1840
+ const { min, max } = resolveBounds("many()", opts);
1841
+ if (min >= 1) return atLeast(combinator, min, max);
1842
+ const meta = {
1843
+ firstSet: combinator._meta.firstSet,
1844
+ canMatchNewline: combinator._meta.canMatchNewline,
1845
+ isTrivia: false
1846
+ };
1847
+ const def = { tag: "many", parser: combinator, min: 0, ...max === Infinity ? {} : { max } };
1848
+ let expected;
1849
+ const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
1850
+ return {
1851
+ _tag: "many",
1852
+ _meta: meta,
1853
+ _def: def,
1854
+ parse(input, pos, ctx) {
1855
+ const values = def.valueUnused ? void 0 : [];
1856
+ let cur = pos;
1857
+ let count = 0;
1858
+ while (cur < input.length) {
1859
+ if (count >= max) break;
1860
+ const item = repItem(combinator, input, cur, ctx, guardable);
1861
+ if (item === "stop") break;
1862
+ if ("fail" in item) {
1863
+ const sync = ctx._tolerant ? ctx._sync : void 0;
1864
+ if (sync === void 0) break;
1865
+ if (matchesAt(sync, input, item.failPos, ctx)) break;
1866
+ expected ??= deriveExpected(combinator);
1867
+ const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
1868
+ if (values !== void 0) values.push(error);
1869
+ captureError(ctx, error);
1870
+ count++;
1871
+ cur = end;
1872
+ continue;
1873
+ }
1874
+ if (values !== void 0) values.push(item.value);
1875
+ count++;
1876
+ cur = item.end;
1877
+ }
1878
+ return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
1879
+ }
1880
+ };
1881
+ }
1882
+ function oneOrMore(combinator, opts = {}) {
1883
+ return many(combinator, { ...opts, min: opts.min ?? 1 });
1884
+ }
1885
+ function atLeast(combinator, min, max) {
1886
+ const meta = {
1887
+ firstSet: combinator._meta.firstSet,
1888
+ canMatchNewline: combinator._meta.canMatchNewline,
1889
+ isTrivia: false
1890
+ };
1891
+ const def = { tag: "oneOrMore", parser: combinator, min, ...max === Infinity ? {} : { max } };
1892
+ let expected;
1893
+ const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
1894
+ return {
1895
+ _tag: "oneOrMore",
1896
+ _meta: meta,
1897
+ _def: def,
1898
+ parse(input, pos, ctx) {
1899
+ const first = combinator.parse(input, pos, ctx);
1900
+ if (!first.ok) return first;
1901
+ const values = def.valueUnused ? void 0 : [first.value];
1902
+ let cur = first.span.end;
1903
+ let count = 1;
1904
+ while (count < min) {
1905
+ const item = repItem(combinator, input, cur, ctx, guardable);
1906
+ if (item === "stop" || "fail" in item) {
1907
+ expected ??= deriveExpected(combinator);
1908
+ return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: cur, end: cur } };
1909
+ }
1910
+ if (values !== void 0) values.push(item.value);
1911
+ cur = item.end;
1912
+ count++;
1913
+ }
1914
+ while (cur < input.length) {
1915
+ if (count >= max) break;
1916
+ const item = repItem(combinator, input, cur, ctx, guardable);
1917
+ if (item === "stop") break;
1918
+ if ("fail" in item) {
1919
+ const sync = ctx._tolerant ? ctx._sync : void 0;
1920
+ if (sync === void 0) break;
1921
+ if (matchesAt(sync, input, item.failPos, ctx)) break;
1922
+ expected ??= deriveExpected(combinator);
1923
+ const { error, end } = recoverScan(input, item.failPos, ctx, sync, expected);
1924
+ if (values !== void 0) values.push(error);
1925
+ captureError(ctx, error);
1926
+ count++;
1927
+ cur = end;
1928
+ continue;
1929
+ }
1930
+ if (values !== void 0) values.push(item.value);
1931
+ count++;
1932
+ cur = item.end;
1933
+ }
1934
+ return { ok: true, value: values ?? void 0, span: { start: pos, end: cur } };
1935
+ }
1936
+ };
1937
+ }
1938
+ function optional(combinator) {
1939
+ const meta = {
1940
+ firstSet: combinator._meta.firstSet,
1941
+ canMatchNewline: combinator._meta.canMatchNewline,
1942
+ isTrivia: false
1943
+ };
1944
+ const firstSetSkippable = !matchesEmpty(combinator);
1945
+ return {
1946
+ _tag: "optional",
1947
+ _meta: meta,
1948
+ _def: { tag: "optional", parser: combinator },
1949
+ parse(input, pos, ctx) {
1950
+ if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
1951
+ return { ok: true, value: null, span: { start: pos, end: pos } };
1952
+ }
1953
+ const mark = saveTriviaMark(ctx);
1954
+ const result = combinator.parse(input, pos, ctx);
1955
+ if (result.ok) return result;
1956
+ rollbackTrivia(ctx, mark);
1957
+ return { ok: true, value: null, span: { start: pos, end: pos } };
1958
+ }
1959
+ };
1960
+ }
1961
+ function sepBy(combinator, separator, opts = {}) {
1962
+ const { min, max } = resolveBounds("sepBy()", opts);
1963
+ const trailing = opts.trailing ?? "forbid";
1964
+ const meta = {
1965
+ firstSet: combinator._meta.firstSet,
1966
+ canMatchNewline: combinator._meta.canMatchNewline || separator._meta.canMatchNewline,
1967
+ isTrivia: false
1968
+ };
1969
+ let expected;
1970
+ const failAt2 = (at) => {
1971
+ expected ??= deriveExpected(combinator);
1972
+ return { ok: false, expected: expected.length > 0 ? expected : [combinator._tag], span: { start: at, end: at } };
1973
+ };
1974
+ return {
1975
+ _tag: "sepBy",
1976
+ _meta: meta,
1977
+ _def: {
1978
+ tag: "sepBy",
1979
+ parser: combinator,
1980
+ separator,
1981
+ min,
1982
+ ...max === Infinity ? {} : { max },
1983
+ ...trailing === "forbid" ? {} : { trailing }
1984
+ },
1985
+ parse(input, pos, ctx) {
1986
+ const first = combinator.parse(input, pos, ctx);
1987
+ const values = [];
1988
+ let cur;
1989
+ if (first.ok) {
1990
+ values.push(first.value);
1991
+ cur = first.span.end;
1992
+ } else {
1993
+ const term = ctx._tolerant ? ctx._sync : void 0;
1994
+ if (term === void 0 || matchesAt(term, input, pos, ctx)) {
1995
+ if (min >= 1) return failAt2(pos);
1996
+ return { ok: true, value: [], span: { start: pos, end: pos } };
1997
+ }
1998
+ expected ??= deriveExpected(combinator);
1999
+ const rec = recoverScan(input, pos, ctx, orSentinel(separator, term), expected);
2000
+ values.push(rec.error);
2001
+ captureError(ctx, rec.error);
2002
+ cur = rec.end;
2003
+ }
2004
+ while (cur < input.length) {
2005
+ if (values.length >= max) break;
2006
+ const loopMark = saveTriviaMark(ctx);
2007
+ let sepPos = cur;
2008
+ if (ctx.trivia) {
2009
+ if (needsDeferredTriviaCommit(ctx)) {
2010
+ const scan = scanTrivia(input, cur, ctx);
2011
+ scan.commit();
2012
+ sepPos = scan.end;
2013
+ } else {
2014
+ sepPos = advanceTrivia(input, cur, ctx);
2015
+ }
2016
+ }
2017
+ const sep = separator.parse(input, sepPos, ctx);
2018
+ if (!sep.ok) {
2019
+ rollbackTrivia(ctx, loopMark);
2020
+ break;
2021
+ }
2022
+ const sepMark = trailing === "forbid" ? void 0 : saveTriviaMark(ctx);
2023
+ let nextPos = sep.span.end;
2024
+ if (ctx.trivia) {
2025
+ if (needsDeferredTriviaCommit(ctx)) {
2026
+ const scan = scanTrivia(input, sep.span.end, ctx);
2027
+ scan.commit();
2028
+ nextPos = scan.end;
2029
+ } else {
2030
+ nextPos = advanceTrivia(input, sep.span.end, ctx);
2031
+ }
2032
+ }
2033
+ const next = combinator.parse(input, nextPos, ctx);
2034
+ if (!next.ok) {
2035
+ const term = ctx._tolerant ? ctx._sync : void 0;
2036
+ if (term !== void 0 && !matchesAt(term, input, nextPos, ctx)) {
2037
+ expected ??= deriveExpected(combinator);
2038
+ const rec = recoverScan(input, nextPos, ctx, orSentinel(separator, term), expected);
2039
+ values.push(rec.error);
2040
+ captureError(ctx, rec.error);
2041
+ cur = rec.end;
2042
+ continue;
2043
+ }
2044
+ if (sepMark !== void 0) {
2045
+ rollbackTrivia(ctx, sepMark);
2046
+ cur = sep.span.end;
2047
+ break;
2048
+ }
2049
+ rollbackTrivia(ctx, loopMark);
2050
+ break;
2051
+ }
2052
+ values.push(next.value);
2053
+ cur = next.span.end;
2054
+ }
2055
+ if (values.length < min) return failAt2(cur);
2056
+ return { ok: true, value: values, span: { start: pos, end: cur } };
2057
+ }
2058
+ };
2059
+ }
2060
+
2061
+ // src/combinators/map.ts
2062
+ function transform(combinator, fn) {
2063
+ return {
2064
+ _tag: "transform",
2065
+ _meta: combinator._meta,
2066
+ _def: { tag: "transform", parser: combinator, fn },
2067
+ parse(input, pos, ctx) {
2068
+ const result = combinator.parse(input, pos, ctx);
2069
+ if (!result.ok) return result;
2070
+ return { ok: true, value: fn(result.value, result.span), span: result.span };
2071
+ }
2072
+ };
2073
+ }
2074
+ function skip(main, skipped) {
2075
+ return {
2076
+ _tag: "skip",
2077
+ _meta: main._meta,
2078
+ _def: { tag: "skip", main, skipped },
2079
+ parse(input, pos, ctx) {
2080
+ const result = main.parse(input, pos, ctx);
2081
+ if (!result.ok) return result;
2082
+ const s = skipped.parse(input, result.span.end, ctx);
2083
+ if (!s.ok) return result;
2084
+ return { ok: true, value: result.value, span: { start: result.span.start, end: s.span.end } };
2085
+ }
2086
+ };
2087
+ }
2088
+ function trivia(combinator) {
2089
+ const kindLabels = analyzeLabeledTrivia(combinator)?.labels;
2090
+ return {
2091
+ _tag: combinator._tag,
2092
+ _meta: {
2093
+ ...combinator._meta,
2094
+ isTrivia: true,
2095
+ ...kindLabels ? { triviaKindLabels: kindLabels } : {}
2096
+ },
2097
+ _def: { tag: "trivia", parser: combinator },
2098
+ parse: combinator.parse.bind(combinator)
2099
+ };
2100
+ }
2101
+ function label(name, combinator) {
2102
+ return {
2103
+ _tag: combinator._tag,
2104
+ _meta: combinator._meta,
2105
+ _def: { tag: "label", label: name, parser: combinator },
2106
+ parse(input, pos, ctx) {
2107
+ const result = combinator.parse(input, pos, ctx);
2108
+ if (!result.ok) return { ok: false, expected: [name], span: result.span };
2109
+ return result;
2110
+ }
2111
+ };
2112
+ }
2113
+ function field(name, combinator) {
2114
+ return {
2115
+ _tag: combinator._tag,
2116
+ _meta: combinator._meta,
2117
+ _def: { tag: "field", name, parser: combinator },
2118
+ parse(input, pos, ctx) {
2119
+ const result = combinator.parse(input, pos, ctx);
2120
+ if (!result.ok) return result;
2121
+ ctx._fields?.push({ name, value: result.value, span: result.span });
2122
+ return result;
2123
+ }
2124
+ };
2125
+ }
2126
+
2127
+ // src/combinators/scanTo.ts
2128
+ function resolveScanSkip(explicitSkip, raw, ctx) {
2129
+ if (raw) return [];
2130
+ const trivia2 = ctx.trivia;
2131
+ const ambient = ctx.scanSkip;
2132
+ if (!trivia2 && !ambient) return explicitSkip;
2133
+ const out = [];
2134
+ if (trivia2) out.push(trivia2);
2135
+ if (ambient) out.push(...ambient);
2136
+ out.push(...explicitSkip);
2137
+ return out;
2138
+ }
2139
+ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
2140
+ const meta = {
2141
+ firstSet: any(),
2142
+ canMatchNewline: true,
2143
+ isTrivia: false
2144
+ };
2145
+ const explicitSkip = skip2 ?? [];
2146
+ return {
2147
+ _tag: "scanTo",
2148
+ _meta: meta,
2149
+ _def: { tag: "scanTo", sentinel, skip: explicitSkip, raw, orEOF },
2150
+ parse(input, pos, ctx) {
2151
+ let cur = pos;
2152
+ const skip3 = resolveScanSkip(explicitSkip, raw, ctx);
2153
+ const probeCtx = {
2154
+ trackLines: ctx.trackLines,
2155
+ state: ctx.state,
2156
+ ...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
2157
+ };
2158
+ const emit = (end) => {
2159
+ if (end > pos && cstCaptureActive(ctx)) {
2160
+ const leaf2 = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
2161
+ pushCstLeaf(ctx, leaf2);
2162
+ }
2163
+ };
2164
+ while (cur < input.length) {
2165
+ const s = sentinel.parse(input, cur, probeCtx);
2166
+ if (s.ok) {
2167
+ emit(cur);
2168
+ return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
2169
+ }
2170
+ let advanced = false;
2171
+ for (const skipper of skip3) {
2172
+ const r = skipper.parse(input, cur, probeCtx);
2173
+ if (r.ok && r.span.end > cur) {
2174
+ cur = r.span.end;
2175
+ advanced = true;
2176
+ break;
2177
+ }
2178
+ }
2179
+ if (!advanced) cur++;
2180
+ }
2181
+ if (orEOF) {
2182
+ emit(cur);
2183
+ return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
2184
+ }
2185
+ const sentDef = sentinel._def;
2186
+ const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
2187
+ return { ok: false, expected, span: { start: pos, end: cur } };
2188
+ }
2189
+ };
2190
+ }
2191
+
2192
+ // src/compiler/scannable-run.ts
2193
+ var META = new Set("()[]{}*+?|^$.".split(""));
2194
+
2195
+ // src/compiler/trivia-fast-path.ts
2196
+ var CAP_RECORD = [
2197
+ ` if (_cap && _e > _pos) {`,
2198
+ ` if (_ctx._triviaLog !== undefined) _ctx._triviaLog.push(_pos, _e)`,
2199
+ ` if (_ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
2200
+ ` }`
2201
+ ].join("\n");
2202
+
2203
+ // src/compiler/build-arity.ts
2204
+ function cstOutputHost(build) {
2205
+ return build?._parsemanCstOutput === true;
2206
+ }
2207
+ var PARAM_LIST_RE = (
2208
+ // (params) => ... | function name?(params) ... | single-ident arrow `x => ...`
2209
+ /^(?:function\b[^(]*\(([^)]*)\)|\(([^)]*)\)\s*=>|([A-Za-z_$][\w$]*)\s*=>)/
2210
+ );
2211
+ var CONFIRMABLE_PARAM_RE = /^[A-Za-z_$][\w$]*\s*\??\s*(?::[^,=]+)?$/;
2212
+ function confirmedBuildArity(src) {
2213
+ const s = src.trim();
2214
+ const m = PARAM_LIST_RE.exec(s);
2215
+ if (!m) return null;
2216
+ if (m[3] !== void 0) return 1;
2217
+ const inner = (m[1] ?? m[2] ?? "").trim();
2218
+ if (inner === "") return 0;
2219
+ const parts = inner.split(",");
2220
+ for (const part of parts) {
2221
+ if (!CONFIRMABLE_PARAM_RE.test(part.trim())) return null;
2222
+ }
2223
+ if (/\barguments\b/.test(s)) return null;
2224
+ return parts.length;
2225
+ }
2226
+ function buildReadsTrivia(def) {
2227
+ if (!def.build) return true;
2228
+ const src = def.buildSrc ?? def.build.toString();
2229
+ const arity = confirmedBuildArity(src);
2230
+ if (arity === null) return true;
2231
+ return arity >= 5;
2232
+ }
2233
+ function buildReadsState(def) {
2234
+ if (!def.build) return true;
2235
+ const src = def.buildSrc ?? def.build.toString();
2236
+ const arity = confirmedBuildArity(src);
2237
+ if (arity === null) return true;
2238
+ return arity >= 6;
2239
+ }
2240
+
2241
+ // src/compiler/fields.ts
2242
+ function buildReadsFields(def) {
2243
+ if (!def.build) return true;
2244
+ const src = def.buildSrc ?? def.build.toString();
2245
+ const arity = confirmedBuildArity(src);
2246
+ if (arity === null) return true;
2247
+ return arity >= 2;
2248
+ }
2249
+ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
2250
+ if (seen.has(p)) return false;
2251
+ seen.add(p);
2252
+ const d = p._def;
2253
+ switch (d.tag) {
2254
+ case "field":
2255
+ return true;
2256
+ case "node":
2257
+ return false;
2258
+ case "lazy": {
2259
+ try {
2260
+ return parserHasOwnFields(d.thunk(), seen);
2261
+ } catch {
2262
+ return false;
2263
+ }
2264
+ }
2265
+ case "sequence":
2266
+ case "choice":
2267
+ return d.parsers.some((x) => parserHasOwnFields(x, seen));
2268
+ case "sepBy":
2269
+ return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
2270
+ case "skip":
2271
+ return parserHasOwnFields(d.main, seen) || parserHasOwnFields(d.skipped, seen);
2272
+ case "grammar":
2273
+ return parserHasOwnFields(d.parser, seen) || (d.triviaParser ? parserHasOwnFields(d.triviaParser, seen) : false);
2274
+ case "scanTo":
2275
+ return parserHasOwnFields(d.sentinel, seen) || d.skip.some((x) => parserHasOwnFields(x, seen));
2276
+ case "recover":
2277
+ return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.sentinel, seen);
2278
+ case "many":
2279
+ case "oneOrMore":
2280
+ case "optional":
2281
+ case "attempt":
2282
+ case "transform":
2283
+ case "trivia":
2284
+ case "token":
2285
+ case "leaf":
2286
+ case "label":
2287
+ case "expect":
2288
+ case "withCtx":
2289
+ case "not":
2290
+ case "peek":
2291
+ return parserHasOwnFields(d.parser, seen);
2292
+ default:
2293
+ return false;
2294
+ }
2295
+ }
2296
+ function buildFieldMap(captures) {
2297
+ if (!captures?.length) return void 0;
2298
+ const out = {};
2299
+ for (const cap of captures) {
2300
+ const entry = { value: cap.value, span: cap.span };
2301
+ const current = out[cap.name];
2302
+ if (current === void 0) out[cap.name] = entry;
2303
+ else if (Array.isArray(current)) current.push(entry);
2304
+ else out[cap.name] = [current, entry];
2305
+ }
2306
+ return out;
2307
+ }
2308
+
2309
+ // src/combinators/case-fold.ts
2310
+ function canonical(ch) {
2311
+ const u = ch.toUpperCase();
2312
+ if (u.length !== 1) return ch;
2313
+ if (ch.codePointAt(0) >= 128 && u.codePointAt(0) < 128) return ch;
2314
+ return u;
2315
+ }
2316
+ var foldIndex = null;
2317
+ function buildFoldIndex() {
2318
+ const byCanonical = /* @__PURE__ */ new Map();
2319
+ for (let cp = 0; cp < 65536; cp++) {
2320
+ if (cp >= 55296 && cp <= 57343) continue;
2321
+ const key = canonical(String.fromCharCode(cp));
2322
+ const bucket = byCanonical.get(key);
2323
+ if (bucket) bucket.push(cp);
2324
+ else byCanonical.set(key, [cp]);
2325
+ }
2326
+ const index = /* @__PURE__ */ new Map();
2327
+ for (const members of byCanonical.values()) {
2328
+ if (members.length < 2) continue;
2329
+ for (const cp of members) index.set(cp, members);
2330
+ }
2331
+ return index;
2332
+ }
2333
+ function caseFoldVariants(cp) {
2334
+ if (cp < 128) {
2335
+ if (cp >= 65 && cp <= 90) return [cp, cp + 32];
2336
+ if (cp >= 97 && cp <= 122) return [cp, cp - 32];
2337
+ return [cp];
2338
+ }
2339
+ if (cp > 65535) return [cp];
2340
+ foldIndex ??= buildFoldIndex();
2341
+ return foldIndex.get(cp) ?? [cp];
2342
+ }
2343
+
2344
+ // src/combinators/keywords.ts
2345
+ function escapeRe(s) {
2346
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2347
+ }
2348
+ function keywords(words, opts = {}) {
2349
+ const sorted = [...new Set(words)].sort((a, b) => b.length - a.length);
2350
+ const alt = sorted.map(escapeRe).join("|");
2351
+ const boundary = opts.boundary ? `(?![${opts.boundary}])` : "";
2352
+ const flags = opts.caseInsensitive ? "iy" : "uy";
2353
+ const re = new RegExp(`(?:${alt})${boundary}`, flags);
2354
+ let firstSet = empty();
2355
+ for (const w of sorted) {
2356
+ if (w.length === 0) continue;
2357
+ const cp = w.codePointAt(0);
2358
+ firstSet = union(firstSet, fromChar(cp));
2359
+ if (opts.caseInsensitive) {
2360
+ for (const v of caseFoldVariants(cp)) firstSet = union(firstSet, fromChar(v));
2361
+ }
2362
+ }
2363
+ const meta = { firstSet, canMatchNewline: false, isTrivia: false };
2364
+ return {
2365
+ _tag: "keywords",
2366
+ _meta: meta,
2367
+ _def: { tag: "keywords", words: sorted, caseInsensitive: opts.caseInsensitive ?? false, boundary: opts.boundary },
2368
+ parse(input, pos, ctx) {
2369
+ re.lastIndex = pos;
2370
+ const m = re.exec(input);
2371
+ if (m === null || m.index !== pos) {
2372
+ return failAt(ctx, ["keyword"], pos);
2373
+ }
2374
+ const value = m[0];
2375
+ const span = { start: pos, end: pos + value.length };
2376
+ if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
2377
+ return { ok: true, value, span };
2378
+ }
2379
+ };
2380
+ }
2381
+
2382
+ // src/combinators/attempt.ts
2383
+ function attempt(parser2) {
2384
+ const guardable = parser2._meta.firstSet.kind !== "any" && !matchesEmpty(parser2);
2385
+ let failExpected;
2386
+ return {
2387
+ _tag: "attempt",
2388
+ _meta: parser2._meta,
2389
+ _def: { tag: "attempt", parser: parser2 },
2390
+ parse(input, pos, ctx) {
2391
+ if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(parser2, input, pos)) {
2392
+ if (failExpected === void 0) {
2393
+ const e = deriveExpected(parser2);
2394
+ failExpected = e.length > 0 ? e : [parser2._tag];
2395
+ }
2396
+ return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
2397
+ }
2398
+ const mark = saveCstMark(ctx);
2399
+ const log = ctx._triviaLog?.length;
2400
+ const result = parser2.parse(input, pos, ctx);
2401
+ if (result.ok) return result;
2402
+ rollbackCstCapture(ctx, mark);
2403
+ if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
2404
+ return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
2405
+ }
2406
+ };
2407
+ }
2408
+
2409
+ // src/combinators/not.ts
2410
+ function not(combinator) {
2411
+ const meta = {
2412
+ firstSet: any(),
2413
+ // we don't know what NOT matches
2414
+ canMatchNewline: false,
2415
+ isTrivia: false
2416
+ };
2417
+ return {
2418
+ _tag: "not",
2419
+ _meta: meta,
2420
+ _def: { tag: "not", parser: combinator },
2421
+ parse(input, pos, ctx) {
2422
+ const mark = saveLookaheadMark(ctx);
2423
+ const result = combinator.parse(input, pos, ctx);
2424
+ rollbackLookahead(ctx, mark);
2425
+ if (result.ok) {
2426
+ return { ok: false, expected: [`not(${combinator._tag})`], span: { start: pos, end: pos } };
2427
+ }
2428
+ return { ok: true, value: null, span: { start: pos, end: pos } };
2429
+ }
2430
+ };
2431
+ }
2432
+
2433
+ // src/combinators/peek.ts
2434
+ function peek(combinator) {
2435
+ const meta = {
2436
+ // A nullable body imposes no first-char constraint — `any()`, not its set.
2437
+ firstSet: matchesEmpty(combinator) ? any() : combinator._meta.firstSet,
2438
+ canMatchNewline: false,
2439
+ isTrivia: false
2440
+ };
2441
+ return {
2442
+ _tag: "peek",
2443
+ _meta: meta,
2444
+ _def: { tag: "peek", parser: combinator },
2445
+ parse(input, pos, ctx) {
2446
+ const mark = saveLookaheadMark(ctx);
2447
+ const result = combinator.parse(input, pos, ctx);
2448
+ rollbackLookahead(ctx, mark);
2449
+ if (result.ok) return { ok: true, value: null, span: { start: pos, end: pos } };
2450
+ return { ok: false, expected: [`peek(${combinator._tag})`], span: { start: pos, end: pos } };
2451
+ }
2452
+ };
2453
+ }
2454
+
2455
+ // src/combinators/node.ts
2456
+ function unwrapChild(child) {
2457
+ return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
2458
+ }
2459
+ function isCstChild(value) {
2460
+ return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "parseError");
2461
+ }
2462
+ function missingInferredType() {
2463
+ throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
2464
+ }
2465
+ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
2466
+ const hasExplicitType = typeof typeOrCombinator === "string";
2467
+ const type = hasExplicitType ? typeOrCombinator : void 0;
2468
+ const combinator = hasExplicitType ? combinatorOrBuild : typeOrCombinator;
2469
+ const build = hasExplicitType ? buildOrOpts : combinatorOrBuild;
2470
+ const opts = hasExplicitType ? maybeOpts : buildOrOpts;
2471
+ const baseDef = { tag: "node", parser: combinator, ...type === void 0 ? {} : { type }, ...build === void 0 ? {} : { build } };
2472
+ const meta = {
2473
+ firstSet: combinator._meta.firstSet,
2474
+ canMatchNewline: combinator._meta.canMatchNewline,
2475
+ isTrivia: false
2476
+ };
2477
+ const unwrap = opts?.unwrap === true;
2478
+ const collapse = opts?.collapse === true;
2479
+ const captureTrivia = opts?.captureTrivia === true;
2480
+ const trailingTrivia = opts?.trailingTrivia === true;
2481
+ if (unwrap && collapse) {
2482
+ throw new Error("node() options cannot set both unwrap and collapse");
2483
+ }
2484
+ const def = unwrap || collapse || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
2485
+ const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : true);
2486
+ const clonesState = build ? buildReadsState(def) : true;
2487
+ const hasOwnFields = parserHasOwnFields(combinator);
2488
+ const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : true);
2489
+ const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
2490
+ let failExpected;
2491
+ return {
2492
+ _tag: "node",
2493
+ _meta: meta,
2494
+ _def: def,
2495
+ parse(input, pos, ctx) {
2496
+ if (guardable && ctx._probe === void 0 && !ctx._tolerant && !startsFirstSet(combinator, input, pos)) {
2497
+ if (failExpected === void 0) {
2498
+ const e = deriveExpected(combinator);
2499
+ failExpected = e.length > 0 ? e : [combinator._tag];
2500
+ }
2501
+ return { ok: false, expected: failExpected, span: { start: pos, end: pos } };
2502
+ }
2503
+ const hostCst = build !== void 0 && cstOutputHost(ctx.build);
2504
+ const effTrivia = capturesTrivia || hostCst;
2505
+ const effFields = capturesFields || hostCst && hasOwnFields;
2506
+ const saved = beginCstNodeCapture(ctx);
2507
+ const savedFields = ctx._fields;
2508
+ ctx._fields = effFields ? [] : void 0;
2509
+ const savedMask = ctx._triviaCaptureMask;
2510
+ if (build === void 0 && ctx.build?._parsemanTriviaKinds !== void 0 && def.type !== void 0) {
2511
+ ctx._triviaCaptureMask = ctx.build._parsemanTriviaKinds(def.type);
2512
+ }
2513
+ if (!effTrivia) ctx.captureTrivia = false;
2514
+ let r = combinator.parse(input, pos, ctx);
2515
+ if (r.ok && trailingTrivia && ctx.trivia) {
2516
+ const end = consumeTrivia(input, r.span.end, ctx);
2517
+ r = { ...r, span: { start: r.span.start, end } };
2518
+ }
2519
+ const fields = effFields ? buildFieldMap(ctx._fields) : void 0;
2520
+ ctx._fields = savedFields;
2521
+ ctx._triviaCaptureMask = savedMask;
2522
+ const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
2523
+ if (!r.ok) return r;
2524
+ const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
2525
+ const nodeType = def.type ?? missingInferredType();
2526
+ const cstOutput = cstOutputHost(ctx.build);
2527
+ const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
2528
+ const built = unwrap && children.length === 1 ? unwrapChild(children[0]) : collapse && children.length === 1 ? children[0] : !build && ctx.build?._parsemanCstCollapse && children.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children[0], children, rawChildren) ? children[0] : build ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, r.span, rawChildren, triviaLog, hostState) : build(children, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children };
2529
+ const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span: r.span };
2530
+ if (saved.buf !== void 0 || saved.ch !== void 0) {
2531
+ pushCstChild(ctx, built, rawEntry);
2532
+ }
2533
+ return { ok: true, value: built, span: r.span };
2534
+ }
2535
+ };
2536
+ }
2537
+
2538
+ // src/compiler/line-index.ts
2539
+ function buildLineIndex(input) {
2540
+ const lineStarts = [0];
2541
+ for (let i = 0; i < input.length; i++) {
2542
+ if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
2543
+ }
2544
+ return { lineStarts };
2545
+ }
2546
+ function offsetToLineCol(index, offset) {
2547
+ const { lineStarts } = index;
2548
+ let lo = 0;
2549
+ let hi = lineStarts.length - 1;
2550
+ while (lo < hi) {
2551
+ const mid = lo + hi + 1 >> 1;
2552
+ if (lineStarts[mid] <= offset) lo = mid;
2553
+ else hi = mid - 1;
2554
+ }
2555
+ return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
2556
+ }
2557
+ function annotateSpan(span, index) {
2558
+ const s = offsetToLineCol(index, span.start);
2559
+ const e = offsetToLineCol(index, span.end);
2560
+ return {
2561
+ ...span,
2562
+ startLine: s.line,
2563
+ startColumn: s.col,
2564
+ endLine: e.line,
2565
+ endColumn: e.col
2566
+ };
2567
+ }
2568
+
2569
+ // src/combinators/grammar.ts
2570
+ function parser(opts, root) {
2571
+ const clearTrivia = opts.trivia === null;
2572
+ return {
2573
+ _tag: "grammar",
2574
+ _meta: root._meta,
2575
+ _def: {
2576
+ tag: "grammar",
2577
+ parser: root,
2578
+ triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
2579
+ clearTrivia,
2580
+ ...opts.captureTrivia ? { captureTrivia: true } : {},
2581
+ trackLines: opts.trackLines ?? false
2582
+ },
2583
+ parse(input, pos, _ctx) {
2584
+ const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
2585
+ const ctx = {
2586
+ ..._ctx,
2587
+ trackLines,
2588
+ // trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
2589
+ ...clearTrivia ? {
2590
+ trivia: void 0,
2591
+ triviaKindLabels: void 0
2592
+ } : opts.trivia != null ? {
2593
+ trivia: opts.trivia,
2594
+ ...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
2595
+ } : {},
2596
+ ...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
2597
+ // Kind-filter for per-node capture. Resolve against this scope's trivia
2598
+ // labels — this parser's own trivia if it declares one, else the INHERITED
2599
+ // labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
2600
+ // trivia is inherited rather than re-declared here. No labels → undefined
2601
+ // (capture all).
2602
+ ...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
2603
+ };
2604
+ const result = root.parse(input, pos ?? 0, ctx);
2605
+ if (trackLines) {
2606
+ const idx = buildLineIndex(input);
2607
+ return { ...result, span: annotateSpan(result.span, idx) };
2608
+ }
2609
+ return result;
2610
+ }
2611
+ };
2612
+ }
2613
+
2614
+ // src/combinators/token.ts
2615
+ function token(root) {
2616
+ const meta = {
2617
+ firstSet: root._meta.firstSet,
2618
+ canMatchNewline: root._meta.canMatchNewline,
2619
+ isTrivia: false
2620
+ };
2621
+ return {
2622
+ _tag: "token",
2623
+ _meta: meta,
2624
+ _def: { tag: "token", parser: root },
2625
+ parse(input, pos, ctx) {
2626
+ const savedTrivia = ctx.trivia;
2627
+ const savedKinds = ctx.triviaKindLabels;
2628
+ const savedBuf = ctx._cstBuf;
2629
+ const savedChildren = ctx._cstChildren;
2630
+ const savedLeaves = ctx._cstLeaves;
2631
+ const savedRaw = ctx._cstRawChildren;
2632
+ const savedTriviaLog = ctx._cstTriviaLog;
2633
+ const savedOuterTriviaLog = ctx._triviaLog;
2634
+ const wasCapturing = cstCaptureActive(ctx);
2635
+ ctx.trivia = void 0;
2636
+ ctx.triviaKindLabels = void 0;
2637
+ ctx._cstBuf = void 0;
2638
+ ctx._cstChildren = void 0;
2639
+ ctx._cstLeaves = void 0;
2640
+ ctx._cstRawChildren = void 0;
2641
+ ctx._cstTriviaLog = void 0;
2642
+ delete ctx._triviaLog;
2643
+ let result;
2644
+ try {
2645
+ result = root.parse(input, pos, ctx);
2646
+ } finally {
2647
+ ctx.trivia = savedTrivia;
2648
+ ctx.triviaKindLabels = savedKinds;
2649
+ ctx._cstBuf = savedBuf;
2650
+ ctx._cstChildren = savedChildren;
2651
+ ctx._cstLeaves = savedLeaves;
2652
+ ctx._cstRawChildren = savedRaw;
2653
+ ctx._cstTriviaLog = savedTriviaLog;
2654
+ if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
2655
+ else ctx._triviaLog = savedOuterTriviaLog;
2656
+ }
2657
+ if (!result.ok) return result;
2658
+ const span = result.span;
2659
+ const value = input.slice(pos, span.end);
2660
+ if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
2661
+ return { ok: true, value, span };
2662
+ }
2663
+ };
2664
+ }
2665
+ function leaf(root, fn) {
2666
+ const meta = {
2667
+ firstSet: root._meta.firstSet,
2668
+ canMatchNewline: root._meta.canMatchNewline,
2669
+ isTrivia: false
2670
+ };
2671
+ return {
2672
+ _tag: "leaf",
2673
+ _meta: meta,
2674
+ _def: { tag: "leaf", parser: root, fn },
2675
+ parse(input, pos, ctx) {
2676
+ const savedBuf = ctx._cstBuf;
2677
+ const savedChildren = ctx._cstChildren;
2678
+ const savedLeaves = ctx._cstLeaves;
2679
+ const savedRaw = ctx._cstRawChildren;
2680
+ const savedTriviaLog = ctx._cstTriviaLog;
2681
+ const savedOuterTriviaLog = ctx._triviaLog;
2682
+ const wasCapturing = cstCaptureActive(ctx);
2683
+ ctx._cstBuf = void 0;
2684
+ ctx._cstChildren = void 0;
2685
+ ctx._cstLeaves = void 0;
2686
+ ctx._cstRawChildren = void 0;
2687
+ ctx._cstTriviaLog = void 0;
2688
+ delete ctx._triviaLog;
2689
+ let result;
2690
+ try {
2691
+ result = root.parse(input, pos, ctx);
2692
+ } finally {
2693
+ ctx._cstBuf = savedBuf;
2694
+ ctx._cstChildren = savedChildren;
2695
+ ctx._cstLeaves = savedLeaves;
2696
+ ctx._cstRawChildren = savedRaw;
2697
+ ctx._cstTriviaLog = savedTriviaLog;
2698
+ if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
2699
+ else ctx._triviaLog = savedOuterTriviaLog;
2700
+ }
2701
+ if (!result.ok) return result;
2702
+ const value = fn(result.value, result.span);
2703
+ if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span: result.span });
2704
+ return { ok: true, value, span: result.span };
2705
+ }
2706
+ };
2707
+ }
2708
+
2709
+ // src/combinators/withCtx.ts
2710
+ function withCtx(extra, combinator) {
2711
+ const meta = {
2712
+ firstSet: combinator._meta.firstSet,
2713
+ canMatchNewline: combinator._meta.canMatchNewline,
2714
+ isTrivia: false
2715
+ };
2716
+ return {
2717
+ _tag: "withCtx",
2718
+ _meta: meta,
2719
+ _def: { tag: "withCtx", extra, parser: combinator },
2720
+ parse(input, pos, ctx) {
2721
+ return combinator.parse(input, pos, { ...ctx, state: extra });
2722
+ }
2723
+ };
2724
+ }
2725
+
2726
+ // src/compiler/ir-serialize.ts
2727
+ function evalRuleMapIR(ir) {
2728
+ const _tf = (child, src, recognitionOnly = false) => {
2729
+ let fn2;
2730
+ try {
2731
+ fn2 = (0, eval)(`(${src})`);
2732
+ } catch {
2733
+ fn2 = () => {
2734
+ throw new Error("IR transform fn not materialized");
2735
+ };
2736
+ }
2737
+ const t = transform(child, fn2);
2738
+ t._def.fnSrc = src;
2739
+ if (recognitionOnly) t._def.recognitionOnly = true;
2740
+ return t;
2741
+ };
2742
+ const _lf = (child, src) => {
2743
+ let fn2;
2744
+ try {
2745
+ fn2 = (0, eval)(`(${src})`);
2746
+ } catch {
2747
+ fn2 = () => {
2748
+ throw new Error("IR leaf fn not materialized");
2749
+ };
2750
+ }
2751
+ const l = leaf(child, fn2);
2752
+ l._def.fnSrc = src;
2753
+ return l;
2754
+ };
2755
+ const _nd = (type, child, src, opts, staticError) => {
2756
+ if (staticError !== void 0 && staticError.length > 0) {
2757
+ throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
2758
+ }
2759
+ const n = node(type, child, (() => {
2760
+ throw new Error("IR node build requires static re-lowering");
2761
+ }), opts);
2762
+ n._def.buildSrc = src;
2763
+ if (staticError !== void 0) n._def.buildStaticError = staticError;
2764
+ return n;
2765
+ };
2766
+ const _gch = (items) => {
2767
+ const gateSrcs = [];
2768
+ const arms = items.map((it) => {
2769
+ if (Array.isArray(it)) {
2770
+ const [src, comb] = it;
2771
+ gateSrcs.push(src);
2772
+ let gate;
2773
+ try {
2774
+ gate = (0, eval)(`(${src})`);
2775
+ } catch {
2776
+ gate = () => {
2777
+ throw new Error("IR gate fn not materialized");
2778
+ };
2779
+ }
2780
+ return { gate, combinator: comb };
2781
+ }
2782
+ gateSrcs.push(null);
2783
+ return it;
2784
+ });
2785
+ const c = choice(...arms);
2786
+ const gates = c._def.gates;
2787
+ if (gates && gates.length !== gateSrcs.length) {
2788
+ throw new Error(`_gch: gateSrcs length ${gateSrcs.length} != choice gates length ${gates.length}`);
2789
+ }
2790
+ ;
2791
+ c._def.gateSrcs = gateSrcs;
2792
+ return c;
2793
+ };
2794
+ const _wc = (src, inner) => {
2795
+ let extra;
2796
+ try {
2797
+ extra = (0, eval)(`(${src})`);
2798
+ } catch {
2799
+ extra = void 0;
2800
+ }
2801
+ const w = withCtx(extra, inner);
2802
+ w._def.extraSrc = src;
2803
+ return w;
2804
+ };
2805
+ const fn = new Function(
2806
+ "rules",
2807
+ "ref",
2808
+ "regex",
2809
+ "literal",
2810
+ "keywords",
2811
+ "sequence",
2812
+ "choice",
2813
+ "attempt",
2814
+ "many",
2815
+ "oneOrMore",
2816
+ "optional",
2817
+ "sepBy",
2818
+ "not",
2819
+ "peek",
2820
+ "node",
2821
+ "parser",
2822
+ "scanTo",
2823
+ "token",
2824
+ "leaf",
2825
+ "transform",
2826
+ "skip",
2827
+ "trivia",
2828
+ "label",
2829
+ "field",
2830
+ "expect",
2831
+ "_tf",
2832
+ "_lf",
2833
+ "_nd",
2834
+ "_gch",
2835
+ "_wc",
2836
+ `return (${ir})`
2837
+ );
2838
+ const map = fn(
2839
+ rules,
2840
+ ref,
2841
+ regex,
2842
+ literal,
2843
+ keywords,
2844
+ sequence,
2845
+ choice,
2846
+ attempt,
2847
+ many,
2848
+ oneOrMore,
2849
+ optional,
2850
+ sepBy,
2851
+ not,
2852
+ peek,
2853
+ node,
2854
+ parser,
2855
+ scanTo,
2856
+ token,
2857
+ leaf,
2858
+ transform,
2859
+ skip,
2860
+ trivia,
2861
+ label,
2862
+ field,
2863
+ expect,
2864
+ _tf,
2865
+ _lf,
2866
+ _nd,
2867
+ _gch,
2868
+ _wc
2869
+ );
2870
+ return Object.entries(map);
2871
+ }
2872
+
2873
+ // src/compiler/linker.ts
2874
+ function normalizeCstCollapse(collapse) {
2875
+ if (collapse === true) return () => true;
2876
+ if (Array.isArray(collapse)) {
2877
+ const types = new Set(collapse);
2878
+ return (type) => types.has(type);
2879
+ }
2880
+ return typeof collapse === "function" ? collapse : void 0;
2881
+ }
2882
+ function buildCstNode(type, children, _fields, span, _rawChildren, _triviaLog, state) {
2883
+ return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children] };
2884
+ }
2885
+ function cstBuildHost(typeOrOptions, children, _fields, span, rawChildren, triviaLog, state) {
2886
+ if (typeof typeOrOptions === "string") {
2887
+ return buildCstNode(typeOrOptions, children ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
2888
+ }
2889
+ const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
2890
+ const host = (type, children2, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children2 ?? [], fields, span2, rawChildren2, triviaLog2, state2);
2891
+ host._parsemanCstOutput = true;
2892
+ if (collapse) host._parsemanCstCollapse = collapse;
2893
+ return host;
2894
+ }
2895
+ cstBuildHost._parsemanCstOutput = true;
2896
+ var COMPOSED_PIECES = /* @__PURE__ */ Symbol.for("parseman.composedPieces");
2897
+ function composedPiecesOf(grammar) {
2898
+ const pieces = grammar[COMPOSED_PIECES];
2899
+ return Array.isArray(pieces) ? pieces : void 0;
2900
+ }
2901
+ function isIRPiece(p) {
2902
+ return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
2903
+ }
2904
+ function carriedRuleMapsDetailed(carried) {
2905
+ const maps = [];
2906
+ const opaque = [];
2907
+ for (const p of carried) {
2908
+ if (isIRPiece(p)) {
2909
+ maps.push(evalRuleMapIR(p.ir));
2910
+ continue;
2911
+ }
2912
+ const ruleFns = p.ruleFns;
2913
+ opaque.push({ ns: p.ns, ruleNames: ruleFns instanceof Map ? [...ruleFns.keys()] : [] });
2914
+ }
2915
+ return { maps, opaque };
2916
+ }
2917
+ function recoverComposedRules(grammar) {
2918
+ const carried = composedPiecesOf(grammar);
2919
+ if (carried === void 0) return void 0;
2920
+ const { maps, opaque } = carriedRuleMapsDetailed(carried);
2921
+ const rules2 = /* @__PURE__ */ new Map();
2922
+ for (const map of maps) for (const [name, rule] of map) {
2923
+ if (rule._def.tag === "lazy") {
2924
+ try {
2925
+ rule._def.thunk();
2926
+ } catch {
2927
+ continue;
2928
+ }
2929
+ }
2930
+ rules2.set(name, rule);
2931
+ }
2932
+ return { rules: rules2, opaque };
2933
+ }
3
2934
 
4
2935
  // src/spec/model.ts
5
- function ruleNameOf(c) {
2936
+ function ruleNameOf2(c) {
6
2937
  return c._ruleName;
7
2938
  }
8
2939
  function resolveLazy(c) {
@@ -67,7 +2998,7 @@ var Builder = class {
67
2998
  if (pinned !== void 0) return { kind: "terminal", text: pinned, literal: false };
68
2999
  let c = comb;
69
3000
  const guard = /* @__PURE__ */ new Set();
70
- while (c._def.tag === "lazy" && ruleNameOf(c) === name && !guard.has(c)) {
3001
+ while (c._def.tag === "lazy" && ruleNameOf2(c) === name && !guard.has(c)) {
71
3002
  guard.add(c);
72
3003
  const next = resolveLazy(c);
73
3004
  if (!next) break;
@@ -77,7 +3008,7 @@ var Builder = class {
77
3008
  }
78
3009
  /** Walk any combinator. `isRuleRoot` suppresses treating it as a self-reference. */
79
3010
  walk(c, isRuleRoot = false) {
80
- const rn = ruleNameOf(c);
3011
+ const rn = ruleNameOf2(c);
81
3012
  if (rn !== void 0 && !isRuleRoot) {
82
3013
  if (!this.record[rn]) this.record[rn] = c;
83
3014
  this.enqueue(rn, c);
@@ -194,9 +3125,19 @@ function flattenChoice(items) {
194
3125
  }
195
3126
  function toRecord(grammar) {
196
3127
  if (isCombinator(grammar)) {
197
- const name = ruleNameOf(grammar) ?? "start";
3128
+ const name = ruleNameOf2(grammar) ?? "start";
198
3129
  return { [name]: grammar };
199
3130
  }
3131
+ const recovered = recoverComposedRules(grammar);
3132
+ if (recovered !== void 0) {
3133
+ if (recovered.opaque.length > 0) {
3134
+ const named = recovered.opaque.map((o) => `"${o.ns}"${o.ruleNames.length > 0 ? ` (${o.ruleNames.length} rule(s))` : ""}`).join(", ");
3135
+ throw new TypeError(
3136
+ `parseman spec: this composed grammar includes opaque precompiled artifact(s) ${named} that carry compiled rule functions rather than re-lowerable IR. Their rules cannot be rendered, and emitting a spec without them would silently understate the grammar. Recompile the contributing grammar(s) so they carry IR.`
3137
+ );
3138
+ }
3139
+ return Object.fromEntries(recovered.rules);
3140
+ }
200
3141
  return grammar;
201
3142
  }
202
3143
  function isCombinator(x) {
@@ -262,25 +3203,25 @@ function repeatOp(min, max) {
262
3203
  if (min === 0 && max === 1) return "?";
263
3204
  return `{${min},${max}}`;
264
3205
  }
265
- function render(node) {
266
- switch (node.kind) {
3206
+ function render(node2) {
3207
+ switch (node2.kind) {
267
3208
  case "terminal":
268
- return { text: node.literal ? quote(node.text) : node.text, level: ATOM };
3209
+ return { text: node2.literal ? quote(node2.text) : node2.text, level: ATOM };
269
3210
  case "ref":
270
- return { text: node.name, level: ATOM };
3211
+ return { text: node2.name, level: ATOM };
271
3212
  case "empty":
272
3213
  return { text: "", level: ATOM };
273
3214
  case "annotation":
274
- return { text: `/* ${node.text} */`, level: ATOM };
3215
+ return { text: `/* ${node2.text} */`, level: ATOM };
275
3216
  case "seq": {
276
- const text = node.items.map((it) => {
3217
+ const text = node2.items.map((it) => {
277
3218
  const r = render(it);
278
3219
  return wrap(r.text, r.level, CAT);
279
3220
  }).filter((t) => t.length > 0).join(" ");
280
3221
  return { text, level: CAT };
281
3222
  }
282
3223
  case "choice": {
283
- const text = node.items.map((it) => {
3224
+ const text = node2.items.map((it) => {
284
3225
  const r = render(it);
285
3226
  return wrap(r.text, r.level, ALT);
286
3227
  }).join(" | ");
@@ -289,27 +3230,27 @@ function render(node) {
289
3230
  case "star":
290
3231
  case "plus":
291
3232
  case "opt": {
292
- const r = render(node.item);
293
- const op = node.kind === "opt" ? "?" : node.kind === "star" ? repeatOp(0, node.max) : repeatOp(node.min ?? 1, node.max);
3233
+ const r = render(node2.item);
3234
+ const op = node2.kind === "opt" ? "?" : node2.kind === "star" ? repeatOp(0, node2.max) : repeatOp(node2.min ?? 1, node2.max);
294
3235
  return { text: `${wrap(r.text, r.level, ATOM)}${op}`, level: ATOM };
295
3236
  }
296
3237
  case "sepBy": {
297
- const item = render(node.item);
298
- const sep = render(node.sep);
3238
+ const item = render(node2.item);
3239
+ const sep = render(node2.sep);
299
3240
  const itemA = wrap(item.text, item.level, ATOM);
300
3241
  const sepA = wrap(sep.text, sep.level, CAT);
301
- const tail = `(${sepA} ${itemA})${repeatOp(Math.max(node.min - 1, 0), node.max === void 0 ? void 0 : node.max - 1)}`;
302
- const trail = node.trailing === "allow" ? ` ${sepA}?` : "";
3242
+ const tail = `(${sepA} ${itemA})${repeatOp(Math.max(node2.min - 1, 0), node2.max === void 0 ? void 0 : node2.max - 1)}`;
3243
+ const trail = node2.trailing === "allow" ? ` ${sepA}?` : "";
303
3244
  const body = `${itemA} ${tail}${trail}`;
304
- return node.min === 0 ? { text: `(${body})?`, level: ATOM } : { text: body, level: CAT };
3245
+ return node2.min === 0 ? { text: `(${body})?`, level: ATOM } : { text: body, level: CAT };
305
3246
  }
306
3247
  case "not": {
307
- const r = render(node.item);
3248
+ const r = render(node2.item);
308
3249
  return { text: `!${wrap(r.text, r.level, ATOM)}`, level: ATOM };
309
3250
  }
310
3251
  // PEG notation: `&` positive lookahead, `!` negative.
311
3252
  case "peek": {
312
- const r = render(node.item);
3253
+ const r = render(node2.item);
313
3254
  return { text: `&${wrap(r.text, r.level, ATOM)}`, level: ATOM };
314
3255
  }
315
3256
  }
@@ -321,8 +3262,8 @@ function renderProduction(p) {
321
3262
  function renderEBNF(model) {
322
3263
  return model.productions.map(renderProduction).join("\n") + "\n";
323
3264
  }
324
- function renderExpr(node) {
325
- return render(node).text;
3265
+ function renderExpr(node2) {
3266
+ return render(node2).text;
326
3267
  }
327
3268
 
328
3269
  // src/spec/railroad-lib.ts
@@ -883,41 +3824,41 @@ function boundLabel(min, max) {
883
3824
  if (max === min) return `${min}\xD7`;
884
3825
  return `${min}\u2013${max} times`;
885
3826
  }
886
- function toDsl(node) {
887
- switch (node.kind) {
3827
+ function toDsl(node2) {
3828
+ switch (node2.kind) {
888
3829
  case "terminal":
889
- return `Terminal(${j(node.text)})`;
3830
+ return `Terminal(${j(node2.text)})`;
890
3831
  case "ref":
891
- return `NonTerminal(${j(node.name)})`;
3832
+ return `NonTerminal(${j(node2.name)})`;
892
3833
  case "empty":
893
3834
  return `Skip()`;
894
3835
  case "annotation":
895
- return `Comment(${j(node.text)})`;
3836
+ return `Comment(${j(node2.text)})`;
896
3837
  case "seq":
897
- return `Sequence(${node.items.map(toDsl).join(", ")})`;
3838
+ return `Sequence(${node2.items.map(toDsl).join(", ")})`;
898
3839
  case "choice":
899
- return `Choice(0, ${node.items.map(toDsl).join(", ")})`;
3840
+ return `Choice(0, ${node2.items.map(toDsl).join(", ")})`;
900
3841
  case "star": {
901
- const b = boundLabel(0, node.max);
902
- return b ? `ZeroOrMore(${toDsl(node.item)}, Comment(${j(b)}))` : `ZeroOrMore(${toDsl(node.item)})`;
3842
+ const b = boundLabel(0, node2.max);
3843
+ return b ? `ZeroOrMore(${toDsl(node2.item)}, Comment(${j(b)}))` : `ZeroOrMore(${toDsl(node2.item)})`;
903
3844
  }
904
3845
  case "plus": {
905
- const b = boundLabel(node.min ?? 1, node.max);
906
- return b ? `OneOrMore(${toDsl(node.item)}, Comment(${j(b)}))` : `OneOrMore(${toDsl(node.item)})`;
3846
+ const b = boundLabel(node2.min ?? 1, node2.max);
3847
+ return b ? `OneOrMore(${toDsl(node2.item)}, Comment(${j(b)}))` : `OneOrMore(${toDsl(node2.item)})`;
907
3848
  }
908
3849
  case "opt":
909
- return `Optional(${toDsl(node.item)})`;
3850
+ return `Optional(${toDsl(node2.item)})`;
910
3851
  case "sepBy": {
911
- const b = boundLabel(node.min, node.max);
912
- const loop = b ? `Sequence(${toDsl(node.sep)}, Comment(${j(b)}))` : toDsl(node.sep);
913
- const rep = `OneOrMore(${toDsl(node.item)}, ${loop})`;
914
- const withTrail = node.trailing === void 0 ? rep : `Sequence(${rep}, Optional(${toDsl(node.sep)}))`;
915
- return node.min === 0 ? `Optional(${withTrail})` : withTrail;
3852
+ const b = boundLabel(node2.min, node2.max);
3853
+ const loop = b ? `Sequence(${toDsl(node2.sep)}, Comment(${j(b)}))` : toDsl(node2.sep);
3854
+ const rep = `OneOrMore(${toDsl(node2.item)}, ${loop})`;
3855
+ const withTrail = node2.trailing === void 0 ? rep : `Sequence(${rep}, Optional(${toDsl(node2.sep)}))`;
3856
+ return node2.min === 0 ? `Optional(${withTrail})` : withTrail;
916
3857
  }
917
3858
  case "not":
918
- return `Sequence(Comment("not"), ${toDsl(node.item)})`;
3859
+ return `Sequence(Comment("not"), ${toDsl(node2.item)})`;
919
3860
  case "peek":
920
- return `Sequence(Comment("peek"), ${toDsl(node.item)})`;
3861
+ return `Sequence(Comment("peek"), ${toDsl(node2.item)})`;
921
3862
  }
922
3863
  }
923
3864
  var _builders = null;
@@ -928,41 +3869,41 @@ function builders() {
928
3869
  _builders = mod;
929
3870
  return _builders;
930
3871
  }
931
- function toDiagramNode(b, node) {
932
- switch (node.kind) {
3872
+ function toDiagramNode(b, node2) {
3873
+ switch (node2.kind) {
933
3874
  case "terminal":
934
- return b.Terminal(node.text);
3875
+ return b.Terminal(node2.text);
935
3876
  case "ref":
936
- return b.NonTerminal(node.name);
3877
+ return b.NonTerminal(node2.name);
937
3878
  case "empty":
938
3879
  return b.Skip();
939
3880
  case "annotation":
940
- return b.Comment(node.text);
3881
+ return b.Comment(node2.text);
941
3882
  case "seq":
942
- return b.Sequence(...node.items.map((n) => toDiagramNode(b, n)));
3883
+ return b.Sequence(...node2.items.map((n) => toDiagramNode(b, n)));
943
3884
  case "choice":
944
- return b.Choice(0, ...node.items.map((n) => toDiagramNode(b, n)));
3885
+ return b.Choice(0, ...node2.items.map((n) => toDiagramNode(b, n)));
945
3886
  case "star": {
946
- const lbl = boundLabel(0, node.max);
947
- return lbl ? b.ZeroOrMore(toDiagramNode(b, node.item), b.Comment(lbl)) : b.ZeroOrMore(toDiagramNode(b, node.item));
3887
+ const lbl = boundLabel(0, node2.max);
3888
+ return lbl ? b.ZeroOrMore(toDiagramNode(b, node2.item), b.Comment(lbl)) : b.ZeroOrMore(toDiagramNode(b, node2.item));
948
3889
  }
949
3890
  case "plus": {
950
- const lbl = boundLabel(node.min ?? 1, node.max);
951
- return lbl ? b.OneOrMore(toDiagramNode(b, node.item), b.Comment(lbl)) : b.OneOrMore(toDiagramNode(b, node.item));
3891
+ const lbl = boundLabel(node2.min ?? 1, node2.max);
3892
+ return lbl ? b.OneOrMore(toDiagramNode(b, node2.item), b.Comment(lbl)) : b.OneOrMore(toDiagramNode(b, node2.item));
952
3893
  }
953
3894
  case "opt":
954
- return b.Optional(toDiagramNode(b, node.item));
3895
+ return b.Optional(toDiagramNode(b, node2.item));
955
3896
  case "sepBy": {
956
- const lbl = boundLabel(node.min, node.max);
957
- const sep = toDiagramNode(b, node.sep);
958
- const rep = b.OneOrMore(toDiagramNode(b, node.item), lbl ? b.Sequence(sep, b.Comment(lbl)) : sep);
959
- const withTrail = node.trailing === void 0 ? rep : b.Sequence(rep, b.Optional(toDiagramNode(b, node.sep)));
960
- return node.min === 0 ? b.Optional(withTrail) : withTrail;
3897
+ const lbl = boundLabel(node2.min, node2.max);
3898
+ const sep = toDiagramNode(b, node2.sep);
3899
+ const rep = b.OneOrMore(toDiagramNode(b, node2.item), lbl ? b.Sequence(sep, b.Comment(lbl)) : sep);
3900
+ const withTrail = node2.trailing === void 0 ? rep : b.Sequence(rep, b.Optional(toDiagramNode(b, node2.sep)));
3901
+ return node2.min === 0 ? b.Optional(withTrail) : withTrail;
961
3902
  }
962
3903
  case "not":
963
- return b.Sequence(b.Comment("not"), toDiagramNode(b, node.item));
3904
+ return b.Sequence(b.Comment("not"), toDiagramNode(b, node2.item));
964
3905
  case "peek":
965
- return b.Sequence(b.Comment("peek"), toDiagramNode(b, node.item));
3906
+ return b.Sequence(b.Comment("peek"), toDiagramNode(b, node2.item));
966
3907
  }
967
3908
  }
968
3909
  function renderRailroadSvg(model) {