parseman 0.52.0 → 0.54.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 (108) hide show
  1. package/dist/analysis/diagnostics.js +636 -126
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +6191 -6274
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/combinators/field-trivia.d.ts +40 -0
  6. package/dist/combinators/field-trivia.d.ts.map +1 -0
  7. package/dist/combinators/map.d.ts +19 -2
  8. package/dist/combinators/map.d.ts.map +1 -1
  9. package/dist/combinators/parser.d.ts +34 -0
  10. package/dist/combinators/parser.d.ts.map +1 -1
  11. package/dist/combinators/ref.d.ts +0 -13
  12. package/dist/combinators/ref.d.ts.map +1 -1
  13. package/dist/combinators/repeat.d.ts.map +1 -1
  14. package/dist/combinators/sequence.d.ts.map +1 -1
  15. package/dist/compiler/borrowed-rules.d.ts +30 -0
  16. package/dist/compiler/borrowed-rules.d.ts.map +1 -0
  17. package/dist/compiler/compile-linkable-table.d.ts +1 -1
  18. package/dist/compiler/fields.d.ts +2 -0
  19. package/dist/compiler/fields.d.ts.map +1 -1
  20. package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
  21. package/dist/compiler/ir-serialize.d.ts +10 -4
  22. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  23. package/dist/compiler/linker.d.ts +48 -91
  24. package/dist/compiler/linker.d.ts.map +1 -1
  25. package/dist/coverage.d.ts +1 -1
  26. package/dist/coverage.d.ts.map +1 -1
  27. package/dist/cst/reflection.d.ts.map +1 -1
  28. package/dist/cst/trivia-charscan.d.ts +11 -3
  29. package/dist/cst/trivia-charscan.d.ts.map +1 -1
  30. package/dist/cst/trivia-kinds.d.ts +11 -0
  31. package/dist/cst/trivia-kinds.d.ts.map +1 -1
  32. package/dist/index.d.ts +1 -0
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +764 -888
  35. package/dist/index.js.map +3 -3
  36. package/dist/language-service/index.js.map +1 -1
  37. package/dist/plugin/evaluator.d.ts +38 -2
  38. package/dist/plugin/evaluator.d.ts.map +1 -1
  39. package/dist/plugin/index.d.ts.map +1 -1
  40. package/dist/plugin/index.js +1443 -729
  41. package/dist/plugin/index.js.map +3 -3
  42. package/dist/plugin/ir-eval.d.ts +21 -0
  43. package/dist/plugin/ir-eval.d.ts.map +1 -0
  44. package/dist/plugin/reducer-resolver.d.ts +6 -0
  45. package/dist/plugin/reducer-resolver.d.ts.map +1 -1
  46. package/dist/spec/index.js +555 -6109
  47. package/dist/spec/index.js.map +3 -3
  48. package/dist/spec/railroad-lib.d.ts +7 -2
  49. package/dist/spec/railroad-lib.d.ts.map +1 -1
  50. package/dist/spec/railroad.d.ts.map +1 -1
  51. package/dist/table/assemble.d.ts +9 -0
  52. package/dist/table/assemble.d.ts.map +1 -1
  53. package/dist/table/compile-rule-map.d.ts +11 -4
  54. package/dist/table/compile-rule-map.d.ts.map +1 -1
  55. package/dist/table/compile.d.ts +16 -0
  56. package/dist/table/compile.d.ts.map +1 -1
  57. package/dist/table/emit-assembly.d.ts +1 -1
  58. package/dist/table/emit-assembly.d.ts.map +1 -1
  59. package/dist/table/emit.d.ts +6 -2
  60. package/dist/table/emit.d.ts.map +1 -1
  61. package/dist/table/encode.d.ts.map +1 -1
  62. package/dist/table/exec.d.ts.map +1 -1
  63. package/dist/table/field-spec.d.ts +13 -0
  64. package/dist/table/field-spec.d.ts.map +1 -0
  65. package/dist/table/index.js +480 -199
  66. package/dist/table/index.js.map +2 -2
  67. package/dist/table/scalar-terminal.d.ts +11 -0
  68. package/dist/table/scalar-terminal.d.ts.map +1 -1
  69. package/dist/types.d.ts +14 -0
  70. package/dist/types.d.ts.map +1 -1
  71. package/dist/version.d.ts +1 -1
  72. package/package.json +1 -1
  73. package/src/analysis/duplication.ts +1 -1
  74. package/src/analysis/rebuild.ts +1 -1
  75. package/src/combinators/field-trivia.ts +44 -0
  76. package/src/combinators/map.ts +48 -6
  77. package/src/combinators/parser.ts +133 -67
  78. package/src/combinators/ref.ts +10 -1
  79. package/src/combinators/repeat.ts +6 -1
  80. package/src/combinators/sequence.ts +9 -1
  81. package/src/compiler/borrowed-rules.ts +88 -0
  82. package/src/compiler/compile-linkable-table.ts +1 -1
  83. package/src/compiler/fields.ts +5 -2
  84. package/src/compiler/grammar-coverage-ids.ts +35 -6
  85. package/src/compiler/ir-serialize.ts +19 -119
  86. package/src/compiler/linker.ts +190 -666
  87. package/src/coverage.ts +7 -5
  88. package/src/cst/reflection.ts +6 -1
  89. package/src/cst/trivia-charscan.ts +17 -56
  90. package/src/cst/trivia-kinds.ts +24 -8
  91. package/src/index.ts +1 -0
  92. package/src/plugin/evaluator.ts +114 -14
  93. package/src/plugin/index.ts +588 -110
  94. package/src/plugin/ir-eval.ts +165 -0
  95. package/src/plugin/reducer-resolver.ts +20 -3
  96. package/src/spec/railroad-lib.ts +18 -8
  97. package/src/spec/railroad.ts +3 -4
  98. package/src/table/assemble.ts +126 -22
  99. package/src/table/compile-rule-map.ts +18 -8
  100. package/src/table/compile.ts +61 -0
  101. package/src/table/emit-assembly.ts +38 -18
  102. package/src/table/emit.ts +15 -4
  103. package/src/table/encode.ts +18 -2
  104. package/src/table/exec.ts +15 -1
  105. package/src/table/field-spec.ts +17 -0
  106. package/src/table/scalar-terminal.ts +25 -0
  107. package/src/types.ts +12 -2
  108. package/src/version.ts +1 -1
@@ -1155,65 +1155,17 @@ function plainRegexSource(p) {
1155
1155
  const d = p._def;
1156
1156
  return d.tag === "regex" && d.flags === "" ? d.source : null;
1157
1157
  }
1158
- var visitSpec0;
1159
- var visitSpec1;
1160
- var visitSpec2;
1161
- var visitSpec3;
1162
- var visitValue0;
1163
- var visitValue1;
1164
- var visitValue2;
1165
- var visitValue3;
1166
1158
  function commonLabeledTriviaVisitor(spec) {
1167
- if (spec === visitSpec0) return visitValue0;
1168
- if (spec === visitSpec1) return visitValue1;
1169
- if (spec === visitSpec2) return visitValue2;
1170
- if (spec === visitSpec3) return visitValue3;
1171
- const sources = spec.minRepeats <= 1 ? spec.arms.map((arm) => plainRegexSource(arm.parser)) : [];
1172
- const visitor = commonCssTriviaVisitor(sources);
1173
- visitSpec3 = visitSpec2;
1174
- visitValue3 = visitValue2;
1175
- visitSpec2 = visitSpec1;
1176
- visitValue2 = visitValue1;
1177
- visitSpec1 = visitSpec0;
1178
- visitValue1 = visitValue0;
1179
- visitSpec0 = spec;
1180
- visitValue0 = visitor;
1181
- return visitor;
1182
- }
1183
- var armSpec0;
1184
- var armSpec1;
1185
- var armSpec2;
1186
- var armSpec3;
1187
- var armValue0;
1188
- var armValue1;
1189
- var armValue2;
1190
- var armValue3;
1159
+ return commonCssTriviaVisitor(spec.minRepeats <= 1 ? spec.arms.map((arm) => plainRegexSource(arm.parser)) : []);
1160
+ }
1191
1161
  function charArmsFor(spec) {
1192
- if (spec === armSpec0) return armValue0;
1193
- if (spec === armSpec1) return armValue1;
1194
- if (spec === armSpec2) return armValue2;
1195
- if (spec === armSpec3) return armValue3;
1196
- let arms = [];
1197
- if (spec.minRepeats > 1) {
1198
- arms = null;
1199
- } else {
1200
- for (const arm of spec.arms) {
1201
- const c = classifyParser(arm.parser);
1202
- if (!c) {
1203
- arms = null;
1204
- break;
1205
- }
1206
- arms.push(c);
1207
- }
1162
+ if (spec.minRepeats > 1) return null;
1163
+ const arms = [];
1164
+ for (const arm of spec.arms) {
1165
+ const c = classifyParser(arm.parser);
1166
+ if (!c) return null;
1167
+ arms.push(c);
1208
1168
  }
1209
- armSpec3 = armSpec2;
1210
- armValue3 = armValue2;
1211
- armSpec2 = armSpec1;
1212
- armValue2 = armValue1;
1213
- armSpec1 = armSpec0;
1214
- armValue1 = armValue0;
1215
- armSpec0 = spec;
1216
- armValue0 = arms;
1217
1169
  return arms;
1218
1170
  }
1219
1171
  function charTriviaEnd(input, cur, arms) {
@@ -1329,12 +1281,16 @@ function analyzeLabeledTrivia(trivia2) {
1329
1281
  }
1330
1282
  arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
1331
1283
  }
1332
- const spec = {
1284
+ return cacheLabeledTrivia(trivia2, labeledTriviaSpec(arms, minRepeats));
1285
+ }
1286
+ function labeledTriviaSpec(arms, minRepeats) {
1287
+ return {
1333
1288
  labels: arms.map((a) => a.label),
1334
1289
  arms,
1335
- minRepeats
1290
+ minRepeats,
1291
+ visitor: commonLabeledTriviaVisitor({ arms, minRepeats }),
1292
+ charArms: charArmsFor({ arms, minRepeats })
1336
1293
  };
1337
- return cacheLabeledTrivia(trivia2, spec);
1338
1294
  }
1339
1295
  function matchArmAt(input, pos, arm, state) {
1340
1296
  if (!startsFirstSet(arm, input, pos)) return null;
@@ -1364,7 +1320,7 @@ function scanLabeledTriviaChunks(input, cur, spec, state) {
1364
1320
  return { end: pos, chunks };
1365
1321
  }
1366
1322
  function scanLabeledTriviaEnd(input, cur, spec, state) {
1367
- const chars = charArmsFor(spec);
1323
+ const chars = spec.charArms;
1368
1324
  if (chars !== null) return charTriviaEnd(input, cur, chars);
1369
1325
  let pos = cur;
1370
1326
  let count = 0;
@@ -1382,9 +1338,9 @@ function scanLabeledTriviaEnd(input, cur, spec, state) {
1382
1338
  }
1383
1339
  function visitLabeledTrivia(input, cur, spec, state, visit) {
1384
1340
  if (spec.minRepeats > 1) return void 0;
1385
- const common = commonLabeledTriviaVisitor(spec);
1341
+ const common = spec.visitor;
1386
1342
  if (common !== null) return common(input, cur, visit);
1387
- const chars = charArmsFor(spec);
1343
+ const chars = spec.charArms;
1388
1344
  if (chars !== null) return charTriviaVisit(input, cur, chars, visit);
1389
1345
  let pos = cur;
1390
1346
  let count = 0;
@@ -1451,7 +1407,7 @@ function resolveAdjacencyKindMask(trivia2, kinds) {
1451
1407
  return mask;
1452
1408
  }
1453
1409
  function triviaKindMaskAt(input, pos, spec, state) {
1454
- const chars = charArmsFor(spec);
1410
+ const chars = spec.charArms;
1455
1411
  if (chars !== null) return charTriviaKindMask(input, pos, chars);
1456
1412
  let cur = pos;
1457
1413
  let mask = 0;
@@ -3252,6 +3208,53 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
3252
3208
  return false;
3253
3209
  }
3254
3210
  }
3211
+ function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
3212
+ if (seen.has(p)) return false;
3213
+ seen.add(p);
3214
+ const d = p._def;
3215
+ switch (d.tag) {
3216
+ case "node":
3217
+ return d.build !== void 0 || hasDirectBuildDef(d.parser, seen);
3218
+ case "lazy": {
3219
+ try {
3220
+ return hasDirectBuildDef(d.thunk(), seen);
3221
+ } catch {
3222
+ return false;
3223
+ }
3224
+ }
3225
+ case "grammar":
3226
+ case "trivia":
3227
+ case "token":
3228
+ case "leaf":
3229
+ case "label":
3230
+ case "field":
3231
+ case "optional":
3232
+ case "many":
3233
+ case "oneOrMore":
3234
+ case "attempt":
3235
+ case "not":
3236
+ case "peek":
3237
+ case "withCtx":
3238
+ case "expect":
3239
+ case "transform":
3240
+ return hasDirectBuildDef(d.parser, seen);
3241
+ case "sequence":
3242
+ case "choice":
3243
+ return d.parsers.some((x) => hasDirectBuildDef(x, seen));
3244
+ case "dispatch":
3245
+ return hasDirectBuildDef(d.selector, seen) || d.cases.some((x) => hasDirectBuildDef(x.parser, seen)) || (d.matchers ? d.matchers.some((x) => hasDirectBuildDef(x.parser, seen)) : false) || (d.otherwise ? hasDirectBuildDef(d.otherwise, seen) : false);
3246
+ case "sepBy":
3247
+ return hasDirectBuildDef(d.parser, seen) || hasDirectBuildDef(d.separator, seen);
3248
+ case "scanTo":
3249
+ return hasDirectBuildDef(d.sentinel, seen) || d.skip.some((x) => hasDirectBuildDef(x, seen)) || d.recoverAt !== void 0 && hasDirectBuildDef(d.recoverAt, seen) || d.stopAt !== void 0 && hasDirectBuildDef(d.stopAt, seen);
3250
+ case "recover":
3251
+ return hasDirectBuildDef(d.parser, seen) || hasDirectBuildDef(d.sentinel, seen);
3252
+ case "routed":
3253
+ return d.fallback ? hasDirectBuildDef(d.fallback, seen) : false;
3254
+ default:
3255
+ return false;
3256
+ }
3257
+ }
3255
3258
  function mayCommitFailure(p, seen = /* @__PURE__ */ new Set(), resolve) {
3256
3259
  if (seen.has(p)) return false;
3257
3260
  seen.add(p);
@@ -4153,7 +4156,7 @@ function buildFieldMap(captures) {
4153
4156
  if (!captures?.length) return void 0;
4154
4157
  const out = {};
4155
4158
  for (const cap of captures) {
4156
- const entry = { value: cap.value, span: cap.span };
4159
+ const entry = cap.leading === void 0 ? { value: cap.value, span: cap.span } : { value: cap.value, span: cap.span, leading: cap.leading, trailing: cap.trailing };
4157
4160
  const current = out[cap.name];
4158
4161
  if (current === void 0) out[cap.name] = entry;
4159
4162
  else if (Array.isArray(current)) current.push(entry);
@@ -4162,6 +4165,23 @@ function buildFieldMap(captures) {
4162
4165
  return out;
4163
4166
  }
4164
4167
 
4168
+ // src/combinators/field-trivia.ts
4169
+ var LEAD = { at: -1 };
4170
+ var FIELD_LEADING_TRIVIA = 1;
4171
+ var FIELD_TRAILING_TRIVIA = 2;
4172
+ function triviaFieldCapture(name, value, input, start, end, leadFrom, trailEnd) {
4173
+ return {
4174
+ name,
4175
+ value,
4176
+ span: { start, end },
4177
+ leading: leadFrom >= 0 && leadFrom < start ? input.slice(leadFrom, start) : "",
4178
+ trailing: trailEnd > end ? input.slice(end, trailEnd) : ""
4179
+ };
4180
+ }
4181
+ function leadsTrivia(p) {
4182
+ return p._def.tag === "field" && p._def.leadingTrivia === true;
4183
+ }
4184
+
4165
4185
  // src/combinators/dispatch.ts
4166
4186
  function parserUsesRouted(parser2, seen = /* @__PURE__ */ new Set()) {
4167
4187
  if (seen.has(parser2)) return false;
@@ -5130,6 +5150,7 @@ function unwrapSeparator(separator) {
5130
5150
  }
5131
5151
  function sepBy(combinator, separatorArg, opts = {}) {
5132
5152
  const { sep: separator, keep: keepSeparators } = unwrapSeparator(separatorArg);
5153
+ const separatorLeads = leadsTrivia(separator);
5133
5154
  const { min, max } = resolveBounds("sepBy()", opts);
5134
5155
  const trailing = opts.trailing ?? "forbid";
5135
5156
  const meta = {
@@ -5194,7 +5215,7 @@ function sepBy(combinator, separatorArg, opts = {}) {
5194
5215
  // this option surface already; parity is held by test/parity, not by hope.
5195
5216
  ...keepSeparators ? { keepSeparators: true } : {}
5196
5217
  },
5197
- _parseScalar: keepSeparators ? void 0 : parseScalar,
5218
+ _parseScalar: keepSeparators || separatorLeads ? void 0 : parseScalar,
5198
5219
  parse(input, pos, ctx) {
5199
5220
  const first = combinator.parse(input, pos, ctx);
5200
5221
  const values = [];
@@ -5226,6 +5247,7 @@ function sepBy(combinator, separatorArg, opts = {}) {
5226
5247
  sepPos = advanceTrivia(input, cur, ctx);
5227
5248
  }
5228
5249
  }
5250
+ if (separatorLeads) LEAD.at = cur;
5229
5251
  const sep = separator.parse(input, sepPos, ctx);
5230
5252
  if (!sep.ok) {
5231
5253
  rollbackTrivia(ctx, loopMark);
@@ -5377,16 +5399,41 @@ function label(name, combinator) {
5377
5399
  }
5378
5400
  };
5379
5401
  }
5380
- function field(name, combinator) {
5402
+ function field(name, combinator, opts) {
5403
+ const leadingTrivia = opts?.leadingTrivia === true;
5404
+ const trailingTrivia = opts?.trailingTrivia === true;
5405
+ if (!leadingTrivia && !trailingTrivia) {
5406
+ return {
5407
+ _tag: combinator._tag,
5408
+ _meta: combinator._meta,
5409
+ _def: { tag: "field", name, parser: combinator },
5410
+ parse(input, pos, ctx) {
5411
+ const result = combinator.parse(input, pos, ctx);
5412
+ if (!result.ok) return result;
5413
+ ctx._fields?.push({ name, value: result.value, span: result.span });
5414
+ return result;
5415
+ }
5416
+ };
5417
+ }
5381
5418
  return {
5382
5419
  _tag: combinator._tag,
5383
5420
  _meta: combinator._meta,
5384
- _def: { tag: "field", name, parser: combinator },
5421
+ _def: {
5422
+ tag: "field",
5423
+ name,
5424
+ parser: combinator,
5425
+ ...leadingTrivia ? { leadingTrivia: true } : {},
5426
+ ...trailingTrivia ? { trailingTrivia: true } : {}
5427
+ },
5385
5428
  parse(input, pos, ctx) {
5429
+ const leadFrom = LEAD.at;
5430
+ LEAD.at = -1;
5386
5431
  const result = combinator.parse(input, pos, ctx);
5387
5432
  if (!result.ok) return result;
5388
- ctx._fields?.push({ name, value: result.value, span: result.span });
5389
- return result;
5433
+ const end = result.span.end;
5434
+ const trailEnd = trailingTrivia && ctx.trivia ? consumeTrivia(input, end, ctx) : end;
5435
+ ctx._fields?.push(triviaFieldCapture(name, result.value, input, result.span.start, end, leadingTrivia ? leadFrom : -1, trailEnd));
5436
+ return trailEnd === end ? result : { ok: true, value: result.value, span: { start: result.span.start, end: trailEnd } };
5390
5437
  }
5391
5438
  };
5392
5439
  }
@@ -6531,6 +6578,16 @@ var Encoder = class {
6531
6578
  this.kIndex.set(key, i);
6532
6579
  return i;
6533
6580
  }
6581
+ fieldSpecIndex = /* @__PURE__ */ new Map();
6582
+ fieldSpecSlot(name, bits) {
6583
+ const key = JSON.stringify([name, bits]);
6584
+ const hit = this.fieldSpecIndex.get(key);
6585
+ if (hit !== void 0) return hit;
6586
+ const i = this.k.length;
6587
+ this.k.push([name, bits]);
6588
+ this.fieldSpecIndex.set(key, i);
6589
+ return i;
6590
+ }
6534
6591
  /**
6535
6592
  * A `notAdjacent({ kinds })` filter, pooled by its CONTENTS.
6536
6593
  *
@@ -7151,8 +7208,10 @@ var Encoder = class {
7151
7208
  for (let i = 0; i < arms.length; i++) this.code[head + 6 + i] = arms[i];
7152
7209
  return head;
7153
7210
  }
7154
- case "field":
7155
- return this.emit(OP_FIELD, this.constant(d.name), this.node(d.parser).ip);
7211
+ case "field": {
7212
+ const bits = (d.leadingTrivia === true ? FIELD_LEADING_TRIVIA : 0) | (d.trailingTrivia === true ? FIELD_TRAILING_TRIVIA : 0);
7213
+ return this.emit(OP_FIELD, bits === 0 ? this.constant(d.name) : this.fieldSpecSlot(d.name, bits), this.node(d.parser).ip);
7214
+ }
7156
7215
  case "lazy": {
7157
7216
  const refName = p._ruleName;
7158
7217
  const winner = refName === void 0 ? void 0 : this.winners?.[refName];
@@ -8825,6 +8884,26 @@ function leadingLiteralFamily(code, constants, ip, minDepth = 2, limit = 4) {
8825
8884
  };
8826
8885
  return walk(ip, 0);
8827
8886
  }
8887
+ function largeChoiceLiteralPretest(code, constants, armIp) {
8888
+ const child = leadingScalarTerminal(code, armIp, 2, true, true);
8889
+ if (child >= 0) {
8890
+ const spec = constants[code[child + 1]];
8891
+ if (code[child] === OP_LIT && typeof spec === "string" && spec.length >= 2) return [child];
8892
+ }
8893
+ const family = leadingLiteralFamily(code, constants, armIp);
8894
+ return family !== void 0 && family.length >= 2 && family.every((terminal) => {
8895
+ const value = constants[code[terminal + 1]];
8896
+ return typeof value === "string" && value.length >= 2;
8897
+ }) ? family : void 0;
8898
+ }
8899
+
8900
+ // src/table/field-spec.ts
8901
+ function fieldSpec(slot) {
8902
+ return Array.isArray(slot) ? { name: slot[0], bits: slot[1] } : { name: slot, bits: 0 };
8903
+ }
8904
+ function leadingTriviaFieldAt(code, k, ip) {
8905
+ return code[ip] === OP_FIELD && (fieldSpec(k[code[ip + 1]]).bits & FIELD_LEADING_TRIVIA) !== 0;
8906
+ }
8828
8907
 
8829
8908
  // src/table/emit-assembly.ts
8830
8909
  var Unemittable = class extends Error {
@@ -8899,7 +8978,11 @@ var EMITTED_PARAMS = [
8899
8978
  // Appended for old precompiled-factory ABI: old factories ignore it.
8900
8979
  "adjacencyHolds",
8901
8980
  // Appended for selected composite lexical programs; old factories ignore it.
8902
- "LEXPROG"
8981
+ "LEXPROG",
8982
+ // Appended for trivia-attributing fields (`field(…, { leadingTrivia })`);
8983
+ // old factories ignore them.
8984
+ "LEAD",
8985
+ "triviaFieldCapture"
8903
8986
  ];
8904
8987
  var RUNTIME_PRELUDE = `
8905
8988
  let _pfScan=null
@@ -9159,20 +9242,12 @@ function emitAssemblySource(t2, prog, cfg, extraIps = [], staticBuild = false) {
9159
9242
  if (child >= 0) scalarSpecs.add(code[child + 1]);
9160
9243
  continue;
9161
9244
  }
9162
- if (child >= 0) {
9163
- const spec = k[code[child + 1]];
9164
- if (code[child] === OP_LIT && typeof spec === "string" && spec.length >= 2) {
9165
- largeChoiceScalarSpecs.add(code[child + 1]);
9166
- continue;
9167
- }
9168
- }
9169
- const family = leadingLiteralFamily(code, k, armIp);
9170
- if (family !== void 0 && family.length >= 2 && family.every((terminal) => {
9171
- const value = k[code[terminal + 1]];
9172
- return typeof value === "string" && value.length >= 2;
9173
- })) {
9174
- largeChoiceLiteralFamilies.set(armIp, family);
9245
+ const literals = largeChoiceLiteralPretest(code, k, armIp);
9246
+ if (literals !== void 0 && literals.length === 1 && literals[0] === child) {
9247
+ largeChoiceScalarSpecs.add(code[child + 1]);
9248
+ continue;
9175
9249
  }
9250
+ if (literals !== void 0) largeChoiceLiteralFamilies.set(armIp, literals);
9176
9251
  const sequence6 = leadingScalarSequence(code, armIp);
9177
9252
  if (sequence6 !== void 0 && (sequence6.trivia < 0 || swapLegal && t2.triviaScan[sequence6.trivia] != null)) {
9178
9253
  largeChoiceScalarSequences.set(armIp, sequence6);
@@ -9596,14 +9671,31 @@ return v
9596
9671
  }`;
9597
9672
  }
9598
9673
  case OP_FIELD: {
9599
- const name = q(k[code[ip + 1]]);
9674
+ const spec = fieldSpec(k[code[ip + 1]]);
9675
+ const name = q(spec.name);
9600
9676
  const child = link(code[ip + 2]);
9601
- return `${head}
9677
+ if (spec.bits === 0) {
9678
+ return `${head}
9602
9679
  const v=${child}(input,pos,ctx)
9603
9680
  if(v===FAIL)return FAIL
9604
9681
  const f=ctx._fields
9605
9682
  if(f!==undefined)f.push({name:${name},value:v,span:{start:pos,end:EC.e}})
9606
9683
  return v
9684
+ }`;
9685
+ }
9686
+ const leading = (spec.bits & FIELD_LEADING_TRIVIA) !== 0;
9687
+ const trailing = (spec.bits & FIELD_TRAILING_TRIVIA) !== 0;
9688
+ return `${head}
9689
+ const lf=${leading ? "LEAD.at" : "-1"}
9690
+ LEAD.at=-1
9691
+ const v=${child}(input,pos,ctx)
9692
+ if(v===FAIL)return FAIL
9693
+ const e=EC.e
9694
+ const te=${trailing ? "ctx.trivia!==undefined?consumeTrivia(input,e,ctx):e" : "e"}
9695
+ const f=ctx._fields
9696
+ if(f!==undefined)f.push(triviaFieldCapture(${name},v,input,pos,e,lf,te))
9697
+ EC.e=te
9698
+ return v
9607
9699
  }`;
9608
9700
  }
9609
9701
  case OP_EXPECT: {
@@ -9899,7 +9991,10 @@ return v
9899
9991
  `if(!adjacencyHolds(input,cur,ctx,${negated ? "true" : "false"},${kinds})){ctx._fe=cur;ctx._fx=${expected};return FAIL}`,
9900
9992
  `${vn}=null`
9901
9993
  );
9902
- } else parts.push(emitTerm(kids[i], vn, tmp(), L, skipFor(L)));
9994
+ } else {
9995
+ const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
9996
+ parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L)));
9997
+ }
9903
9998
  names.push(vn);
9904
9999
  }
9905
10000
  parts.push("EC.e=cur");
@@ -10299,7 +10394,7 @@ let sp=cur
10299
10394
  ${hasTrivia === "false" ? "" : hasTrivia === "true" ? `sp=${skip}(input,sp,ctx)
10300
10395
  ` : `if(hasTrivia)sp=${skip}(input,sp,ctx)
10301
10396
  `}ctx._fc=false
10302
- const sv=${sep}(input,sp,ctx)
10397
+ ${sepIp >= 0 && leadingTriviaFieldAt(code, k, sepIp) ? "LEAD.at=cur\n" : ""}const sv=${sep}(input,sp,ctx)
10303
10398
  if(sv===FAIL){
10304
10399
  ${rb}
10305
10400
  if(ctx._fc===true)return FAIL
@@ -10681,6 +10776,10 @@ function sequence(...parsers) {
10681
10776
  (adjacency ??= Array.from({ length: parsers.length }, () => null))[i] = a;
10682
10777
  }
10683
10778
  const hasAdjacency = adjacency !== null;
10779
+ let leading = null;
10780
+ for (let i = 1; i < parsers.length; i++) {
10781
+ if (leadsTrivia(parsers[i])) (leading ??= Array.from({ length: parsers.length }, () => false))[i] = true;
10782
+ }
10684
10783
  const strictArity = !hasAdjacency && (parsers.length === 2 && !matchesEmpty(parsers[1]) || parsers.length === 3 && parsers.every((p) => !matchesEmpty(p))) ? parsers.length : 0;
10685
10784
  const meta = {
10686
10785
  // Union through the nullable prefix — a leading optional()/many() lets a later
@@ -10728,7 +10827,7 @@ function sequence(...parsers) {
10728
10827
  _tag: "sequence",
10729
10828
  _meta: meta,
10730
10829
  _def: def,
10731
- _parseScalar: hasAdjacency ? void 0 : parseScalar,
10830
+ _parseScalar: hasAdjacency || leading !== null ? void 0 : parseScalar,
10732
10831
  parse(input, pos, ctx) {
10733
10832
  const tolerant = ctx._tolerant === true;
10734
10833
  if (tolerant) {
@@ -10762,6 +10861,7 @@ function sequence(...parsers) {
10762
10861
  const scanTlog = deferredTrivia ? cstTlLen(ctx) : 0;
10763
10862
  const scanLog = deferredTrivia ? ctx._triviaLog?.length ?? 0 : 0;
10764
10863
  const scanRootLog = deferredTrivia ? ctx._rootTriviaLog?.length ?? 0 : 0;
10864
+ if (leading?.[i] === true) LEAD.at = cur;
10765
10865
  const result = parsers[i].parse(input, termPos, ctx);
10766
10866
  if (!result.ok) return result;
10767
10867
  if (values !== void 0) values.push(result.value);
@@ -10803,6 +10903,7 @@ function withRuleTrivia(trivia2, ctx, run) {
10803
10903
  ctx.triviaKindLabels = savedLabels;
10804
10904
  }
10805
10905
  }
10906
+ var UNDEFINED_REF = new Error("ref<T>() used before .define() was called");
10806
10907
  function ref() {
10807
10908
  let resolved = null;
10808
10909
  let resolvedScalar = null;
@@ -10818,7 +10919,7 @@ function ref() {
10818
10919
  _def: {
10819
10920
  tag: "lazy",
10820
10921
  thunk: () => {
10821
- if (!resolved) throw new Error("ref<T>() used before .define() was called");
10922
+ if (!resolved) throw UNDEFINED_REF;
10822
10923
  return resolved;
10823
10924
  }
10824
10925
  },
@@ -11793,6 +11894,12 @@ function assemble(t2, prog, cfg) {
11793
11894
  rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
11794
11895
  return cur;
11795
11896
  }
11897
+ function leadingFieldTerm(step, child, input, cur, ctx) {
11898
+ return step((i, p, c) => {
11899
+ LEAD.at = cur;
11900
+ return child(i, p, c);
11901
+ }, input, cur, ctx);
11902
+ }
11796
11903
  function committed3(c) {
11797
11904
  return c._fc === true;
11798
11905
  }
@@ -12430,12 +12537,27 @@ function assemble(t2, prog, cfg) {
12430
12537
  };
12431
12538
  }
12432
12539
  case OP_FIELD: {
12433
- const name = k[code[ip + 1]];
12540
+ const { name, bits } = fieldSpec(k[code[ip + 1]]);
12434
12541
  const child = link(code[ip + 2]);
12542
+ if (bits === 0) {
12543
+ return (input, pos, ctx) => {
12544
+ const v = child(input, pos, ctx);
12545
+ if (v === FAIL) return FAIL;
12546
+ ctx._fields?.push({ name, value: v, span: { start: pos, end: EC.e } });
12547
+ return v;
12548
+ };
12549
+ }
12550
+ const leading = (bits & FIELD_LEADING_TRIVIA) !== 0;
12551
+ const trailing = (bits & FIELD_TRAILING_TRIVIA) !== 0;
12435
12552
  return (input, pos, ctx) => {
12553
+ const leadFrom = leading ? LEAD.at : -1;
12554
+ LEAD.at = -1;
12436
12555
  const v = child(input, pos, ctx);
12437
12556
  if (v === FAIL) return FAIL;
12438
- ctx._fields?.push({ name, value: v, span: { start: pos, end: EC.e } });
12557
+ const end = EC.e;
12558
+ const trailEnd = trailing && ctx.trivia !== void 0 ? consumeTrivia(input, end, ctx) : end;
12559
+ ctx._fields?.push(triviaFieldCapture(name, v, input, pos, end, leadFrom, trailEnd));
12560
+ EC.e = trailEnd;
12439
12561
  return v;
12440
12562
  };
12441
12563
  }
@@ -12869,6 +12991,12 @@ function assemble(t2, prog, cfg) {
12869
12991
  const kidIp = code[base + i];
12870
12992
  if (code[kidIp] !== OP_ADJ) {
12871
12993
  const kid = link(kidIp);
12994
+ if (leadingTriviaFieldAt(code, k, kidIp)) {
12995
+ return (input, cur, ctx, inherited) => {
12996
+ ctx._sync = sync ?? inherited;
12997
+ return leadingFieldTerm(step, kid, input, cur, ctx);
12998
+ };
12999
+ }
12872
13000
  return (input, cur, ctx, inherited) => {
12873
13001
  ctx._sync = sync ?? inherited;
12874
13002
  return step(kid, input, cur, ctx);
@@ -12946,9 +13074,12 @@ function assemble(t2, prog, cfg) {
12946
13074
  };
12947
13075
  }
12948
13076
  let hasAdj = false;
12949
- for (let i = 1; i < n; i++) if (code[code[base + i]] === OP_ADJ) {
12950
- hasAdj = true;
12951
- break;
13077
+ for (let i = 1; i < n; i++) {
13078
+ const kidIp = code[base + i];
13079
+ if (code[kidIp] === OP_ADJ || leadingTriviaFieldAt(code, k, kidIp)) {
13080
+ hasAdj = true;
13081
+ break;
13082
+ }
12952
13083
  }
12953
13084
  if (hasAdj) {
12954
13085
  const first2 = link(code[base]);
@@ -12956,6 +13087,9 @@ function assemble(t2, prog, cfg) {
12956
13087
  const kidIp = code[base + i];
12957
13088
  if (code[kidIp] !== OP_ADJ) {
12958
13089
  const kid = link(kidIp);
13090
+ if (leadingTriviaFieldAt(code, k, kidIp)) {
13091
+ return (input, cur, ctx) => leadingFieldTerm(step, kid, input, cur, ctx);
13092
+ }
12959
13093
  return (input, cur, ctx) => step(kid, input, cur, ctx);
12960
13094
  }
12961
13095
  const negated = code[kidIp + 1] === 1;
@@ -13318,7 +13452,7 @@ function assemble(t2, prog, cfg) {
13318
13452
  if (n === 2 || n === 3) {
13319
13453
  const a0 = link(code[base]), a1 = link(code[base + 1]);
13320
13454
  const a2 = n === 3 ? link(code[base + 2]) : void 0;
13321
- const predecide = !hostCst && !REC && !cfg.probe && !cfg.coverage && !cfg.trackLines;
13455
+ const predecide = !REC && !cfg.probe && !cfg.coverage && !cfg.trackLines;
13322
13456
  const p0ip = predecide ? leadingScalarTerminal(code, code[base], 2, true, true) : -1;
13323
13457
  const p1ip = predecide ? leadingScalarTerminal(code, code[base + 1], 2, true, true) : -1;
13324
13458
  const p2ip = predecide && n === 3 ? leadingScalarTerminal(code, code[base + 2], 2, true, true) : -1;
@@ -13541,6 +13675,75 @@ function assemble(t2, prog, cfg) {
13541
13675
  );
13542
13676
  };
13543
13677
  const masked = bindMasked(0, EMPTY_EXPECTED_PREFIX);
13678
+ const pBit = [];
13679
+ const pRec = [];
13680
+ if (!REC && !cfg.probe && !cfg.coverage && !cfg.trackLines) {
13681
+ for (let i = 0; i < n; i++) {
13682
+ for (const terminal of largeChoiceLiteralPretest(code, k, code[base + i]) ?? []) {
13683
+ pBit.push(1 << i);
13684
+ pRec.push(scalarFor(terminal));
13685
+ }
13686
+ }
13687
+ }
13688
+ const pn = pBit.length;
13689
+ if (pn !== 0) {
13690
+ return (input, pos, ctx) => {
13691
+ const c = lead(input, pos);
13692
+ const need = markCst(ctx);
13693
+ const mRaw = MRAW;
13694
+ const mTl = MTL;
13695
+ const mLv = MLV;
13696
+ const mFl = need ? ctx._fields?.length ?? 0 : 0;
13697
+ const mEr = need ? ctx._errors?.length ?? 0 : 0;
13698
+ const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
13699
+ const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
13700
+ if (c < 128) {
13701
+ const bits = mask[c < 0 ? 128 : c];
13702
+ let tested = 0;
13703
+ let hit = 0;
13704
+ for (let i = 0; i < pn; i++) {
13705
+ const b = pBit[i];
13706
+ if ((bits & b) === 0 || (hit & b) !== 0) continue;
13707
+ tested |= b;
13708
+ if (pRec[i](input, pos) >= 0) hit |= b;
13709
+ }
13710
+ return masked(
13711
+ input,
13712
+ pos,
13713
+ ctx,
13714
+ bits & (~tested | hit),
13715
+ need,
13716
+ mRaw,
13717
+ mTl,
13718
+ mLv,
13719
+ mFl,
13720
+ mEr,
13721
+ mLog,
13722
+ mRoot,
13723
+ void 0,
13724
+ 0,
13725
+ pos
13726
+ );
13727
+ }
13728
+ return general(
13729
+ input,
13730
+ pos,
13731
+ ctx,
13732
+ c,
13733
+ need,
13734
+ mRaw,
13735
+ mTl,
13736
+ mLv,
13737
+ mFl,
13738
+ mEr,
13739
+ mLog,
13740
+ mRoot,
13741
+ void 0,
13742
+ 0,
13743
+ pos
13744
+ );
13745
+ };
13746
+ }
13544
13747
  return (input, pos, ctx) => {
13545
13748
  const c = lead(input, pos);
13546
13749
  const need = markCst(ctx);
@@ -13702,6 +13905,7 @@ function assemble(t2, prog, cfg) {
13702
13905
  const max = code[ip + 3];
13703
13906
  const sepIp = code[ip + 4];
13704
13907
  const sep = sepIp >= 0 ? link(sepIp) : void 0;
13908
+ const sepLeads = sepIp >= 0 && leadingTriviaFieldAt(code, k, sepIp);
13705
13909
  const flags = code[ip + 5];
13706
13910
  const keepSeparators = (flags & 2) !== 0;
13707
13911
  const trailingAllowed = (flags & 1) !== 0;
@@ -13741,6 +13945,7 @@ function assemble(t2, prog, cfg) {
13741
13945
  let sp = cur;
13742
13946
  if (hasTrivia) sp = skipTrivia(input, sp, ctx);
13743
13947
  ctx._fc = false;
13948
+ if (sepLeads) LEAD.at = cur;
13744
13949
  const sv = sep(input, sp, ctx);
13745
13950
  if (sv === FAIL) {
13746
13951
  if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
@@ -13830,6 +14035,7 @@ function assemble(t2, prog, cfg) {
13830
14035
  let sp = cur;
13831
14036
  if (hasTrivia) sp = skipTrivia(input, sp, ctx);
13832
14037
  ctx._fc = false;
14038
+ if (sepLeads) LEAD.at = cur;
13833
14039
  const sv = sep(input, sp, ctx);
13834
14040
  if (sv === FAIL) {
13835
14041
  if (needMark) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
@@ -14152,20 +14358,9 @@ function assemble(t2, prog, cfg) {
14152
14358
  if (child >= 0) scalarFor(child);
14153
14359
  continue;
14154
14360
  }
14155
- if (child >= 0) {
14156
- const spec = k[code[child + 1]];
14157
- if (code[child] === OP_LIT && typeof spec === "string" && spec.length >= 2) {
14158
- scalarFor(child);
14159
- continue;
14160
- }
14161
- }
14162
- const family = leadingLiteralFamily(code, k, armIp);
14163
- if (family !== void 0 && family.length >= 2 && family.every((terminal) => {
14164
- const value = k[code[terminal + 1]];
14165
- return typeof value === "string" && value.length >= 2;
14166
- })) {
14167
- for (const terminal of family) scalarFor(terminal);
14168
- }
14361
+ const literals = largeChoiceLiteralPretest(code, k, armIp);
14362
+ if (literals !== void 0) for (const terminal of literals) scalarFor(terminal);
14363
+ if (literals !== void 0 && literals.length === 1 && literals[0] === child) continue;
14169
14364
  const sequence6 = leadingScalarSequence(code, armIp);
14170
14365
  if (sequence6 !== void 0 && (sequence6.trivia < 0 || triviaScan[sequence6.trivia] != null)) {
14171
14366
  for (const terminal of sequence6.terminals) scalarFor(terminal);
@@ -14231,7 +14426,9 @@ function assemble(t2, prog, cfg) {
14231
14426
  scanTriviaCompact,
14232
14427
  t2.lex,
14233
14428
  adjacencyHolds,
14234
- t2.lexPrograms
14429
+ t2.lexPrograms,
14430
+ LEAD,
14431
+ triviaFieldCapture
14235
14432
  );
14236
14433
  emitReached = new Set(pre.reached);
14237
14434
  }
@@ -14313,7 +14510,9 @@ function assemble(t2, prog, cfg) {
14313
14510
  scanTriviaCompact,
14314
14511
  t2.lex,
14315
14512
  adjacencyHolds,
14316
- t2.lexPrograms
14513
+ t2.lexPrograms,
14514
+ LEAD,
14515
+ triviaFieldCapture
14317
14516
  );
14318
14517
  emitReached = em.reached;
14319
14518
  } catch (e) {
@@ -14489,7 +14688,9 @@ var AssemblyCache = class {
14489
14688
  return made;
14490
14689
  }
14491
14690
  };
14492
- function tableRules(source, artifactMetadata = {}) {
14691
+ function tableRules(source, metadataOrEntry = {}) {
14692
+ const entry = typeof metadataOrEntry === "string" ? metadataOrEntry : void 0;
14693
+ const artifactMetadata = typeof metadataOrEntry === "string" ? {} : metadataOrEntry;
14493
14694
  const prog = expandCompact(source);
14494
14695
  const resolved = resolveTable(prog);
14495
14696
  const cache = new AssemblyCache(prog, resolved);
@@ -14497,7 +14698,7 @@ function tableRules(source, artifactMetadata = {}) {
14497
14698
  const skipOf = prog.scanSkipOf;
14498
14699
  let last;
14499
14700
  let selected;
14500
- return stampRuleMap(prog, {
14701
+ const map = stampRuleMap(prog, {
14501
14702
  runRule: (ri, input, pos, ctx) => {
14502
14703
  const a = selected ?? cache.forCtx(ctx);
14503
14704
  selected = void 0;
@@ -14518,6 +14719,9 @@ function tableRules(source, artifactMetadata = {}) {
14518
14719
  return a.scanSkip[skipOf?.[ri] ?? -1];
14519
14720
  }
14520
14721
  }, artifactMetadata, resolved);
14722
+ if (entry === void 0) return map;
14723
+ if (!Object.hasOwn(map, entry)) throw new Error(`tableRules: the program has no rule ${JSON.stringify(entry)}`);
14724
+ return map[entry];
14521
14725
  }
14522
14726
 
14523
14727
  // src/table/emit.ts
@@ -14672,11 +14876,15 @@ function emitTableExpression(prog, opts = {}) {
14672
14876
  const entry = opts.entry === void 0 ? "grammar" : opts.entry;
14673
14877
  const ref2 = opts.runtimeRef ?? "tableRules";
14674
14878
  const fns = opts.fnSources ?? prog.fns.map(() => "() => {}");
14675
- const close = `}${opts.metadataSource === void 0 ? "" : `,${opts.metadataSource}`})`;
14879
+ const meta = opts.metadataSource;
14880
+ if (entry !== null && meta !== void 0) {
14881
+ throw new Error("emitTableExpression: metadataSource is for the rule-map form (entry: null); a single entry carries none");
14882
+ }
14883
+ const tail = entry !== null ? `,${jsString(entry)}` : meta === void 0 ? "" : `,${meta}`;
14676
14884
  return [
14677
14885
  `/* @__PURE__ */ ${ref2}({`,
14678
14886
  ...programFields(prog, fns, opts),
14679
- entry === null ? close : `${close}[${jsString(entry)}]`
14887
+ `}${tail})`
14680
14888
  ].join("\n");
14681
14889
  }
14682
14890
 
@@ -14745,7 +14953,8 @@ function children(def, winners) {
14745
14953
  return [];
14746
14954
  }
14747
14955
  const name = resolved._ruleName;
14748
- return name && winners?.[name] ? [winners[name]] : [resolved];
14956
+ const winner = name ? winners?.[name] : void 0;
14957
+ return winner !== void 0 && winner._def !== def ? [winner] : [resolved];
14749
14958
  }
14750
14959
  default:
14751
14960
  return [];
@@ -14770,16 +14979,39 @@ function buildGrammarPlan(entry, winners) {
14770
14979
  }
14771
14980
  }
14772
14981
  }
14982
+ const selfWinnerBody = (parser2) => {
14983
+ if (parser2._def.tag !== "lazy" || winners === void 0) return void 0;
14984
+ const name = winnerNames.get(parser2);
14985
+ if (name === void 0 || winners[name] !== parser2) return void 0;
14986
+ try {
14987
+ return parser2._def.thunk();
14988
+ } catch {
14989
+ return void 0;
14990
+ }
14991
+ };
14992
+ const slotsPerBody = /* @__PURE__ */ new Map();
14993
+ if (winners) {
14994
+ for (const winner of Object.values(winners)) {
14995
+ const body = selfWinnerBody(winner);
14996
+ if (body !== void 0) slotsPerBody.set(body, (slotsPerBody.get(body) ?? 0) + 1);
14997
+ }
14998
+ }
14999
+ const sharedBody = (parser2) => (slotsPerBody.get(parser2) ?? 0) > 1;
15000
+ const ownRule = (parser2, rule2) => {
15001
+ const id = `rule:${rule2}`;
15002
+ definitions.set(id, { id, kind: "rule" });
15003
+ rules.set(parser2, id);
15004
+ };
14773
15005
  const seen = /* @__PURE__ */ new Set();
14774
15006
  const visit = (parser2, path) => {
14775
15007
  if (seen.has(parser2)) return;
14776
15008
  seen.add(parser2);
14777
15009
  const rule2 = winnerNames.get(parser2) ?? parser2._ruleName;
14778
- if (rule2 && (winnerNames.has(parser2) || parser2._def.tag !== "lazy")) {
14779
- const id = `rule:${rule2}`;
14780
- definitions.set(id, { id, kind: "rule" });
14781
- rules.set(parser2, id);
15010
+ const body = selfWinnerBody(parser2);
15011
+ if (rule2 && body === void 0 && !sharedBody(parser2) && (winnerNames.has(parser2) || parser2._def.tag !== "lazy")) {
15012
+ ownRule(parser2, rule2);
14782
15013
  }
15014
+ if (rule2 && body !== void 0 && sharedBody(body)) ownRule(parser2, rule2);
14783
15015
  if (parser2._def.tag === "choice") {
14784
15016
  const ids = parser2._def.parsers.map((_, index) => `choice:${path}/arm:${index}`);
14785
15017
  choices.set(parser2, ids);
@@ -14800,7 +15032,13 @@ function buildGrammarPlan(entry, winners) {
14800
15032
  };
14801
15033
  const roots = Array.isArray(entry) ? entry : [entry];
14802
15034
  for (const root of roots) {
14803
- visit(root, winnerNames.get(root) ?? root._ruleName ?? "entry");
15035
+ const name = winnerNames.get(root) ?? root._ruleName ?? "entry";
15036
+ const body = selfWinnerBody(root);
15037
+ if (body !== void 0 && sharedBody(body) && !seen.has(root)) {
15038
+ seen.add(root);
15039
+ ownRule(root, name);
15040
+ }
15041
+ visit(body ?? root, name);
14804
15042
  }
14805
15043
  return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules };
14806
15044
  }
@@ -14824,7 +15062,7 @@ function payloadKey(p, d) {
14824
15062
  case "label":
14825
15063
  return `label\0${d.label}`;
14826
15064
  case "field":
14827
- return `field\0${d.name}`;
15065
+ return `field\0${d.name}\0${d.leadingTrivia === true}\0${d.trailingTrivia === true}`;
14828
15066
  case "node":
14829
15067
  return `node\0${d.type ?? ""}\0${d.unwrap === true}\0${d.collapse === true}\0${fnKey(d.buildSrc, d.build)}`;
14830
15068
  case "transform":
@@ -16102,6 +16340,238 @@ ${lines.join("\n")}`);
16102
16340
  function runDuplicationDiagnostic(combinator, opt) {
16103
16341
  return reportDuplication(opt, (o) => analyzeDuplication(combinator, o));
16104
16342
  }
16343
+ function runDuplicationDiagnosticRules(ruleMap, opt) {
16344
+ return reportDuplication(opt, (o) => analyzeDuplicationRules(ruleMap, o));
16345
+ }
16346
+
16347
+ // src/cst/reflection-symbols.ts
16348
+ var GRAMMAR_REFLECTION = /* @__PURE__ */ Symbol.for("parseman.grammarReflection");
16349
+
16350
+ // src/cst/reflection.ts
16351
+ function childrenOf2(def) {
16352
+ switch (def.tag) {
16353
+ case "sequence":
16354
+ case "choice":
16355
+ return def.parsers;
16356
+ case "dispatch":
16357
+ return [
16358
+ def.selector,
16359
+ ...def.cases.map((c) => c.parser),
16360
+ ...def.matchers ? def.matchers.map((c) => c.parser) : [],
16361
+ ...def.otherwise ? [def.otherwise] : []
16362
+ ];
16363
+ case "many":
16364
+ case "oneOrMore":
16365
+ case "optional":
16366
+ case "attempt":
16367
+ case "transform":
16368
+ case "trivia":
16369
+ case "token":
16370
+ case "leaf":
16371
+ case "label":
16372
+ case "field":
16373
+ case "not":
16374
+ case "peek":
16375
+ case "node":
16376
+ case "withCtx":
16377
+ case "expect":
16378
+ return [def.parser];
16379
+ case "recover":
16380
+ return [def.parser, def.sentinel];
16381
+ case "grammar":
16382
+ return def.triviaParser ? [def.parser, def.triviaParser] : [def.parser];
16383
+ case "sepBy":
16384
+ return [def.parser, def.separator];
16385
+ case "scanTo":
16386
+ return [
16387
+ def.sentinel,
16388
+ ...def.skip,
16389
+ ...def.recoverAt === void 0 ? [] : [def.recoverAt],
16390
+ ...def.stopAt === void 0 ? [] : [def.stopAt]
16391
+ ];
16392
+ case "routed":
16393
+ return def.fallback ? [def.fallback] : [];
16394
+ case "literal":
16395
+ case "regex":
16396
+ case "keywords":
16397
+ case "guard":
16398
+ case "adjacency":
16399
+ case "lazy":
16400
+ case "unknown":
16401
+ return [];
16402
+ }
16403
+ }
16404
+ function addNode(out, def) {
16405
+ if (def.type === void 0) return;
16406
+ const existing = out.get(def.type);
16407
+ if (existing === void 0) {
16408
+ out.set(def.type, def.tags === void 0 ? [] : [...def.tags]);
16409
+ return;
16410
+ }
16411
+ if (def.tags === void 0) return;
16412
+ for (const tag of def.tags) {
16413
+ if (!existing.includes(tag)) existing.push(tag);
16414
+ }
16415
+ }
16416
+ function collectFromCombinator(parser2, out, seen, followLazy = true) {
16417
+ if (seen.has(parser2)) return;
16418
+ seen.add(parser2);
16419
+ const def = parser2._def;
16420
+ if (def.tag === "lazy") {
16421
+ if (followLazy) {
16422
+ try {
16423
+ collectFromCombinator(def.thunk(), out, seen, followLazy);
16424
+ } catch {
16425
+ }
16426
+ }
16427
+ return;
16428
+ }
16429
+ if (def.tag === "node") addNode(out, def);
16430
+ for (const child of childrenOf2(def)) collectFromCombinator(child, out, seen, followLazy);
16431
+ }
16432
+ function collectGrammarReflection(ruleMap, opts) {
16433
+ const byType = /* @__PURE__ */ new Map();
16434
+ const followLazy = opts?.followLazy !== false;
16435
+ const seen = /* @__PURE__ */ new Set();
16436
+ for (const [, rule2] of ruleMap) {
16437
+ if (!followLazy && rule2._def.tag === "lazy") {
16438
+ try {
16439
+ const resolved = rule2._def.thunk();
16440
+ if (resolved._def.tag !== "lazy") collectFromCombinator(resolved, byType, /* @__PURE__ */ new Set(), false);
16441
+ } catch {
16442
+ }
16443
+ continue;
16444
+ }
16445
+ collectFromCombinator(rule2, byType, seen, followLazy);
16446
+ }
16447
+ return { nodes: [...byType].map(([type, tags]) => ({ type, tags })) };
16448
+ }
16449
+
16450
+ // src/table/compile-rule-map.ts
16451
+ function resolveHostMode(ruleMap, explicit) {
16452
+ return explicit ?? ruleMap.map(([, r]) => r._meta.grammarHostMode).find(Boolean) ?? "ast";
16453
+ }
16454
+ function resolveTrackLines(ruleMap, explicit) {
16455
+ return explicit === true || ruleMap.some(([, r]) => r._meta.grammarTrackLines === true);
16456
+ }
16457
+ function withAmbient(ruleMap, opts) {
16458
+ if (opts.trivia === void 0 && opts.scanSkip === void 0) return ruleMap;
16459
+ const wrappers = /* @__PURE__ */ new Map();
16460
+ return ruleMap.map(([name, rule2]) => {
16461
+ if (rule2._meta.isTrivia) return [name, rule2];
16462
+ const addTrivia = opts.trivia !== void 0 && rule2._meta.grammarTrivia === void 0;
16463
+ const addScanSkip = opts.scanSkip !== void 0 && rule2._meta.grammarScanSkip === void 0;
16464
+ if (!addTrivia && !addScanSkip) return [name, rule2];
16465
+ let wrapped = wrappers.get(rule2);
16466
+ if (wrapped === void 0) {
16467
+ wrapped = {
16468
+ ...rule2,
16469
+ _meta: {
16470
+ ...rule2._meta,
16471
+ ...addTrivia ? { grammarTrivia: opts.trivia } : {},
16472
+ ...addScanSkip ? { grammarScanSkip: opts.scanSkip } : {}
16473
+ }
16474
+ };
16475
+ wrappers.set(rule2, wrapped);
16476
+ }
16477
+ return [name, wrapped];
16478
+ });
16479
+ }
16480
+ function compileRuleMapRunnable(ruleMap, opts = {}) {
16481
+ const encoded = encodeForRun(ruleMap, opts);
16482
+ if (encoded === null) return null;
16483
+ const { prog, hostMode, plan } = encoded;
16484
+ const artifact = closureArtifact(prog);
16485
+ const reflection = collectGrammarReflection(ruleMap);
16486
+ return {
16487
+ keys: ruleMap.map(([key]) => key),
16488
+ hostMode,
16489
+ hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule2]) => hasDirectBuildDef(rule2)),
16490
+ reflection,
16491
+ ...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
16492
+ // Reflection rides on the map's metadata prototype from birth. Only `compile()`
16493
+ // asks to specialise; every other caller runs the closure artifact.
16494
+ rules: tableRules(opts.specialise === true ? prog : artifact, { [GRAMMAR_REFLECTION]: reflection }),
16495
+ prog: artifact
16496
+ };
16497
+ }
16498
+ function encodeForRun(ruleMap, opts) {
16499
+ runDuplicationDiagnosticRules(ruleMap, opts.duplication);
16500
+ const encodeMap = withAmbient(ruleMap, opts);
16501
+ const plan = opts.coverage === true ? buildGrammarPlan(
16502
+ encodeMap.map(([, rule2]) => rule2),
16503
+ Object.fromEntries(encodeMap.filter(([, rule2]) => rule2._def.tag !== "lazy"))
16504
+ ) : void 0;
16505
+ const hostMode = resolveHostMode(ruleMap, opts.hostMode);
16506
+ const settings = {
16507
+ hostMode,
16508
+ ...resolveTrackLines(ruleMap, opts.trackLines) ? { trackLines: true } : {},
16509
+ ...opts.recovery === true ? { recovery: true } : {},
16510
+ ...plan === void 0 ? {} : { coverage: plan }
16511
+ };
16512
+ try {
16513
+ const { prog, fnSrcs } = encodeTableProgram(Object.fromEntries(encodeMap), settings);
16514
+ return { prog, fnSrcs, hostMode, plan };
16515
+ } catch (e) {
16516
+ opts.refusals?.push(e instanceof Error ? e.message : String(e));
16517
+ return null;
16518
+ }
16519
+ }
16520
+
16521
+ // src/compiler/borrowed-rules.ts
16522
+ var nameOf = (c) => c._ruleName;
16523
+ function deref(c) {
16524
+ const seen = /* @__PURE__ */ new Set();
16525
+ let current = c;
16526
+ while (current._def.tag === "lazy" && !seen.has(current)) {
16527
+ seen.add(current);
16528
+ try {
16529
+ current = current._def.thunk();
16530
+ } catch {
16531
+ return void 0;
16532
+ }
16533
+ }
16534
+ return current;
16535
+ }
16536
+ function borrowedRuleReference(map) {
16537
+ const seen = /* @__PURE__ */ new Set();
16538
+ for (const [rule2, self] of Object.entries(map)) {
16539
+ let found;
16540
+ const visit = (c) => {
16541
+ if (found !== void 0) return;
16542
+ if (c._def.tag === "lazy") {
16543
+ if (!winnerWrapsReference(self, c)) {
16544
+ const name = nameOf(c);
16545
+ const winner = name !== void 0 && Object.hasOwn(map, name) ? map[name] : void 0;
16546
+ if (winner !== void 0) {
16547
+ if (winnerWrapsReference(winner, c) || deref(c) === deref(winner)) return;
16548
+ found = name;
16549
+ return;
16550
+ }
16551
+ }
16552
+ if (seen.has(c)) return;
16553
+ seen.add(c);
16554
+ let body;
16555
+ try {
16556
+ body = c._def.thunk();
16557
+ } catch {
16558
+ return;
16559
+ }
16560
+ visit(body);
16561
+ return;
16562
+ }
16563
+ if (seen.has(c)) return;
16564
+ seen.add(c);
16565
+ for (const child of childrenOf(c._def)) visit(child);
16566
+ };
16567
+ visit(self);
16568
+ if (found !== void 0) return { rule: rule2, reference: found };
16569
+ }
16570
+ return void 0;
16571
+ }
16572
+ function borrowedRuleMessage(api, hit) {
16573
+ return `${api}: rule "${hit.rule}" is a rule object borrowed from another grammar, and its graph references "${hit.reference}", which this grammar also defines. The interpreter would keep the other grammar's "${hit.reference}" while a compiled table binds this grammar's, so the two would accept different input. Compose the grammar that defines "${hit.rule}" instead of borrowing its rule object, so its references resolve to this grammar's rules.`;
16574
+ }
16105
16575
 
16106
16576
  // src/table/compile.ts
16107
16577
  var ENTRY = "Entry";
@@ -16112,7 +16582,47 @@ function ownSource(fn) {
16112
16582
  const name = fn.name;
16113
16583
  return typeof name === "string" && name.length > 0 && globalThis[name] === fn ? name : null;
16114
16584
  }
16115
- function compile(combinator, mapFnSources, opts = {}) {
16585
+ function compile(target, second, third) {
16586
+ if (!isCombinator(target)) return compileMap(target, second);
16587
+ return compileRoot(target, second, third);
16588
+ }
16589
+ function isCombinator(x) {
16590
+ return typeof x === "object" && x !== null && typeof x.parse === "function" && "_def" in x;
16591
+ }
16592
+ function compileMap(grammar, opts = {}) {
16593
+ const entries = [];
16594
+ for (const [key, value] of Object.entries(grammar)) {
16595
+ if (!isCombinator(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
16596
+ if (value._def.tag === "lazy") {
16597
+ try {
16598
+ value._def.thunk();
16599
+ } catch {
16600
+ continue;
16601
+ }
16602
+ }
16603
+ entries.push([key, value]);
16604
+ }
16605
+ const borrowed = borrowedRuleReference(Object.fromEntries(entries));
16606
+ if (borrowed !== void 0) throw new Error(borrowedRuleMessage("compile", borrowed));
16607
+ const drain = beginCompileDegradationDrain();
16608
+ let done = false;
16609
+ try {
16610
+ const refusals = [];
16611
+ const compiled = compileRuleMapRunnable(entries, {
16612
+ ...opts.hostMode ? { hostMode: opts.hostMode } : {},
16613
+ refusals,
16614
+ specialise: true
16615
+ });
16616
+ if (compiled === null) {
16617
+ throw new Error(`compile: this grammar could not be encoded to a table${refusals.length ? ` \u2014 ${refusals.join("; ")}` : ""}`);
16618
+ }
16619
+ done = true;
16620
+ return compiled.rules;
16621
+ } finally {
16622
+ drain(done);
16623
+ }
16624
+ }
16625
+ function compileRoot(combinator, mapFnSources, opts = {}) {
16116
16626
  runDuplicationDiagnostic(combinator, opts.duplication);
16117
16627
  const drain = beginCompileDegradationDrain();
16118
16628
  let compiled = false;
@@ -16626,7 +17136,7 @@ function rebuildCombinator(root, replacements) {
16626
17136
  out = label(d.label, one(d.parser));
16627
17137
  break;
16628
17138
  case "field":
16629
- out = field(d.name, one(d.parser));
17139
+ out = field(d.name, one(d.parser), { leadingTrivia: d.leadingTrivia === true, trailingTrivia: d.trailingTrivia === true });
16630
17140
  break;
16631
17141
  case "token":
16632
17142
  out = token(one(d.parser));