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
package/dist/cli/index.js CHANGED
@@ -52,6 +52,13 @@ function empty() {
52
52
  function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve2) {
53
53
  if (seen.has(p)) return true;
54
54
  seen.add(p);
55
+ try {
56
+ return matchesEmptyBody(p, seen, resolve2);
57
+ } finally {
58
+ seen.delete(p);
59
+ }
60
+ }
61
+ function matchesEmptyBody(p, seen, resolve2) {
55
62
  const me = (c) => matchesEmpty(c, seen, resolve2);
56
63
  const d = p._def;
57
64
  switch (d.tag) {
@@ -153,6 +160,13 @@ function sequenceFirstSet(parsers) {
153
160
  function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve2) {
154
161
  if (seen.has(p)) return any();
155
162
  seen.add(p);
163
+ try {
164
+ return firstSetBody(p, seen, resolve2);
165
+ } finally {
166
+ seen.delete(p);
167
+ }
168
+ }
169
+ function firstSetBody(p, seen, resolve2) {
156
170
  const fs = (c) => firstSetOf(c, seen, resolve2);
157
171
  const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve2);
158
172
  const d = p._def;
@@ -2501,6 +2515,23 @@ function rollbackTrivia(ctx, mark) {
2501
2515
  if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
2502
2516
  if (ctx._rootTriviaLog && ctx._rootTriviaLog.length !== mark.rootLog) ctx._rootTriviaLog.length = mark.rootLog;
2503
2517
  }
2518
+ function removeNumberRange(values, start, end) {
2519
+ if (values === void 0 || end <= start) return;
2520
+ if (values.length > end) values.copyWithin(start, end);
2521
+ values.length -= end - start;
2522
+ }
2523
+ function rollbackScannedTriviaAt(ctx, tlogStart, tlogEnd, logStart, logEnd, rootLogStart, rootLogEnd) {
2524
+ const b = ctx._cstBuf;
2525
+ if (b !== void 0) {
2526
+ const tlog = b.tl;
2527
+ removeNumberRange(tlog, tlogStart, tlogEnd);
2528
+ if (tlog !== void 0 && tlog.length === 0) b.tl = void 0;
2529
+ } else {
2530
+ removeNumberRange(ctx._cstTriviaLog, tlogStart, tlogEnd);
2531
+ }
2532
+ removeNumberRange(ctx._triviaLog, logStart, logEnd);
2533
+ removeNumberRange(ctx._rootTriviaLog, rootLogStart, rootLogEnd);
2534
+ }
2504
2535
  function parseTriviaNoCapture(triviaP, input, cur, ctx) {
2505
2536
  const probeCtx = createDetachedParseContext(ctx.trackLines, ctx.state);
2506
2537
  probeCtx._lineIndex = ctx._lineIndex;
@@ -3204,7 +3235,9 @@ function sequence(...parsers) {
3204
3235
  continue;
3205
3236
  }
3206
3237
  if (ctx.trivia && i > 0) {
3207
- const mark = saveTriviaMark(ctx);
3238
+ const mTlog = cstTlLen(ctx);
3239
+ const mLog = ctx._triviaLog?.length ?? 0;
3240
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3208
3241
  let scanEnd;
3209
3242
  if (needsDeferredTriviaCommit(ctx)) {
3210
3243
  const scan = scanTrivia(input, cur, ctx);
@@ -3213,10 +3246,13 @@ function sequence(...parsers) {
3213
3246
  } else {
3214
3247
  scanEnd = advanceTrivia(input, cur, ctx);
3215
3248
  }
3249
+ const scanTlog = cstTlLen(ctx);
3250
+ const scanLog = ctx._triviaLog?.length ?? 0;
3251
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3216
3252
  const result2 = parsers[i].parse(input, scanEnd, ctx);
3217
3253
  if (!result2.ok) return result2;
3218
3254
  if (result2.span.end > scanEnd) cur = result2.span.end;
3219
- else rollbackTrivia(ctx, mark);
3255
+ else rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
3220
3256
  if (values !== void 0) values.push(result2.value);
3221
3257
  continue;
3222
3258
  }
@@ -3247,7 +3283,9 @@ function sequence(...parsers) {
3247
3283
  }
3248
3284
  if (ctx.trivia && i > 0) {
3249
3285
  let scanEnd;
3250
- const mark = saveTriviaMark(ctx);
3286
+ const mTlog = cstTlLen(ctx);
3287
+ const mLog = ctx._triviaLog?.length ?? 0;
3288
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3251
3289
  if (needsDeferredTriviaCommit(ctx)) {
3252
3290
  const scan = scanTrivia(input, cur, ctx);
3253
3291
  scan.commit();
@@ -3255,10 +3293,13 @@ function sequence(...parsers) {
3255
3293
  } else {
3256
3294
  scanEnd = advanceTrivia(input, cur, ctx);
3257
3295
  }
3296
+ const scanTlog = cstTlLen(ctx);
3297
+ const scanLog = ctx._triviaLog?.length ?? 0;
3298
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3258
3299
  const result2 = parsers[i].parse(input, scanEnd, ctx);
3259
3300
  if (!result2.ok) return result2;
3260
3301
  if (result2.span.end > scanEnd) cur = result2.span.end;
3261
- else rollbackTrivia(ctx, mark);
3302
+ else rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
3262
3303
  if (values !== void 0) values.push(result2.value);
3263
3304
  continue;
3264
3305
  }
@@ -3286,7 +3327,9 @@ function sequence(...parsers) {
3286
3327
  for (let i = 0; i < parsers.length; i++) {
3287
3328
  if (ctx.trivia && i > 0) {
3288
3329
  let scanEnd;
3289
- let mark = saveTriviaMark(ctx);
3330
+ const mTlog = cstTlLen(ctx);
3331
+ const mLog = ctx._triviaLog?.length ?? 0;
3332
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3290
3333
  if (needsDeferredTriviaCommit(ctx)) {
3291
3334
  const scan = scanTrivia(input, cur, ctx);
3292
3335
  scan.commit();
@@ -3294,12 +3337,15 @@ function sequence(...parsers) {
3294
3337
  } else {
3295
3338
  scanEnd = advanceTrivia(input, cur, ctx);
3296
3339
  }
3340
+ const scanTlog = cstTlLen(ctx);
3341
+ const scanLog = ctx._triviaLog?.length ?? 0;
3342
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3297
3343
  const result2 = parsers[i].parse(input, scanEnd, ctx);
3298
3344
  if (!result2.ok) return result2;
3299
3345
  if (result2.span.end > scanEnd) {
3300
3346
  cur = result2.span.end;
3301
3347
  } else {
3302
- rollbackTrivia(ctx, mark);
3348
+ rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
3303
3349
  }
3304
3350
  if (values !== void 0) values.push(result2.value);
3305
3351
  continue;
@@ -5293,6 +5339,7 @@ var OP_LIVE = 37;
5293
5339
  var OP_ATTEMPT = 38;
5294
5340
  var OP_LABEL = 39;
5295
5341
  var OP_COV = 40;
5342
+ var OP_SCOPE_PLAIN = 41;
5296
5343
  var OP_DISPATCH = 25;
5297
5344
  var OP_ROUTED = 26;
5298
5345
  var OP_NAMES = {
@@ -5335,7 +5382,8 @@ var OP_NAMES = {
5335
5382
  [OP_LIVE]: "LIVE",
5336
5383
  [OP_ATTEMPT]: "ATTEMPT",
5337
5384
  [OP_LABEL]: "LABEL",
5338
- [OP_COV]: "COV"
5385
+ [OP_COV]: "COV",
5386
+ [OP_SCOPE_PLAIN]: "SCOPE_PLAIN"
5339
5387
  };
5340
5388
 
5341
5389
  // src/table/program.ts
@@ -5393,6 +5441,15 @@ function expandCompact(p) {
5393
5441
  ...p.a === void 0 ? {} : { asm: p.a }
5394
5442
  });
5395
5443
  }
5444
+ function validateDispatchSpec(spec, arity, fallbackRouted) {
5445
+ const invalid = (arms) => {
5446
+ for (const arm of arms) if (!Number.isInteger(arm) || arm < 0 || arm >= arity) return true;
5447
+ return false;
5448
+ };
5449
+ 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]]))) {
5450
+ throw new TypeError("table: malformed dispatch");
5451
+ }
5452
+ }
5396
5453
  var TABLE_RUNTIME = /* @__PURE__ */ Symbol("parseman.tableRuntime");
5397
5454
  function ownTableProgram(prog, resolved) {
5398
5455
  return { ...prog, [TABLE_RUNTIME]: { resolved } };
@@ -5951,7 +6008,7 @@ var Encoder = class {
5951
6008
  this.carryTriviaMeta(amb);
5952
6009
  this.carryTriviaMeta(p);
5953
6010
  if (p._def.tag === "grammar") this.carryTriviaMeta(p._def.triviaParser);
5954
- this.rules[name] = amb === void 0 ? body : this.emit(OP_SCOPE, this.triviaSlot(amb), body);
6011
+ this.rules[name] = amb === void 0 ? body : this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), body);
5955
6012
  }
5956
6013
  /**
5957
6014
  * The row a cross-rule `g.X` reference jumps to — the target's body, RE-WRAPPED
@@ -5994,7 +6051,7 @@ var Encoder = class {
5994
6051
  const amb = p._meta.grammarTrivia ?? target._meta.grammarTrivia;
5995
6052
  if (amb === void 0 || this.activeTrivia !== void 0) return ip;
5996
6053
  if (!hasOwnTriviaBoundary(target)) return ip;
5997
- return this.emit(OP_SCOPE, this.triviaSlot(amb), ip);
6054
+ return this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), ip);
5998
6055
  }
5999
6056
  node(p) {
6000
6057
  const lazyRef = p._def.tag === "lazy";
@@ -6399,6 +6456,7 @@ var Encoder = class {
6399
6456
  return [ip + 1];
6400
6457
  case OP_SCOPE:
6401
6458
  case OP_SCOPE_CAP:
6459
+ case OP_SCOPE_PLAIN:
6402
6460
  case OP_WITHCTX:
6403
6461
  case OP_XFORM:
6404
6462
  case OP_LEAF:
@@ -7589,6 +7647,7 @@ function childSlots(code, ip, out) {
7589
7647
  case OP_GATE:
7590
7648
  case OP_SCOPE:
7591
7649
  case OP_SCOPE_CAP:
7650
+ case OP_SCOPE_PLAIN:
7592
7651
  case OP_WITHCTX:
7593
7652
  case OP_XFORM:
7594
7653
  case OP_NODE:
@@ -7677,7 +7736,7 @@ function reachableSites(code, roots) {
7677
7736
  }
7678
7737
  function transfer(code, ip, at, hostCst) {
7679
7738
  const op = code[ip];
7680
- if (op === OP_SCOPE || op === OP_SCOPE_CAP) {
7739
+ if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
7681
7740
  const ki = code[ip + 1];
7682
7741
  const tri = ki < 0 ? TRI_NONE : ki;
7683
7742
  const cap = op === OP_SCOPE_CAP ? CAP_ON : at.cap;
@@ -7758,6 +7817,7 @@ var EMITTED_PARAMS = [
7758
7817
  "pushCstLeaf",
7759
7818
  "pushCstChild",
7760
7819
  "rollbackTriviaAt",
7820
+ "rollbackScannedTriviaAt",
7761
7821
  "failAt",
7762
7822
  "classHas",
7763
7823
  "consumeTrivia",
@@ -7901,19 +7961,24 @@ if(ctx._errors!==undefined&&ctx._errors.length!==${t2}er)ctx._errors.length=${t2
7901
7961
  if (!s.fd && !s.er) return `if(${t2}n)rollbackTriviaAt(ctx,${t2}raw,${t2}tl,${t2}lv,0,undefined,${t2}lg,${t2}rt)`;
7902
7962
  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)}`;
7903
7963
  }
7904
- function emitTerm(callee, dst, t2, l, skip, s) {
7964
+ function emitTerm(callee, dst, t2, l, skip) {
7905
7965
  const fast = `const ${t2}v=${callee}(input,cur,ctx)
7906
7966
  if(${t2}v===FAIL)return FAIL
7907
7967
  ${dst}=${t2}v
7908
7968
  cur=EC.e`;
7909
7969
  if (l.tri === TRI_NONE) return fast;
7910
- const scanned = `${emitMark(t2, l.buf, s)}
7970
+ const scanned = `const ${t2}tl=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
7971
+ const ${t2}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
7972
+ const ${t2}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
7911
7973
  const ${t2}s=${skip}(input,cur,ctx)
7974
+ const ${t2}stl=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
7975
+ const ${t2}slg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
7976
+ const ${t2}srt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
7912
7977
  const ${t2}v=${callee}(input,${t2}s,ctx)
7913
7978
  if(${t2}v===FAIL)return FAIL
7914
7979
  ${dst}=${t2}v
7915
7980
  if(EC.e>${t2}s)cur=EC.e
7916
- else{${emitRollback(t2, l.buf, s)}}`;
7981
+ else{rollbackScannedTriviaAt(ctx,${t2}tl,${t2}stl,${t2}lg,${t2}slg,${t2}rt,${t2}srt)}`;
7917
7982
  if (l.tri !== TRI_UNKNOWN) return scanned;
7918
7983
  return `if(ctx.trivia===undefined){
7919
7984
  ${fast}
@@ -8076,7 +8141,7 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
8076
8141
  const op = code[ip];
8077
8142
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2];
8078
8143
  if (op === OP_RULE) return code[ip + 1];
8079
- if (op === OP_SCOPE && code[ip + 3] === 0 && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
8144
+ if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
8080
8145
  return code[ip + 2];
8081
8146
  }
8082
8147
  return void 0;
@@ -8244,10 +8309,11 @@ return r.value
8244
8309
  }`;
8245
8310
  }
8246
8311
  case OP_SCOPE:
8247
- case OP_SCOPE_CAP: {
8312
+ case OP_SCOPE_CAP:
8313
+ case OP_SCOPE_PLAIN: {
8248
8314
  const ki = code[ip + 1];
8249
8315
  const cap = op === OP_SCOPE_CAP;
8250
- const flags = code[ip + 3];
8316
+ const flags = op === OP_SCOPE_PLAIN ? 0 : code[ip + 3];
8251
8317
  const child = link(code[ip + 2]);
8252
8318
  const scanFor = swapLegal && ki >= 0 && !triviaLabelled[ki] ? hoist("ts", `TRIVIASCAN[${ki}]`) : "null";
8253
8319
  const tri = ki < 0 ? "undefined" : hoist("tv", `TRIVIA[${ki}]`);
@@ -8401,7 +8467,7 @@ return v
8401
8467
  const vn = `v${i}`;
8402
8468
  parts.push(`let ${vn}`);
8403
8469
  if (REC) parts.push(pub(i));
8404
- parts.push(emitTerm(kids[i], vn, tmp(), L, skipFor(L), sinks));
8470
+ parts.push(emitTerm(kids[i], vn, tmp(), L, skipFor(L)));
8405
8471
  names.push(vn);
8406
8472
  }
8407
8473
  parts.push("EC.e=cur");
@@ -8502,11 +8568,11 @@ return FAIL
8502
8568
  const other = otherIp >= 0 ? link(otherIp) : void 0;
8503
8569
  const otherRouted = code[ip + 4] === 1;
8504
8570
  const n = code[ip + 5];
8571
+ validateDispatchSpec(spec, n, code[ip + 4]);
8505
8572
  const armBase = ip + 6;
8506
8573
  const arms = [];
8507
8574
  for (let i = 0; i < n; i++) arms.push(link(code[armBase + i]));
8508
8575
  const bk = hoist("bk", `DSP[${di}].byKey`);
8509
- const rt = hoist("rt", `DSP[${di}].routed`);
8510
8576
  const dx = hoist("dx", `DSP[${di}].expected`);
8511
8577
  const claims = (m) => {
8512
8578
  switch (m[0]) {
@@ -8530,6 +8596,15 @@ ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${claims(m)})arm=${m[3]}
8530
8596
  ` : "";
8531
8597
  const m1 = tmp();
8532
8598
  const m2 = tmp();
8599
+ const routedCall = (target) => `{const savedRouted=ctx._routed
8600
+ ${emitRollback(m1, L.buf, sinks)}
8601
+ ${emitMark(m2, L.buf, sinks, false)}
8602
+ ctx._routed={value:key,span:{start:pos,end:selEnd}}
8603
+ try{v=${target}(input,pos,ctx)}finally{ctx._routed=savedRouted}
8604
+ break}`;
8605
+ const plainCall = (target) => `v=${target}(input,selEnd,ctx);break`;
8606
+ const armCases = arms.map((target, i) => `case ${i}:${spec.routed[i] === 1 ? routedCall(target) : plainCall(target)}`).join("\n");
8607
+ const fallbackCase = other === void 0 ? "" : `default:${otherRouted ? routedCall(other) : plainCall(other)}`;
8533
8608
  return `${head}
8534
8609
  ${emitMark(m1, L.buf, sinks)}
8535
8610
  const sv=${selector}(input,pos,ctx)
@@ -8537,24 +8612,16 @@ if(sv===FAIL)return FAIL
8537
8612
  const selEnd=EC.e
8538
8613
  const key=sv
8539
8614
  let arm=${bk}.get(key)
8540
- ${fold}${chain}let ur
8615
+ ${fold}${chain}
8541
8616
  if(arm===undefined){
8542
- ${other === void 0 ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : `ur=${String(otherRouted)}`}
8543
- }else ur=${rt}[arm]===1
8544
- const savedRouted=ctx._routed
8545
- ${emitMark(m2, L.buf, sinks)}
8546
- if(ur){
8547
- ${emitRollback(m1, L.buf, sinks)}
8548
- ${emitMark(m2, L.buf, sinks, false)}
8549
- ctx._routed={value:key,span:{start:pos,end:selEnd}}
8617
+ ${other === void 0 ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : ""}
8550
8618
  }
8551
- const at=ur?pos:selEnd
8619
+ ${emitMark(m2, L.buf, sinks)}
8552
8620
  let v
8553
8621
  switch(arm){
8554
- ${arms.map((a, i) => `case ${i}:v=${a}(input,at,ctx);break`).join("\n")}
8555
- ${other === void 0 ? "" : `default:v=${other}(input,at,ctx)`}
8622
+ ${armCases}
8623
+ ${fallbackCase}
8556
8624
  }
8557
- if(ur)ctx._routed=savedRouted
8558
8625
  if(v===FAIL){
8559
8626
  ${emitRollback(m2, L.buf, sinks)}
8560
8627
  ctx._fc=true
@@ -8879,7 +8946,7 @@ function committed(c) {
8879
8946
  }
8880
8947
  function stampRuleMap(prog, d, artifactMetadata = {}, resolved = resolveTable(prog)) {
8881
8948
  const triviaOfRule = (ip) => {
8882
- if (prog.code[ip] !== OP_SCOPE) return void 0;
8949
+ if (prog.code[ip] !== OP_SCOPE_PLAIN && prog.code[ip] !== OP_SCOPE) return void 0;
8883
8950
  const slot = prog.code[ip + 1];
8884
8951
  return slot < 0 ? void 0 : resolved.trivia[slot];
8885
8952
  };
@@ -9093,20 +9160,19 @@ function assemble(t2, prog, cfg) {
9093
9160
  TERMV = v2;
9094
9161
  return EC.e > scanEnd2 ? EC.e : cur;
9095
9162
  }
9096
- const need = markCst(ctx);
9097
- const mRaw = MRAW;
9098
- const mTl = MTL;
9099
- const mLv = MLV;
9100
- const mFl = need ? ctx._fields?.length ?? 0 : 0;
9101
- const mEr = need ? ctx._errors?.length ?? 0 : 0;
9163
+ const need = rollbackNeeded(ctx);
9164
+ const mTl = need ? cstTlLen(ctx) : 0;
9102
9165
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
9103
9166
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
9104
9167
  const scanEnd = skipTrivia(input, cur, ctx);
9168
+ const scanTl = need ? cstTlLen(ctx) : 0;
9169
+ const scanLog = need ? ctx._triviaLog?.length ?? 0 : 0;
9170
+ const scanRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
9105
9171
  const v = child(input, scanEnd, ctx);
9106
9172
  if (v === FAIL) return -1;
9107
9173
  TERMV = v;
9108
9174
  if (EC.e > scanEnd) return EC.e;
9109
- if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
9175
+ if (need) rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
9110
9176
  return cur;
9111
9177
  }
9112
9178
  function committed2(c) {
@@ -9520,7 +9586,8 @@ function assemble(t2, prog, cfg) {
9520
9586
  };
9521
9587
  }
9522
9588
  case OP_SCOPE:
9523
- case OP_SCOPE_CAP: {
9589
+ case OP_SCOPE_CAP:
9590
+ case OP_SCOPE_PLAIN: {
9524
9591
  const ki = code[ip + 1];
9525
9592
  const scopeTrivia = ki < 0 ? void 0 : trivia2[ki];
9526
9593
  const scopeLabels = scopeTrivia?._meta.triviaKindLabels;
@@ -9554,7 +9621,7 @@ function assemble(t2, prog, cfg) {
9554
9621
  SCAN = savedScan;
9555
9622
  return v;
9556
9623
  };
9557
- return scopeRootPolicy(scopePiece, code[ip + 3]);
9624
+ return scopeRootPolicy(scopePiece, code[ip] === OP_SCOPE_PLAIN ? 0 : code[ip + 3]);
9558
9625
  }
9559
9626
  case OP_ROUTED: {
9560
9627
  const fb = code[ip + 1];
@@ -10470,15 +10537,21 @@ function assemble(t2, prog, cfg) {
10470
10537
  target = arms[arm];
10471
10538
  usesRouted = routed2[arm] === 1;
10472
10539
  }
10473
- const savedRouted = ctx._routed;
10474
10540
  let mark = saveTriviaMark(ctx);
10541
+ let v;
10475
10542
  if (usesRouted) {
10543
+ const savedRouted = ctx._routed;
10476
10544
  rollbackTrivia(ctx, selectorMark);
10477
10545
  mark = saveTriviaMark(ctx);
10478
10546
  ctx._routed = { value: key, span: { start: pos, end: selEnd } };
10547
+ try {
10548
+ v = target(input, pos, ctx);
10549
+ } finally {
10550
+ ctx._routed = savedRouted;
10551
+ }
10552
+ } else {
10553
+ v = target(input, selEnd, ctx);
10479
10554
  }
10480
- const v = target(input, usesRouted ? pos : selEnd, ctx);
10481
- if (usesRouted) ctx._routed = savedRouted;
10482
10555
  if (v === FAIL) {
10483
10556
  rollbackTrivia(ctx, mark);
10484
10557
  ctx._fc = true;
@@ -10624,6 +10697,11 @@ function assemble(t2, prog, cfg) {
10624
10697
  if (s.sentinel !== void 0) extraIps.push(s.sentinel[0]);
10625
10698
  }
10626
10699
  for (const set of prog.scanSkip ?? []) for (const r of set) extraIps.push(r[0]);
10700
+ const validationRoots = [...Object.values(prog.rules), ...extraIps];
10701
+ for (const ip of reachableSites(code, validationRoots)) {
10702
+ if (code[ip] !== OP_DISPATCH) continue;
10703
+ validateDispatchSpec(dsp[code[ip + 2]], code[ip + 5], code[ip + 4]);
10704
+ }
10627
10705
  const pre = cfg.hostCaptureTrivia === void 0 ? prog.asm?.find((a) => a.key === cfgKey(cfg)) : void 0;
10628
10706
  if (pre !== void 0) {
10629
10707
  const pools = rebuildPools(t2.cc, t2.fx, pre.plan);
@@ -10650,6 +10728,7 @@ function assemble(t2, prog, cfg) {
10650
10728
  pushCstLeaf,
10651
10729
  pushCstChild,
10652
10730
  rollbackTriviaAt,
10731
+ rollbackScannedTriviaAt,
10653
10732
  failAt,
10654
10733
  classHas,
10655
10734
  consumeTrivia,
@@ -10720,6 +10799,7 @@ function assemble(t2, prog, cfg) {
10720
10799
  pushCstLeaf,
10721
10800
  pushCstChild,
10722
10801
  rollbackTriviaAt,
10802
+ rollbackScannedTriviaAt,
10723
10803
  failAt,
10724
10804
  classHas,
10725
10805
  consumeTrivia,
@@ -10952,6 +11032,14 @@ function tableRules(source, artifactMetadata = {}) {
10952
11032
  function jsString(s) {
10953
11033
  return JSON.stringify(s);
10954
11034
  }
11035
+ function emitClassPool(classes) {
11036
+ const array = `[${classes.map(jsString).join(",")}]`;
11037
+ if (classes.length < 2) return array;
11038
+ const delimiter = "|/~?^`".split("").find((ch2) => classes.every((spec) => !spec.includes(ch2)));
11039
+ if (delimiter === void 0) return array;
11040
+ const split = `${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
11041
+ return split.length < array.length ? split : array;
11042
+ }
10955
11043
  function emitConst(v) {
10956
11044
  if (v instanceof RegExp) return `/${v.source}/${v.flags}`;
10957
11045
  if (typeof v === "string") return jsString(v);
@@ -11030,7 +11118,7 @@ function programFields(prog, fns, opts = {}) {
11030
11118
  ...emitAssemblies(prog, opts.assemblies ?? []),
11031
11119
  `c:[${prog.code.join(",")}],`,
11032
11120
  `k:[${prog.k.map(emitConst).join(",")}],`,
11033
- `x:[${prog.cc.map(jsString).join(",")}],`,
11121
+ `x:${emitClassPool(prog.cc)},`,
11034
11122
  `e:[${prog.fx.map((f) => `[${f.map(jsString).join(",")}]`).join(",")}],`,
11035
11123
  `d:[${prog.disp.map((a) => `[${a.join(",")}]`).join(",")}],`,
11036
11124
  `r:${JSON.stringify(prog.rules)},`,