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
@@ -75,6 +75,13 @@ function empty() {
75
75
  function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve2) {
76
76
  if (seen.has(p)) return true;
77
77
  seen.add(p);
78
+ try {
79
+ return matchesEmptyBody(p, seen, resolve2);
80
+ } finally {
81
+ seen.delete(p);
82
+ }
83
+ }
84
+ function matchesEmptyBody(p, seen, resolve2) {
78
85
  const me = (c) => matchesEmpty(c, seen, resolve2);
79
86
  const d = p._def;
80
87
  switch (d.tag) {
@@ -176,6 +183,13 @@ function sequenceFirstSet(parsers) {
176
183
  function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve2) {
177
184
  if (seen.has(p)) return any();
178
185
  seen.add(p);
186
+ try {
187
+ return firstSetBody(p, seen, resolve2);
188
+ } finally {
189
+ seen.delete(p);
190
+ }
191
+ }
192
+ function firstSetBody(p, seen, resolve2) {
179
193
  const fs = (c) => firstSetOf(c, seen, resolve2);
180
194
  const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve2);
181
195
  const d = p._def;
@@ -2524,6 +2538,23 @@ function rollbackTrivia(ctx, mark) {
2524
2538
  if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
2525
2539
  if (ctx._rootTriviaLog && ctx._rootTriviaLog.length !== mark.rootLog) ctx._rootTriviaLog.length = mark.rootLog;
2526
2540
  }
2541
+ function removeNumberRange(values, start, end) {
2542
+ if (values === void 0 || end <= start) return;
2543
+ if (values.length > end) values.copyWithin(start, end);
2544
+ values.length -= end - start;
2545
+ }
2546
+ function rollbackScannedTriviaAt(ctx, tlogStart, tlogEnd, logStart, logEnd, rootLogStart, rootLogEnd) {
2547
+ const b = ctx._cstBuf;
2548
+ if (b !== void 0) {
2549
+ const tlog = b.tl;
2550
+ removeNumberRange(tlog, tlogStart, tlogEnd);
2551
+ if (tlog !== void 0 && tlog.length === 0) b.tl = void 0;
2552
+ } else {
2553
+ removeNumberRange(ctx._cstTriviaLog, tlogStart, tlogEnd);
2554
+ }
2555
+ removeNumberRange(ctx._triviaLog, logStart, logEnd);
2556
+ removeNumberRange(ctx._rootTriviaLog, rootLogStart, rootLogEnd);
2557
+ }
2527
2558
  function parseTriviaNoCapture(triviaP, input, cur, ctx) {
2528
2559
  const probeCtx = createDetachedParseContext(ctx.trackLines, ctx.state);
2529
2560
  probeCtx._lineIndex = ctx._lineIndex;
@@ -3227,7 +3258,9 @@ function sequence(...parsers) {
3227
3258
  continue;
3228
3259
  }
3229
3260
  if (ctx.trivia && i > 0) {
3230
- const mark = saveTriviaMark(ctx);
3261
+ const mTlog = cstTlLen(ctx);
3262
+ const mLog = ctx._triviaLog?.length ?? 0;
3263
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3231
3264
  let scanEnd;
3232
3265
  if (needsDeferredTriviaCommit(ctx)) {
3233
3266
  const scan = scanTrivia(input, cur, ctx);
@@ -3236,10 +3269,13 @@ function sequence(...parsers) {
3236
3269
  } else {
3237
3270
  scanEnd = advanceTrivia(input, cur, ctx);
3238
3271
  }
3272
+ const scanTlog = cstTlLen(ctx);
3273
+ const scanLog = ctx._triviaLog?.length ?? 0;
3274
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3239
3275
  const result2 = parsers[i].parse(input, scanEnd, ctx);
3240
3276
  if (!result2.ok) return result2;
3241
3277
  if (result2.span.end > scanEnd) cur = result2.span.end;
3242
- else rollbackTrivia(ctx, mark);
3278
+ else rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
3243
3279
  if (values !== void 0) values.push(result2.value);
3244
3280
  continue;
3245
3281
  }
@@ -3270,7 +3306,9 @@ function sequence(...parsers) {
3270
3306
  }
3271
3307
  if (ctx.trivia && i > 0) {
3272
3308
  let scanEnd;
3273
- const mark = saveTriviaMark(ctx);
3309
+ const mTlog = cstTlLen(ctx);
3310
+ const mLog = ctx._triviaLog?.length ?? 0;
3311
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3274
3312
  if (needsDeferredTriviaCommit(ctx)) {
3275
3313
  const scan = scanTrivia(input, cur, ctx);
3276
3314
  scan.commit();
@@ -3278,10 +3316,13 @@ function sequence(...parsers) {
3278
3316
  } else {
3279
3317
  scanEnd = advanceTrivia(input, cur, ctx);
3280
3318
  }
3319
+ const scanTlog = cstTlLen(ctx);
3320
+ const scanLog = ctx._triviaLog?.length ?? 0;
3321
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3281
3322
  const result2 = parsers[i].parse(input, scanEnd, ctx);
3282
3323
  if (!result2.ok) return result2;
3283
3324
  if (result2.span.end > scanEnd) cur = result2.span.end;
3284
- else rollbackTrivia(ctx, mark);
3325
+ else rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
3285
3326
  if (values !== void 0) values.push(result2.value);
3286
3327
  continue;
3287
3328
  }
@@ -3309,7 +3350,9 @@ function sequence(...parsers) {
3309
3350
  for (let i = 0; i < parsers.length; i++) {
3310
3351
  if (ctx.trivia && i > 0) {
3311
3352
  let scanEnd;
3312
- let mark = saveTriviaMark(ctx);
3353
+ const mTlog = cstTlLen(ctx);
3354
+ const mLog = ctx._triviaLog?.length ?? 0;
3355
+ const mRootLog = ctx._rootTriviaLog?.length ?? 0;
3313
3356
  if (needsDeferredTriviaCommit(ctx)) {
3314
3357
  const scan = scanTrivia(input, cur, ctx);
3315
3358
  scan.commit();
@@ -3317,12 +3360,15 @@ function sequence(...parsers) {
3317
3360
  } else {
3318
3361
  scanEnd = advanceTrivia(input, cur, ctx);
3319
3362
  }
3363
+ const scanTlog = cstTlLen(ctx);
3364
+ const scanLog = ctx._triviaLog?.length ?? 0;
3365
+ const scanRootLog = ctx._rootTriviaLog?.length ?? 0;
3320
3366
  const result2 = parsers[i].parse(input, scanEnd, ctx);
3321
3367
  if (!result2.ok) return result2;
3322
3368
  if (result2.span.end > scanEnd) {
3323
3369
  cur = result2.span.end;
3324
3370
  } else {
3325
- rollbackTrivia(ctx, mark);
3371
+ rollbackScannedTriviaAt(ctx, mTlog, scanTlog, mLog, scanLog, mRootLog, scanRootLog);
3326
3372
  }
3327
3373
  if (values !== void 0) values.push(result2.value);
3328
3374
  continue;
@@ -5316,6 +5362,7 @@ var OP_LIVE = 37;
5316
5362
  var OP_ATTEMPT = 38;
5317
5363
  var OP_LABEL = 39;
5318
5364
  var OP_COV = 40;
5365
+ var OP_SCOPE_PLAIN = 41;
5319
5366
  var OP_DISPATCH = 25;
5320
5367
  var OP_ROUTED = 26;
5321
5368
  var OP_NAMES = {
@@ -5358,7 +5405,8 @@ var OP_NAMES = {
5358
5405
  [OP_LIVE]: "LIVE",
5359
5406
  [OP_ATTEMPT]: "ATTEMPT",
5360
5407
  [OP_LABEL]: "LABEL",
5361
- [OP_COV]: "COV"
5408
+ [OP_COV]: "COV",
5409
+ [OP_SCOPE_PLAIN]: "SCOPE_PLAIN"
5362
5410
  };
5363
5411
 
5364
5412
  // src/table/program.ts
@@ -5416,6 +5464,15 @@ function expandCompact(p) {
5416
5464
  ...p.a === void 0 ? {} : { asm: p.a }
5417
5465
  });
5418
5466
  }
5467
+ function validateDispatchSpec(spec, arity, fallbackRouted) {
5468
+ const invalid = (arms) => {
5469
+ for (const arm of arms) if (!Number.isInteger(arm) || arm < 0 || arm >= arity) return true;
5470
+ return false;
5471
+ };
5472
+ 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]]))) {
5473
+ throw new TypeError("table: malformed dispatch");
5474
+ }
5475
+ }
5419
5476
  var TABLE_RUNTIME = /* @__PURE__ */ Symbol("parseman.tableRuntime");
5420
5477
  function ownTableProgram(prog, resolved) {
5421
5478
  return { ...prog, [TABLE_RUNTIME]: { resolved } };
@@ -5974,7 +6031,7 @@ var Encoder = class {
5974
6031
  this.carryTriviaMeta(amb);
5975
6032
  this.carryTriviaMeta(p);
5976
6033
  if (p._def.tag === "grammar") this.carryTriviaMeta(p._def.triviaParser);
5977
- this.rules[name] = amb === void 0 ? body : this.emit(OP_SCOPE, this.triviaSlot(amb), body);
6034
+ this.rules[name] = amb === void 0 ? body : this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), body);
5978
6035
  }
5979
6036
  /**
5980
6037
  * The row a cross-rule `g.X` reference jumps to — the target's body, RE-WRAPPED
@@ -6017,7 +6074,7 @@ var Encoder = class {
6017
6074
  const amb = p._meta.grammarTrivia ?? target._meta.grammarTrivia;
6018
6075
  if (amb === void 0 || this.activeTrivia !== void 0) return ip;
6019
6076
  if (!hasOwnTriviaBoundary(target)) return ip;
6020
- return this.emit(OP_SCOPE, this.triviaSlot(amb), ip);
6077
+ return this.emit(OP_SCOPE_PLAIN, this.triviaSlot(amb), ip);
6021
6078
  }
6022
6079
  node(p) {
6023
6080
  const lazyRef = p._def.tag === "lazy";
@@ -6422,6 +6479,7 @@ var Encoder = class {
6422
6479
  return [ip + 1];
6423
6480
  case OP_SCOPE:
6424
6481
  case OP_SCOPE_CAP:
6482
+ case OP_SCOPE_PLAIN:
6425
6483
  case OP_WITHCTX:
6426
6484
  case OP_XFORM:
6427
6485
  case OP_LEAF:
@@ -7612,6 +7670,7 @@ function childSlots(code, ip, out) {
7612
7670
  case OP_GATE:
7613
7671
  case OP_SCOPE:
7614
7672
  case OP_SCOPE_CAP:
7673
+ case OP_SCOPE_PLAIN:
7615
7674
  case OP_WITHCTX:
7616
7675
  case OP_XFORM:
7617
7676
  case OP_NODE:
@@ -7700,7 +7759,7 @@ function reachableSites(code, roots) {
7700
7759
  }
7701
7760
  function transfer(code, ip, at, hostCst) {
7702
7761
  const op = code[ip];
7703
- if (op === OP_SCOPE || op === OP_SCOPE_CAP) {
7762
+ if (op === OP_SCOPE || op === OP_SCOPE_CAP || op === OP_SCOPE_PLAIN) {
7704
7763
  const ki = code[ip + 1];
7705
7764
  const tri = ki < 0 ? TRI_NONE : ki;
7706
7765
  const cap = op === OP_SCOPE_CAP ? CAP_ON : at.cap;
@@ -7781,6 +7840,7 @@ var EMITTED_PARAMS = [
7781
7840
  "pushCstLeaf",
7782
7841
  "pushCstChild",
7783
7842
  "rollbackTriviaAt",
7843
+ "rollbackScannedTriviaAt",
7784
7844
  "failAt",
7785
7845
  "classHas",
7786
7846
  "consumeTrivia",
@@ -7924,19 +7984,24 @@ if(ctx._errors!==undefined&&ctx._errors.length!==${t2}er)ctx._errors.length=${t2
7924
7984
  if (!s.fd && !s.er) return `if(${t2}n)rollbackTriviaAt(ctx,${t2}raw,${t2}tl,${t2}lv,0,undefined,${t2}lg,${t2}rt)`;
7925
7985
  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)}`;
7926
7986
  }
7927
- function emitTerm(callee, dst, t2, l, skip, s) {
7987
+ function emitTerm(callee, dst, t2, l, skip) {
7928
7988
  const fast = `const ${t2}v=${callee}(input,cur,ctx)
7929
7989
  if(${t2}v===FAIL)return FAIL
7930
7990
  ${dst}=${t2}v
7931
7991
  cur=EC.e`;
7932
7992
  if (l.tri === TRI_NONE) return fast;
7933
- const scanned = `${emitMark(t2, l.buf, s)}
7993
+ const scanned = `const ${t2}tl=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
7994
+ const ${t2}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
7995
+ const ${t2}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
7934
7996
  const ${t2}s=${skip}(input,cur,ctx)
7997
+ const ${t2}stl=ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)
7998
+ const ${t2}slg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
7999
+ const ${t2}srt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
7935
8000
  const ${t2}v=${callee}(input,${t2}s,ctx)
7936
8001
  if(${t2}v===FAIL)return FAIL
7937
8002
  ${dst}=${t2}v
7938
8003
  if(EC.e>${t2}s)cur=EC.e
7939
- else{${emitRollback(t2, l.buf, s)}}`;
8004
+ else{rollbackScannedTriviaAt(ctx,${t2}tl,${t2}stl,${t2}lg,${t2}slg,${t2}rt,${t2}srt)}`;
7940
8005
  if (l.tri !== TRI_UNKNOWN) return scanned;
7941
8006
  return `if(ctx.trivia===undefined){
7942
8007
  ${fast}
@@ -8099,7 +8164,7 @@ ${cfg.probe ? `failAt(ctx,${xf},pos)
8099
8164
  const op = code[ip];
8100
8165
  if (op === OP_GATE && (cfg.tolerant || cfg.probe)) return code[ip + 2];
8101
8166
  if (op === OP_RULE) return code[ip + 1];
8102
- if (op === OP_SCOPE && code[ip + 3] === 0 && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
8167
+ if ((op === OP_SCOPE_PLAIN || op === OP_SCOPE && code[ip + 3] === 0) && code[ip + 1] >= 0 && labels.at(ip).tri === code[ip + 1]) {
8103
8168
  return code[ip + 2];
8104
8169
  }
8105
8170
  return void 0;
@@ -8267,10 +8332,11 @@ return r.value
8267
8332
  }`;
8268
8333
  }
8269
8334
  case OP_SCOPE:
8270
- case OP_SCOPE_CAP: {
8335
+ case OP_SCOPE_CAP:
8336
+ case OP_SCOPE_PLAIN: {
8271
8337
  const ki = code[ip + 1];
8272
8338
  const cap = op === OP_SCOPE_CAP;
8273
- const flags = code[ip + 3];
8339
+ const flags = op === OP_SCOPE_PLAIN ? 0 : code[ip + 3];
8274
8340
  const child = link(code[ip + 2]);
8275
8341
  const scanFor = swapLegal && ki >= 0 && !triviaLabelled[ki] ? hoist("ts", `TRIVIASCAN[${ki}]`) : "null";
8276
8342
  const tri = ki < 0 ? "undefined" : hoist("tv", `TRIVIA[${ki}]`);
@@ -8424,7 +8490,7 @@ return v
8424
8490
  const vn = `v${i}`;
8425
8491
  parts.push(`let ${vn}`);
8426
8492
  if (REC) parts.push(pub(i));
8427
- parts.push(emitTerm(kids[i], vn, tmp(), L, skipFor(L), sinks));
8493
+ parts.push(emitTerm(kids[i], vn, tmp(), L, skipFor(L)));
8428
8494
  names.push(vn);
8429
8495
  }
8430
8496
  parts.push("EC.e=cur");
@@ -8525,11 +8591,11 @@ return FAIL
8525
8591
  const other = otherIp >= 0 ? link(otherIp) : void 0;
8526
8592
  const otherRouted = code[ip + 4] === 1;
8527
8593
  const n = code[ip + 5];
8594
+ validateDispatchSpec(spec, n, code[ip + 4]);
8528
8595
  const armBase = ip + 6;
8529
8596
  const arms = [];
8530
8597
  for (let i = 0; i < n; i++) arms.push(link(code[armBase + i]));
8531
8598
  const bk = hoist("bk", `DSP[${di}].byKey`);
8532
- const rt = hoist("rt", `DSP[${di}].routed`);
8533
8599
  const dx = hoist("dx", `DSP[${di}].expected`);
8534
8600
  const claims = (m) => {
8535
8601
  switch (m[0]) {
@@ -8553,6 +8619,15 @@ ${spec.match.map((m, i) => `${i === 0 ? "" : "else "}if(${claims(m)})arm=${m[3]}
8553
8619
  ` : "";
8554
8620
  const m1 = tmp();
8555
8621
  const m2 = tmp();
8622
+ const routedCall = (target) => `{const savedRouted=ctx._routed
8623
+ ${emitRollback(m1, L.buf, sinks)}
8624
+ ${emitMark(m2, L.buf, sinks, false)}
8625
+ ctx._routed={value:key,span:{start:pos,end:selEnd}}
8626
+ try{v=${target}(input,pos,ctx)}finally{ctx._routed=savedRouted}
8627
+ break}`;
8628
+ const plainCall = (target) => `v=${target}(input,selEnd,ctx);break`;
8629
+ const armCases = arms.map((target, i) => `case ${i}:${spec.routed[i] === 1 ? routedCall(target) : plainCall(target)}`).join("\n");
8630
+ const fallbackCase = other === void 0 ? "" : `default:${otherRouted ? routedCall(other) : plainCall(other)}`;
8556
8631
  return `${head}
8557
8632
  ${emitMark(m1, L.buf, sinks)}
8558
8633
  const sv=${selector}(input,pos,ctx)
@@ -8560,24 +8635,16 @@ if(sv===FAIL)return FAIL
8560
8635
  const selEnd=EC.e
8561
8636
  const key=sv
8562
8637
  let arm=${bk}.get(key)
8563
- ${fold}${chain}let ur
8638
+ ${fold}${chain}
8564
8639
  if(arm===undefined){
8565
- ${other === void 0 ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : `ur=${String(otherRouted)}`}
8566
- }else ur=${rt}[arm]===1
8567
- const savedRouted=ctx._routed
8568
- ${emitMark(m2, L.buf, sinks)}
8569
- if(ur){
8570
- ${emitRollback(m1, L.buf, sinks)}
8571
- ${emitMark(m2, L.buf, sinks, false)}
8572
- ctx._routed={value:key,span:{start:pos,end:selEnd}}
8640
+ ${other === void 0 ? `ctx._fe=selEnd;ctx._fx=${dx};return FAIL` : ""}
8573
8641
  }
8574
- const at=ur?pos:selEnd
8642
+ ${emitMark(m2, L.buf, sinks)}
8575
8643
  let v
8576
8644
  switch(arm){
8577
- ${arms.map((a, i) => `case ${i}:v=${a}(input,at,ctx);break`).join("\n")}
8578
- ${other === void 0 ? "" : `default:v=${other}(input,at,ctx)`}
8645
+ ${armCases}
8646
+ ${fallbackCase}
8579
8647
  }
8580
- if(ur)ctx._routed=savedRouted
8581
8648
  if(v===FAIL){
8582
8649
  ${emitRollback(m2, L.buf, sinks)}
8583
8650
  ctx._fc=true
@@ -8902,7 +8969,7 @@ function committed(c) {
8902
8969
  }
8903
8970
  function stampRuleMap(prog, d, artifactMetadata = {}, resolved = resolveTable(prog)) {
8904
8971
  const triviaOfRule = (ip) => {
8905
- if (prog.code[ip] !== OP_SCOPE) return void 0;
8972
+ if (prog.code[ip] !== OP_SCOPE_PLAIN && prog.code[ip] !== OP_SCOPE) return void 0;
8906
8973
  const slot = prog.code[ip + 1];
8907
8974
  return slot < 0 ? void 0 : resolved.trivia[slot];
8908
8975
  };
@@ -9116,20 +9183,19 @@ function assemble(t2, prog, cfg) {
9116
9183
  TERMV = v2;
9117
9184
  return EC.e > scanEnd2 ? EC.e : cur;
9118
9185
  }
9119
- const need = markCst(ctx);
9120
- const mRaw = MRAW;
9121
- const mTl = MTL;
9122
- const mLv = MLV;
9123
- const mFl = need ? ctx._fields?.length ?? 0 : 0;
9124
- const mEr = need ? ctx._errors?.length ?? 0 : 0;
9186
+ const need = rollbackNeeded(ctx);
9187
+ const mTl = need ? cstTlLen(ctx) : 0;
9125
9188
  const mLog = need ? ctx._triviaLog?.length ?? 0 : 0;
9126
9189
  const mRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
9127
9190
  const scanEnd = skipTrivia(input, cur, ctx);
9191
+ const scanTl = need ? cstTlLen(ctx) : 0;
9192
+ const scanLog = need ? ctx._triviaLog?.length ?? 0 : 0;
9193
+ const scanRoot = need ? ctx._rootTriviaLog?.length ?? 0 : 0;
9128
9194
  const v = child(input, scanEnd, ctx);
9129
9195
  if (v === FAIL) return -1;
9130
9196
  TERMV = v;
9131
9197
  if (EC.e > scanEnd) return EC.e;
9132
- if (need) rollbackTriviaAt(ctx, mRaw, mTl, mLv, mFl, mEr, mLog, mRoot);
9198
+ if (need) rollbackScannedTriviaAt(ctx, mTl, scanTl, mLog, scanLog, mRoot, scanRoot);
9133
9199
  return cur;
9134
9200
  }
9135
9201
  function committed2(c) {
@@ -9543,7 +9609,8 @@ function assemble(t2, prog, cfg) {
9543
9609
  };
9544
9610
  }
9545
9611
  case OP_SCOPE:
9546
- case OP_SCOPE_CAP: {
9612
+ case OP_SCOPE_CAP:
9613
+ case OP_SCOPE_PLAIN: {
9547
9614
  const ki = code[ip + 1];
9548
9615
  const scopeTrivia = ki < 0 ? void 0 : trivia2[ki];
9549
9616
  const scopeLabels = scopeTrivia?._meta.triviaKindLabels;
@@ -9577,7 +9644,7 @@ function assemble(t2, prog, cfg) {
9577
9644
  SCAN = savedScan;
9578
9645
  return v;
9579
9646
  };
9580
- return scopeRootPolicy(scopePiece, code[ip + 3]);
9647
+ return scopeRootPolicy(scopePiece, code[ip] === OP_SCOPE_PLAIN ? 0 : code[ip + 3]);
9581
9648
  }
9582
9649
  case OP_ROUTED: {
9583
9650
  const fb = code[ip + 1];
@@ -10493,15 +10560,21 @@ function assemble(t2, prog, cfg) {
10493
10560
  target = arms[arm];
10494
10561
  usesRouted = routed2[arm] === 1;
10495
10562
  }
10496
- const savedRouted = ctx._routed;
10497
10563
  let mark = saveTriviaMark(ctx);
10564
+ let v;
10498
10565
  if (usesRouted) {
10566
+ const savedRouted = ctx._routed;
10499
10567
  rollbackTrivia(ctx, selectorMark);
10500
10568
  mark = saveTriviaMark(ctx);
10501
10569
  ctx._routed = { value: key, span: { start: pos, end: selEnd } };
10570
+ try {
10571
+ v = target(input, pos, ctx);
10572
+ } finally {
10573
+ ctx._routed = savedRouted;
10574
+ }
10575
+ } else {
10576
+ v = target(input, selEnd, ctx);
10502
10577
  }
10503
- const v = target(input, usesRouted ? pos : selEnd, ctx);
10504
- if (usesRouted) ctx._routed = savedRouted;
10505
10578
  if (v === FAIL) {
10506
10579
  rollbackTrivia(ctx, mark);
10507
10580
  ctx._fc = true;
@@ -10647,6 +10720,11 @@ function assemble(t2, prog, cfg) {
10647
10720
  if (s.sentinel !== void 0) extraIps.push(s.sentinel[0]);
10648
10721
  }
10649
10722
  for (const set of prog.scanSkip ?? []) for (const r of set) extraIps.push(r[0]);
10723
+ const validationRoots = [...Object.values(prog.rules), ...extraIps];
10724
+ for (const ip of reachableSites(code, validationRoots)) {
10725
+ if (code[ip] !== OP_DISPATCH) continue;
10726
+ validateDispatchSpec(dsp[code[ip + 2]], code[ip + 5], code[ip + 4]);
10727
+ }
10650
10728
  const pre = cfg.hostCaptureTrivia === void 0 ? prog.asm?.find((a) => a.key === cfgKey(cfg)) : void 0;
10651
10729
  if (pre !== void 0) {
10652
10730
  const pools = rebuildPools(t2.cc, t2.fx, pre.plan);
@@ -10673,6 +10751,7 @@ function assemble(t2, prog, cfg) {
10673
10751
  pushCstLeaf,
10674
10752
  pushCstChild,
10675
10753
  rollbackTriviaAt,
10754
+ rollbackScannedTriviaAt,
10676
10755
  failAt,
10677
10756
  classHas,
10678
10757
  consumeTrivia,
@@ -10743,6 +10822,7 @@ function assemble(t2, prog, cfg) {
10743
10822
  pushCstLeaf,
10744
10823
  pushCstChild,
10745
10824
  rollbackTriviaAt,
10825
+ rollbackScannedTriviaAt,
10746
10826
  failAt,
10747
10827
  classHas,
10748
10828
  consumeTrivia,
@@ -10975,6 +11055,14 @@ function tableRules(source, artifactMetadata = {}) {
10975
11055
  function jsString(s) {
10976
11056
  return JSON.stringify(s);
10977
11057
  }
11058
+ function emitClassPool(classes) {
11059
+ const array = `[${classes.map(jsString).join(",")}]`;
11060
+ if (classes.length < 2) return array;
11061
+ const delimiter = "|/~?^`".split("").find((ch2) => classes.every((spec) => !spec.includes(ch2)));
11062
+ if (delimiter === void 0) return array;
11063
+ const split = `${jsString(classes.join(delimiter))}.split(${jsString(delimiter)})`;
11064
+ return split.length < array.length ? split : array;
11065
+ }
10978
11066
  function emitConst(v) {
10979
11067
  if (v instanceof RegExp) return `/${v.source}/${v.flags}`;
10980
11068
  if (typeof v === "string") return jsString(v);
@@ -11053,7 +11141,7 @@ function programFields(prog, fns, opts = {}) {
11053
11141
  ...emitAssemblies(prog, opts.assemblies ?? []),
11054
11142
  `c:[${prog.code.join(",")}],`,
11055
11143
  `k:[${prog.k.map(emitConst).join(",")}],`,
11056
- `x:[${prog.cc.map(jsString).join(",")}],`,
11144
+ `x:${emitClassPool(prog.cc)},`,
11057
11145
  `e:[${prog.fx.map((f) => `[${f.map(jsString).join(",")}]`).join(",")}],`,
11058
11146
  `d:[${prog.disp.map((a) => `[${a.join(",")}]`).join(",")}],`,
11059
11147
  `r:${JSON.stringify(prog.rules)},`,