parseman 0.47.0 → 0.47.1

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 (57) hide show
  1. package/dist/analysis/diagnostics.cjs +133 -45
  2. package/dist/analysis/diagnostics.cjs.map +2 -2
  3. package/dist/analysis/diagnostics.js +133 -45
  4. package/dist/analysis/diagnostics.js.map +2 -2
  5. package/dist/cli/index.cjs +133 -45
  6. package/dist/cli/index.cjs.map +2 -2
  7. package/dist/cli/index.js +133 -45
  8. package/dist/cli/index.js.map +2 -2
  9. package/dist/combinators/first-set.d.ts.map +1 -1
  10. package/dist/combinators/sequence.d.ts.map +1 -1
  11. package/dist/combinators/trivia-skip.d.ts +5 -0
  12. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  13. package/dist/index.cjs +134 -46
  14. package/dist/index.cjs.map +2 -2
  15. package/dist/index.js +134 -46
  16. package/dist/index.js.map +2 -2
  17. package/dist/language-service/index.cjs +3 -1
  18. package/dist/language-service/index.cjs.map +1 -1
  19. package/dist/language-service/index.js +3 -1
  20. package/dist/language-service/index.js.map +1 -1
  21. package/dist/plugin/index.cjs +134 -46
  22. package/dist/plugin/index.cjs.map +2 -2
  23. package/dist/plugin/index.js +134 -46
  24. package/dist/plugin/index.js.map +2 -2
  25. package/dist/spec/index.cjs +55 -7
  26. package/dist/spec/index.cjs.map +1 -1
  27. package/dist/spec/index.js +55 -7
  28. package/dist/spec/index.js.map +1 -1
  29. package/dist/table/assemble.d.ts.map +1 -1
  30. package/dist/table/emit-assembly.d.ts +2 -2
  31. package/dist/table/emit-assembly.d.ts.map +1 -1
  32. package/dist/table/emit.d.ts.map +1 -1
  33. package/dist/table/exec.d.ts.map +1 -1
  34. package/dist/table/index.cjs +1566 -1478
  35. package/dist/table/index.cjs.map +3 -3
  36. package/dist/table/index.js +1566 -1478
  37. package/dist/table/index.js.map +3 -3
  38. package/dist/table/ops.d.ts +8 -1
  39. package/dist/table/ops.d.ts.map +1 -1
  40. package/dist/table/program.d.ts +4 -1
  41. package/dist/table/program.d.ts.map +1 -1
  42. package/dist/version.d.ts +1 -1
  43. package/package.json +2 -1
  44. package/src/combinators/first-set.ts +29 -3
  45. package/src/combinators/sequence.ts +23 -7
  46. package/src/combinators/trivia-skip.ts +31 -0
  47. package/src/table/assemble.ts +30 -18
  48. package/src/table/child-slots.ts +2 -2
  49. package/src/table/emit-assembly.ts +36 -25
  50. package/src/table/emit.ts +12 -1
  51. package/src/table/encode.ts +4 -4
  52. package/src/table/exec.ts +20 -12
  53. package/src/table/ops.ts +9 -1
  54. package/src/table/program.ts +22 -1
  55. package/src/table/site-labels.ts +2 -2
  56. package/src/table/stamp.ts +2 -2
  57. package/src/version.ts +1 -1
@@ -79,6 +79,13 @@ function empty() {
79
79
  function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
80
80
  if (seen.has(p)) return true;
81
81
  seen.add(p);
82
+ try {
83
+ return matchesEmptyBody(p, seen, resolve);
84
+ } finally {
85
+ seen.delete(p);
86
+ }
87
+ }
88
+ function matchesEmptyBody(p, seen, resolve) {
82
89
  const me = (c) => matchesEmpty(c, seen, resolve);
83
90
  const d = p._def;
84
91
  switch (d.tag) {
@@ -180,6 +187,13 @@ function sequenceFirstSet(parsers) {
180
187
  function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve) {
181
188
  if (seen.has(p)) return any();
182
189
  seen.add(p);
190
+ try {
191
+ return firstSetBody(p, seen, resolve);
192
+ } finally {
193
+ seen.delete(p);
194
+ }
195
+ }
196
+ function firstSetBody(p, seen, resolve) {
183
197
  const fs = (c) => firstSetOf(c, seen, resolve);
184
198
  const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve);
185
199
  const d = p._def;
@@ -1220,6 +1234,23 @@ function rollbackTrivia(ctx, mark) {
1220
1234
  if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
1221
1235
  if (ctx._rootTriviaLog && ctx._rootTriviaLog.length !== mark.rootLog) ctx._rootTriviaLog.length = mark.rootLog;
1222
1236
  }
1237
+ function removeNumberRange(values, start, end) {
1238
+ if (values === void 0 || end <= start) return;
1239
+ if (values.length > end) values.copyWithin(start, end);
1240
+ values.length -= end - start;
1241
+ }
1242
+ function rollbackScannedTriviaAt(ctx, tlogStart, tlogEnd, logStart, logEnd, rootLogStart, rootLogEnd) {
1243
+ const b = ctx._cstBuf;
1244
+ if (b !== void 0) {
1245
+ const tlog = b.tl;
1246
+ removeNumberRange(tlog, tlogStart, tlogEnd);
1247
+ if (tlog !== void 0 && tlog.length === 0) b.tl = void 0;
1248
+ } else {
1249
+ removeNumberRange(ctx._cstTriviaLog, tlogStart, tlogEnd);
1250
+ }
1251
+ removeNumberRange(ctx._triviaLog, logStart, logEnd);
1252
+ removeNumberRange(ctx._rootTriviaLog, rootLogStart, rootLogEnd);
1253
+ }
1223
1254
  function parseTriviaNoCapture(triviaP, input, cur, ctx) {
1224
1255
  const probeCtx = createDetachedParseContext(ctx.trackLines, ctx.state);
1225
1256
  probeCtx._lineIndex = ctx._lineIndex;
@@ -3248,6 +3279,7 @@ var OP_LIVE = 37;
3248
3279
  var OP_ATTEMPT = 38;
3249
3280
  var OP_LABEL = 39;
3250
3281
  var OP_COV = 40;
3282
+ var OP_SCOPE_PLAIN = 41;
3251
3283
  var OP_DISPATCH = 25;
3252
3284
  var OP_ROUTED = 26;
3253
3285
  var OP_NAMES = {
@@ -3290,7 +3322,8 @@ var OP_NAMES = {
3290
3322
  [OP_LIVE]: "LIVE",
3291
3323
  [OP_ATTEMPT]: "ATTEMPT",
3292
3324
  [OP_LABEL]: "LABEL",
3293
- [OP_COV]: "COV"
3325
+ [OP_COV]: "COV",
3326
+ [OP_SCOPE_PLAIN]: "SCOPE_PLAIN"
3294
3327
  };
3295
3328
 
3296
3329
  // src/combinators/adjacency.ts
@@ -4273,6 +4306,15 @@ function expandCompact(p) {
4273
4306
  ...p.a === void 0 ? {} : { asm: p.a }
4274
4307
  });
4275
4308
  }
4309
+ function validateDispatchSpec(spec, arity, fallbackRouted) {
4310
+ const invalid = (arms) => {
4311
+ for (const arm of arms) if (!Number.isInteger(arm) || arm < 0 || arm >= arity) return true;
4312
+ return false;
4313
+ };
4314
+ if (spec === void 0 || !Number.isInteger(arity) || arity < 0 || fallbackRouted !== 0 && fallbackRouted !== 1 || spec.routed.length !== arity || spec.routed.some((value) => value !== 0 && value !== 1) || invalid(spec.byKey.values()) || invalid(spec.byFold.values()) || spec.match.some((matcher) => invalid([matcher[3]]))) {
4315
+ throw new TypeError("table: malformed dispatch");
4316
+ }
4317
+ }
4276
4318
  var TABLE_RUNTIME = /* @__PURE__ */ Symbol("parseman.tableRuntime");
4277
4319
  function ownTableProgram(prog, resolved) {
4278
4320
  return { ...prog, [TABLE_RUNTIME]: { resolved } };
@@ -4831,7 +4873,7 @@ var Encoder = class {
4831
4873
  this.carryTriviaMeta(amb);
4832
4874
  this.carryTriviaMeta(p);
4833
4875
  if (p._def.tag === "grammar") this.carryTriviaMeta(p._def.triviaParser);
4834
- this.rules[name] = amb === void 0 ? body : this.emit(OP_SCOPE, this.triviaSlot(amb), body);
4876
+ this.rules[name] = amb === void 0 ? body : this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), body);
4835
4877
  }
4836
4878
  /**
4837
4879
  * The row a cross-rule `g.X` reference jumps to — the target's body, RE-WRAPPED
@@ -4874,7 +4916,7 @@ var Encoder = class {
4874
4916
  const amb = p._meta.grammarTrivia ?? target._meta.grammarTrivia;
4875
4917
  if (amb === void 0 || this.activeTrivia !== void 0) return ip;
4876
4918
  if (!hasOwnTriviaBoundary(target)) return ip;
4877
- return this.emit(OP_SCOPE, this.triviaSlot(amb), ip);
4919
+ return this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), ip);
4878
4920
  }
4879
4921
  node(p) {
4880
4922
  const lazyRef = p._def.tag === "lazy";
@@ -5279,6 +5321,7 @@ var Encoder = class {
5279
5321
  return [ip + 1];
5280
5322
  case OP_SCOPE:
5281
5323
  case OP_SCOPE_CAP:
5324
+ case OP_SCOPE_PLAIN:
5282
5325
  case OP_WITHCTX:
5283
5326
  case OP_XFORM:
5284
5327
  case OP_LEAF:
@@ -6469,6 +6512,7 @@ function childSlots(code, ip, out) {
6469
6512
  case OP_GATE:
6470
6513
  case OP_SCOPE:
6471
6514
  case OP_SCOPE_CAP:
6515
+ case OP_SCOPE_PLAIN:
6472
6516
  case OP_WITHCTX:
6473
6517
  case OP_XFORM:
6474
6518
  case OP_NODE:
@@ -6557,7 +6601,7 @@ function reachableSites(code, roots) {
6557
6601
  }
6558
6602
  function transfer(code, ip, at, hostCst) {
6559
6603
  const op = code[ip];
6560
- if (op === OP_SCOPE || op === OP_SCOPE_CAP) {
6604
+ if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
6561
6605
  const ki = code[ip + 1];
6562
6606
  const tri = ki < 0 ? TRI_NONE : ki;
6563
6607
  const cap = op === OP_SCOPE_CAP ? CAP_ON : at.cap;
@@ -6638,6 +6682,7 @@ var EMITTED_PARAMS = [
6638
6682
  "pushCstLeaf",
6639
6683
  "pushCstChild",
6640
6684
  "rollbackTriviaAt",
6685
+ "rollbackScannedTriviaAt",
6641
6686
  "failAt",
6642
6687
  "classHas",
6643
6688
  "consumeTrivia",
@@ -6781,19 +6826,24 @@ if(ctx._errors!==undefined&&ctx._errors.length!==${t2}er)ctx._errors.length=${t2
6781
6826
  if (!s.fd && !s.er) return `if(${t2}n)rollbackTriviaAt(ctx,${t2}raw,${t2}tl,${t2}lv,0,undefined,${t2}lg,${t2}rt)`;
6782
6827
  return `if(${t2}n){rollbackTriviaAt(ctx,${t2}raw,${t2}tl,${t2}lv,${s.fd ? `${t2}fd` : "0"},${s.er ? `${t2}er` : "undefined"},${t2}lg,${t2}rt)}`;
6783
6828
  }
6784
- function emitTerm(callee, dst, t2, l, skip, s) {
6829
+ function emitTerm(callee, dst, t2, l, skip) {
6785
6830
  const fast = `const ${t2}v=${callee}(input,cur,ctx)
6786
6831
  if(${t2}v===FAIL)return FAIL
6787
6832
  ${dst}=${t2}v
6788
6833
  cur=EC.e`;
6789
6834
  if (l.tri === TRI_NONE) return fast;
6790
- const scanned = `${emitMark(t2, l.buf, s)}
6835
+ const scanned = `const ${t2}tl=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
6836
+ const ${t2}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
6837
+ const ${t2}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
6791
6838
  const ${t2}s=${skip}(input,cur,ctx)
6839
+ const ${t2}stl=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
6840
+ const ${t2}slg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
6841
+ const ${t2}srt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
6792
6842
  const ${t2}v=${callee}(input,${t2}s,ctx)
6793
6843
  if(${t2}v===FAIL)return FAIL
6794
6844
  ${dst}=${t2}v
6795
6845
  if(EC.e>${t2}s)cur=EC.e
6796
- else{${emitRollback(t2, l.buf, s)}}`;
6846
+ else{rollbackScannedTriviaAt(ctx,${t2}tl,${t2}stl,${t2}lg,${t2}slg,${t2}rt,${t2}srt)}`;
6797
6847
  if (l.tri !== TRI_UNKNOWN) return scanned;
6798
6848
  return `if(ctx.trivia===undefined){
6799
6849
  ${fast}
@@ -6956,7 +7006,7 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
6956
7006
  const op = code[ip];
6957
7007
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2];
6958
7008
  if (op === OP_RULE) return code[ip + 1];
6959
- if (op === OP_SCOPE && code[ip + 3] === 0 && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
7009
+ if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
6960
7010
  return code[ip + 2];
6961
7011
  }
6962
7012
  return void 0;
@@ -7124,10 +7174,11 @@ return r.value
7124
7174
  }`;
7125
7175
  }
7126
7176
  case OP_SCOPE:
7127
- case OP_SCOPE_CAP: {
7177
+ case OP_SCOPE_CAP:
7178
+ case OP_SCOPE_PLAIN: {
7128
7179
  const ki = code[ip + 1];
7129
7180
  const cap = op === OP_SCOPE_CAP;
7130
- const flags = code[ip + 3];
7181
+ const flags = op === OP_SCOPE_PLAIN ? 0 : code[ip + 3];
7131
7182
  const child = link(code[ip + 2]);
7132
7183
  const scanFor = swapLegal && ki >= 0 && !triviaLabelled[ki] ? hoist("ts", `TRIVIASCAN[${ki}]`) : "null";
7133
7184
  const tri = ki < 0 ? "undefined" : hoist("tv", `TRIVIA[${ki}]`);
@@ -7281,7 +7332,7 @@ return v
7281
7332
  const vn = `v${i}`;
7282
7333
  parts.push(`let ${vn}`);
7283
7334
  if (REC) parts.push(pub(i));
7284
- parts.push(emitTerm(kids[i], vn, tmp(), L, skipFor(L), sinks));
7335
+ parts.push(emitTerm(kids[i], vn, tmp(), L, skipFor(L)));
7285
7336
  names.push(vn);
7286
7337
  }
7287
7338
  parts.push("EC.e=cur");
@@ -7382,11 +7433,11 @@ return FAIL
7382
7433
  const other = otherIp >= 0 ? link(otherIp) : void 0;
7383
7434
  const otherRouted = code[ip + 4] === 1;
7384
7435
  const n = code[ip + 5];
7436
+ validateDispatchSpec(spec, n, code[ip + 4]);
7385
7437
  const armBase = ip + 6;
7386
7438
  const arms = [];
7387
7439
  for (let i = 0; i < n; i++) arms.push(link(code[armBase + i]));
7388
7440
  const bk = hoist("bk", `DSP[${di}].byKey`);
7389
- const rt = hoist("rt", `DSP[${di}].routed`);
7390
7441
  const dx = hoist("dx", `DSP[${di}].expected`);
7391
7442
  const claims = (m) => {
7392
7443
  switch (m[0]) {
@@ -7410,6 +7461,15 @@ ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${claims(m)})arm=${m[3]}
7410
7461
  ` : "";
7411
7462
  const m1 = tmp();
7412
7463
  const m2 = tmp();
7464
+ const routedCall = (target) => `{const savedRouted=ctx._routed
7465
+ ${emitRollback(m1, L.buf, sinks)}
7466
+ ${emitMark(m2, L.buf, sinks, false)}
7467
+ ctx._routed={value:key,span:{start:pos,end:selEnd}}
7468
+ try{v=${target}(input,pos,ctx)}finally{ctx._routed=savedRouted}
7469
+ break}`;
7470
+ const plainCall = (target) => `v=${target}(input,selEnd,ctx);break`;
7471
+ const armCases = arms.map((target, i) => `case ${i}:${spec.routed[i] === 1 ? routedCall(target) : plainCall(target)}`).join("\n");
7472
+ const fallbackCase = other === void 0 ? "" : `default:${otherRouted ? routedCall(other) : plainCall(other)}`;
7413
7473
  return `${head}
7414
7474
  ${emitMark(m1, L.buf, sinks)}
7415
7475
  const sv=${selector}(input,pos,ctx)
@@ -7417,24 +7477,16 @@ if(sv===FAIL)return FAIL
7417
7477
  const selEnd=EC.e
7418
7478
  const key=sv
7419
7479
  let arm=${bk}.get(key)
7420
- ${fold}${chain}let ur
7480
+ ${fold}${chain}
7421
7481
  if(arm===undefined){
7422
- ${other === void 0 ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : `ur=${String(otherRouted)}`}
7423
- }else ur=${rt}[arm]===1
7424
- const savedRouted=ctx._routed
7425
- ${emitMark(m2, L.buf, sinks)}
7426
- if(ur){
7427
- ${emitRollback(m1, L.buf, sinks)}
7428
- ${emitMark(m2, L.buf, sinks, false)}
7429
- ctx._routed={value:key,span:{start:pos,end:selEnd}}
7482
+ ${other === void 0 ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : ""}
7430
7483
  }
7431
- const at=ur?pos:selEnd
7484
+ ${emitMark(m2, L.buf, sinks)}
7432
7485
  let v
7433
7486
  switch(arm){
7434
- ${arms.map((a, i) => `case ${i}:v=${a}(input,at,ctx);break`).join("\n")}
7435
- ${other === void 0 ? "" : `default:v=${other}(input,at,ctx)`}
7487
+ ${armCases}
7488
+ ${fallbackCase}
7436
7489
  }
7437
- if(ur)ctx._routed=savedRouted
7438
7490
  if(v===FAIL){
7439
7491
  ${emitRollback(m2, L.buf, sinks)}
7440
7492
  ctx._fc=true
@@ -7809,7 +7861,9 @@ function sequence(...parsers) {
7809
7861
  continue;
7810
7862
  }
7811
7863
  if (ctx.trivia && i > 0) {
7812
- const mark = saveTriviaMark(ctx);
7864
+ const mTlog = cstTlLen(ctx);
7865
+ const mLog = ctx._triviaLog?.length ?? 0;
7866
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
7813
7867
  let scanEnd;
7814
7868
  if (needsDeferredTriviaCommit(ctx)) {
7815
7869
  const scan = scanTrivia(input, cur, ctx);
@@ -7818,10 +7872,13 @@ function sequence(...parsers) {
7818
7872
  } else {
7819
7873
  scanEnd = advanceTrivia(input, cur, ctx);
7820
7874
  }
7875
+ const scanTlog = cstTlLen(ctx);
7876
+ const scanLog = ctx._triviaLog?.length ?? 0;
7877
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
7821
7878
  const result2 = parsers[i].parse(input, scanEnd, ctx);
7822
7879
  if (!result2.ok) return result2;
7823
7880
  if (result2.span.end > scanEnd) cur = result2.span.end;
7824
- else rollbackTrivia(ctx, mark);
7881
+ else rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
7825
7882
  if (values !== void 0) values.push(result2.value);
7826
7883
  continue;
7827
7884
  }
@@ -7852,7 +7909,9 @@ function sequence(...parsers) {
7852
7909
  }
7853
7910
  if (ctx.trivia && i > 0) {
7854
7911
  let scanEnd;
7855
- const mark = saveTriviaMark(ctx);
7912
+ const mTlog = cstTlLen(ctx);
7913
+ const mLog = ctx._triviaLog?.length ?? 0;
7914
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
7856
7915
  if (needsDeferredTriviaCommit(ctx)) {
7857
7916
  const scan = scanTrivia(input, cur, ctx);
7858
7917
  scan.commit();
@@ -7860,10 +7919,13 @@ function sequence(...parsers) {
7860
7919
  } else {
7861
7920
  scanEnd = advanceTrivia(input, cur, ctx);
7862
7921
  }
7922
+ const scanTlog = cstTlLen(ctx);
7923
+ const scanLog = ctx._triviaLog?.length ?? 0;
7924
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
7863
7925
  const result2 = parsers[i].parse(input, scanEnd, ctx);
7864
7926
  if (!result2.ok) return result2;
7865
7927
  if (result2.span.end > scanEnd) cur = result2.span.end;
7866
- else rollbackTrivia(ctx, mark);
7928
+ else rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
7867
7929
  if (values !== void 0) values.push(result2.value);
7868
7930
  continue;
7869
7931
  }
@@ -7891,7 +7953,9 @@ function sequence(...parsers) {
7891
7953
  for (let i = 0; i < parsers.length; i++) {
7892
7954
  if (ctx.trivia && i > 0) {
7893
7955
  let scanEnd;
7894
- let mark = saveTriviaMark(ctx);
7956
+ const mTlog = cstTlLen(ctx);
7957
+ const mLog = ctx._triviaLog?.length ?? 0;
7958
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
7895
7959
  if (needsDeferredTriviaCommit(ctx)) {
7896
7960
  const scan = scanTrivia(input, cur, ctx);
7897
7961
  scan.commit();
@@ -7899,12 +7963,15 @@ function sequence(...parsers) {
7899
7963
  } else {
7900
7964
  scanEnd = advanceTrivia(input, cur, ctx);
7901
7965
  }
7966
+ const scanTlog = cstTlLen(ctx);
7967
+ const scanLog = ctx._triviaLog?.length ?? 0;
7968
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
7902
7969
  const result2 = parsers[i].parse(input, scanEnd, ctx);
7903
7970
  if (!result2.ok) return result2;
7904
7971
  if (result2.span.end > scanEnd) {
7905
7972
  cur = result2.span.end;
7906
7973
  } else {
7907
- rollbackTrivia(ctx, mark);
7974
+ rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
7908
7975
  }
7909
7976
  if (values !== void 0) values.push(result2.value);
7910
7977
  continue;
@@ -8269,7 +8336,7 @@ function committed(c) {
8269
8336
  }
8270
8337
  function stampRuleMap(prog, d, artifactMetadata = {}, resolved = resolveTable(prog)) {
8271
8338
  const triviaOfRule = (ip) => {
8272
- if (prog.code[ip] !== OP_SCOPE) return void 0;
8339
+ if (prog.code[ip] !== OP_SCOPE_PLAIN && prog.code[ip] !== OP_SCOPE) return void 0;
8273
8340
  const slot = prog.code[ip + 1];
8274
8341
  return slot < 0 ? void 0 : resolved.trivia[slot];
8275
8342
  };
@@ -8483,20 +8550,19 @@ function assemble(t2, prog, cfg) {
8483
8550
  TERMV = v2;
8484
8551
  return EC.e > scanEnd2 ? EC.e : cur;
8485
8552
  }
8486
- const need = markCst(ctx);
8487
- const mRaw = MRAW;
8488
- const mTl = MTL;
8489
- const mLv = MLV;
8490
- const mFl = need ? ctx._fields?.length ?? 0 : 0;
8491
- const mEr = need ? ctx._errors?.length ?? 0 : 0;
8553
+ const need = rollbackNeeded(ctx);
8554
+ const mTl = need ? cstTlLen(ctx) : 0;
8492
8555
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
8493
8556
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
8494
8557
  const scanEnd = skipTrivia(input, cur, ctx);
8558
+ const scanTl = need ? cstTlLen(ctx) : 0;
8559
+ const scanLog = need ? ctx._triviaLog?.length ?? 0 : 0;
8560
+ const scanRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
8495
8561
  const v = child(input, scanEnd, ctx);
8496
8562
  if (v === FAIL) return -1;
8497
8563
  TERMV = v;
8498
8564
  if (EC.e > scanEnd) return EC.e;
8499
- if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
8565
+ if (need) rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
8500
8566
  return cur;
8501
8567
  }
8502
8568
  function committed2(c) {
@@ -8910,7 +8976,8 @@ function assemble(t2, prog, cfg) {
8910
8976
  };
8911
8977
  }
8912
8978
  case OP_SCOPE:
8913
- case OP_SCOPE_CAP: {
8979
+ case OP_SCOPE_CAP:
8980
+ case OP_SCOPE_PLAIN: {
8914
8981
  const ki = code[ip + 1];
8915
8982
  const scopeTrivia = ki < 0 ? void 0 : trivia2[ki];
8916
8983
  const scopeLabels = scopeTrivia?._meta.triviaKindLabels;
@@ -8944,7 +9011,7 @@ function assemble(t2, prog, cfg) {
8944
9011
  SCAN = savedScan;
8945
9012
  return v;
8946
9013
  };
8947
- return scopeRootPolicy(scopePiece, code[ip + 3]);
9014
+ return scopeRootPolicy(scopePiece, code[ip] === OP_SCOPE_PLAIN ? 0 : code[ip + 3]);
8948
9015
  }
8949
9016
  case OP_ROUTED: {
8950
9017
  const fb = code[ip + 1];
@@ -9860,15 +9927,21 @@ function assemble(t2, prog, cfg) {
9860
9927
  target = arms[arm];
9861
9928
  usesRouted = routed2[arm] === 1;
9862
9929
  }
9863
- const savedRouted = ctx._routed;
9864
9930
  let mark = saveTriviaMark(ctx);
9931
+ let v;
9865
9932
  if (usesRouted) {
9933
+ const savedRouted = ctx._routed;
9866
9934
  rollbackTrivia(ctx, selectorMark);
9867
9935
  mark = saveTriviaMark(ctx);
9868
9936
  ctx._routed = { value: key, span: { start: pos, end: selEnd } };
9937
+ try {
9938
+ v = target(input, pos, ctx);
9939
+ } finally {
9940
+ ctx._routed = savedRouted;
9941
+ }
9942
+ } else {
9943
+ v = target(input, selEnd, ctx);
9869
9944
  }
9870
- const v = target(input, usesRouted ? pos : selEnd, ctx);
9871
- if (usesRouted) ctx._routed = savedRouted;
9872
9945
  if (v === FAIL) {
9873
9946
  rollbackTrivia(ctx, mark);
9874
9947
  ctx._fc = true;
@@ -10014,6 +10087,11 @@ function assemble(t2, prog, cfg) {
10014
10087
  if (s.sentinel !== void 0) extraIps.push(s.sentinel[0]);
10015
10088
  }
10016
10089
  for (const set of prog.scanSkip ?? []) for (const r of set) extraIps.push(r[0]);
10090
+ const validationRoots = [...Object.values(prog.rules), ...extraIps];
10091
+ for (const ip of reachableSites(code, validationRoots)) {
10092
+ if (code[ip] !== OP_DISPATCH) continue;
10093
+ validateDispatchSpec(dsp[code[ip + 2]], code[ip + 5], code[ip + 4]);
10094
+ }
10017
10095
  const pre = cfg.hostCaptureTrivia === void 0 ? prog.asm?.find((a) => a.key === cfgKey(cfg)) : void 0;
10018
10096
  if (pre !== void 0) {
10019
10097
  const pools = rebuildPools(t2.cc, t2.fx, pre.plan);
@@ -10040,6 +10118,7 @@ function assemble(t2, prog, cfg) {
10040
10118
  pushCstLeaf,
10041
10119
  pushCstChild,
10042
10120
  rollbackTriviaAt,
10121
+ rollbackScannedTriviaAt,
10043
10122
  failAt,
10044
10123
  classHas,
10045
10124
  consumeTrivia,
@@ -10110,6 +10189,7 @@ function assemble(t2, prog, cfg) {
10110
10189
  pushCstLeaf,
10111
10190
  pushCstChild,
10112
10191
  rollbackTriviaAt,
10192
+ rollbackScannedTriviaAt,
10113
10193
  failAt,
10114
10194
  classHas,
10115
10195
  consumeTrivia,
@@ -10342,6 +10422,14 @@ function tableRules(source, artifactMetadata = {}) {
10342
10422
  function jsString(s) {
10343
10423
  return JSON.stringify(s);
10344
10424
  }
10425
+ function emitClassPool(classes) {
10426
+ const array = `[${classes.map(jsString).join(",")}]`;
10427
+ if (classes.length < 2) return array;
10428
+ const delimiter = "|/~?^`".split("").find((ch2) => classes.every((spec) => !spec.includes(ch2)));
10429
+ if (delimiter === void 0) return array;
10430
+ const split = `${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
10431
+ return split.length < array.length ? split : array;
10432
+ }
10345
10433
  function emitConst(v) {
10346
10434
  if (v instanceof RegExp) return `/${v.source}/${v.flags}`;
10347
10435
  if (typeof v === "string") return jsString(v);
@@ -10420,7 +10508,7 @@ function programFields(prog, fns, opts = {}) {
10420
10508
  ...emitAssemblies(prog, opts.assemblies ?? []),
10421
10509
  `c:[${prog.code.join(",")}],`,
10422
10510
  `k:[${prog.k.map(emitConst).join(",")}],`,
10423
- `x:[${prog.cc.map(jsString).join(",")}],`,
10511
+ `x:${emitClassPool(prog.cc)},`,
10424
10512
  `e:[${prog.fx.map((f) => `[${f.map(jsString).join(",")}]`).join(",")}],`,
10425
10513
  `d:[${prog.disp.map((a) => `[${a.join(",")}]`).join(",")}],`,
10426
10514
  `r:${JSON.stringify(prog.rules)},`,