parseman 0.55.0 → 0.55.2

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.
@@ -107,8 +107,33 @@ export declare function hasNodeDef(p: Combinator<unknown>, seen?: Set<Combinator
107
107
  * sites and neither of which `hasNodeDef` above walks.
108
108
  */
109
109
  export declare function hasDirectBuildDef(p: Combinator<unknown>, seen?: Set<Combinator<unknown>>): boolean;
110
- /** True when `p` can report a committed failure through emitFallible's failure channel. */
111
- export declare function mayCommitFailure(p: Combinator<unknown>, seen?: Set<Combinator<unknown>>, resolve?: RefResolver): boolean;
110
+ /**
111
+ * True when `p` can report a committed failure through emitFallible's failure
112
+ * channel: a `dispatch`, or a shape this analysis cannot see into, is reachable
113
+ * along `commitFailureSuccessors`' edges.
114
+ *
115
+ * `memo` carries exact answers between calls over one graph and one `resolve`;
116
+ * a caller asking at many sites passes the same map to every call, so the graph
117
+ * is walked once rather than once per site.
118
+ */
119
+ export declare function mayCommitFailure(p: Combinator<unknown>, resolve?: RefResolver, memo?: Map<Combinator<unknown>, boolean>): boolean;
120
+ /**
121
+ * Whether a MARKED node — one `successors` answers `true` for — is reachable
122
+ * from `root`.
123
+ *
124
+ * Reachability over a cyclic graph, decided with Tarjan's strongly connected
125
+ * components so that every node the walk enters leaves with its exact answer in
126
+ * `memo`: the members of one component reach each other, so they share one
127
+ * answer, settled when the walk returns to the component's first node. A DFS
128
+ * that instead cuts a cycle at its own ancestor path learns nothing it can keep
129
+ * about a node whose walk hit the cut; one that keeps a visited set per call
130
+ * keeps nothing past the call. Shared across calls, `memo` makes every node
131
+ * entered once however many roots are asked about.
132
+ *
133
+ * `memo` must only ever be used with one `successors`: its entries are answers
134
+ * about that graph.
135
+ */
136
+ export declare function reachesMarked<T>(root: T, successors: (node: T) => readonly T[] | true, memo: Map<T, boolean>): boolean;
112
137
  /**
113
138
  * `hasDirectBuilders` / `isRecognitionOnly` for a rule map WITHOUT lowering it.
114
139
  *
@@ -1 +1 @@
1
- {"version":3,"file":"commitment.d.ts","sourceRoot":"","sources":["../../src/analysis/commitment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,aAAa,CAAA;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAI9D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAqCnG;AAkCD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAiC1G;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,EAAE,YAAY,UAAO,GAAG,OAAO,CAwGvI;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAkDxG;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAgCtG;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAqC7G;AAED,2FAA2F;AAC3F,wBAAgB,gBAAgB,CAC9B,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EACtB,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,EAC1C,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CA+CT;AAwCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAC7D;IAAE,iBAAiB,EAAE,OAAO,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAAE,CAwB5D"}
1
+ {"version":3,"file":"commitment.d.ts","sourceRoot":"","sources":["../../src/analysis/commitment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,UAAU,EAAa,MAAM,aAAa,CAAA;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAI9D;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAqCnG;AAkCD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAiC1G;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,EAAE,YAAY,UAAO,GAAG,OAAO,CAwGvI;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAkDxG;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAgCtG;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAa,GAAG,OAAO,CAqC7G;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,EACtB,OAAO,CAAC,EAAE,WAAW,EACrB,IAAI,GAAE,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,OAAO,CAAa,GAClD,OAAO,CAET;AAsDD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,IAAI,EAAE,CAAC,EACP,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,SAAS,CAAC,EAAE,GAAG,IAAI,EAC5C,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,GACpB,OAAO,CAkDT;AAwCD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAC7D;IAAE,iBAAiB,EAAE,OAAO,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAAE,CAwB5D"}
@@ -3255,19 +3255,22 @@ function hasDirectBuildDef(p, seen = /* @__PURE__ */ new Set()) {
3255
3255
  return false;
3256
3256
  }
3257
3257
  }
3258
- function mayCommitFailure(p, seen = /* @__PURE__ */ new Set(), resolve) {
3259
- if (seen.has(p)) return false;
3260
- seen.add(p);
3258
+ function mayCommitFailure(p, resolve, memo = /* @__PURE__ */ new Map()) {
3259
+ return reachesMarked(p, (node2) => commitFailureSuccessors(node2, resolve), memo);
3260
+ }
3261
+ var NO_EDGES = [];
3262
+ function commitFailureSuccessors(p, resolve) {
3261
3263
  const d = p._def;
3262
3264
  switch (d.tag) {
3263
3265
  case "dispatch":
3266
+ case "unknown":
3264
3267
  return true;
3265
3268
  case "choice":
3266
3269
  case "sequence":
3267
- return d.parsers.some((x) => mayCommitFailure(x, seen, resolve));
3270
+ return d.parsers;
3268
3271
  // A contained transaction reports every failure uncommitted.
3269
3272
  case "attempt":
3270
- return d.contain !== true && mayCommitFailure(d.parser, seen, resolve);
3273
+ return d.contain === true ? NO_EDGES : [d.parser];
3271
3274
  case "many":
3272
3275
  case "oneOrMore":
3273
3276
  case "optional":
@@ -3276,31 +3279,77 @@ function mayCommitFailure(p, seen = /* @__PURE__ */ new Set(), resolve) {
3276
3279
  case "field":
3277
3280
  case "grammar":
3278
3281
  case "node":
3279
- return mayCommitFailure(d.parser, seen, resolve);
3280
- case "sepBy":
3281
- return mayCommitFailure(d.parser, seen, resolve) || mayCommitFailure(d.separator, seen, resolve);
3282
3282
  case "token":
3283
3283
  case "leaf":
3284
- return mayCommitFailure(d.parser, seen, resolve);
3285
3284
  case "withCtx":
3286
- return mayCommitFailure(d.parser, seen, resolve);
3285
+ return [d.parser];
3286
+ case "sepBy":
3287
+ return [d.parser, d.separator];
3287
3288
  case "scanTo":
3288
- return mayCommitFailure(d.sentinel, seen, resolve) || d.skip.some((x) => mayCommitFailure(x, seen, resolve)) || d.recoverAt !== void 0 && mayCommitFailure(d.recoverAt, seen, resolve) || d.stopAt !== void 0 && mayCommitFailure(d.stopAt, seen, resolve);
3289
+ return [
3290
+ d.sentinel,
3291
+ ...d.skip,
3292
+ ...d.recoverAt === void 0 ? NO_EDGES : [d.recoverAt],
3293
+ ...d.stopAt === void 0 ? NO_EDGES : [d.stopAt]
3294
+ ];
3289
3295
  case "lazy": {
3290
3296
  try {
3291
- return mayCommitFailure(d.thunk(), seen, resolve);
3297
+ return [d.thunk()];
3292
3298
  } catch {
3293
3299
  const name = p._ruleName;
3294
3300
  const target = name === void 0 ? void 0 : resolve?.(name);
3295
- return target === void 0 ? true : mayCommitFailure(target, seen, resolve);
3301
+ return target === void 0 ? true : [target];
3296
3302
  }
3297
3303
  }
3298
- case "unknown":
3299
- return true;
3300
3304
  default:
3301
- return false;
3305
+ return NO_EDGES;
3302
3306
  }
3303
3307
  }
3308
+ function reachesMarked(root, successors, memo) {
3309
+ const known = memo.get(root);
3310
+ if (known !== void 0) return known;
3311
+ const order = /* @__PURE__ */ new Map();
3312
+ const low = [];
3313
+ const found = [];
3314
+ const stack = [];
3315
+ const visit = (node2) => {
3316
+ const at = low.length;
3317
+ order.set(node2, at);
3318
+ low.push(at);
3319
+ found.push(false);
3320
+ stack.push(node2);
3321
+ const next = successors(node2);
3322
+ if (next === true) found[at] = true;
3323
+ else {
3324
+ for (const child of next) {
3325
+ if (found[at]) break;
3326
+ const hit = memo.get(child);
3327
+ if (hit !== void 0) {
3328
+ if (hit) found[at] = true;
3329
+ continue;
3330
+ }
3331
+ const seen = order.get(child);
3332
+ if (seen !== void 0) {
3333
+ if (seen < low[at]) low[at] = seen;
3334
+ continue;
3335
+ }
3336
+ const k = visit(child);
3337
+ if (low[k] < low[at]) low[at] = low[k];
3338
+ if (found[k]) found[at] = true;
3339
+ }
3340
+ }
3341
+ if (low[at] === at) {
3342
+ const answer = found[at];
3343
+ let member;
3344
+ do {
3345
+ member = stack.pop();
3346
+ memo.set(member, answer);
3347
+ } while (member !== node2);
3348
+ }
3349
+ return at;
3350
+ };
3351
+ return found[visit(root)];
3352
+ }
3304
3353
 
3305
3354
  // src/recovery/scan.ts
3306
3355
  function probeAt(sentinel, input, pos, ctx) {
@@ -6225,21 +6274,20 @@ var Encoder = class {
6225
6274
  nonCommittingChoiceSites = /* @__PURE__ */ new Set();
6226
6275
  failureRollbackCleanSites = /* @__PURE__ */ new Set();
6227
6276
  /**
6228
- * `hasSideWriter` memo for `failureNeedsRollback`, shared across every call
6229
- * for the lifetime of this `Encoder`. A cached entry is written only when
6230
- * `complete` is true, which means the answer is a path-independent fact
6231
- * about that combinator node — it does not depend on which root's traversal
6232
- * asked, only on the node's own reachable subgraph. Scoping the memo per call
6233
- * (as a local inside `failureNeedsRollback`) was correct but discarded that
6234
- * fact after every arm, so a grammar with many ordered-choice arms / optional
6235
- * / attempt sites re-walked the SAME shared rule graph from scratch for each
6236
- * site — O(sites × graph size) instead of O(graph size). Measured on the
6237
- * scss-parser grammar (composed CSS-base superset, the deepest/largest of the
6238
- * four grammars): 47-50s for one `compileRuleMap` with the per-call memo,
6239
- * versus the whole macro transform completing in under a second once this
6240
- * memo is hoisted here.
6277
+ * `reachesSideWriter`'s answers, shared by every `failureNeedsRollback` call
6278
+ * for the lifetime of this `Encoder`. Every entry is exact — it depends only on
6279
+ * the node's own reachable subgraph, never on which root's walk asked — so each
6280
+ * combinator is walked once per encode however many choice arms, optionals and
6281
+ * attempt sites reach it.
6241
6282
  */
6242
6283
  sideWriterMemo = /* @__PURE__ */ new Map();
6284
+ /**
6285
+ * `mayCommitFailure`'s answers, shared by every choice site for the lifetime
6286
+ * of this `Encoder` — exact for the graph and the `winners` resolver it is
6287
+ * encoding, so the rule graph is walked once per encode rather than once per
6288
+ * choice site.
6289
+ */
6290
+ commitFailureMemo = /* @__PURE__ */ new Map();
6243
6291
  labels = void 0;
6244
6292
  /** Trivia table in scope at the row being encoded — codegen's `ctx.activeTrivia`. */
6245
6293
  activeTrivia = void 0;
@@ -6670,63 +6718,45 @@ var Encoder = class {
6670
6718
  * writer census covers the side sinks that proof deliberately does not model:
6671
6719
  * fields, recovered errors, and interpreted scanners. Strict assemblies do
6672
6720
  * not run repeat recovery, but these rows can still publish through a caller's
6673
- * context. Cycles are safe to stop: revisiting the same combinator cannot
6674
- * discover a writer the first traversal did not already reach.
6721
+ * context.
6675
6722
  */
6676
6723
  failureNeedsRollback(p, autoNot) {
6677
6724
  const refName = p._ruleName;
6678
6725
  const winner = refName === void 0 ? void 0 : this.winners?.[refName];
6679
6726
  const root = winner !== void 0 && !winnerWrapsReference2(winner, p) ? winner : p;
6680
- const sideWriterMemo = this.sideWriterMemo;
6681
- const seen = /* @__PURE__ */ new Set();
6682
- const hasSideWriter = (current) => {
6683
- const cached = sideWriterMemo.get(current);
6684
- if (cached !== void 0) return { found: cached, complete: true };
6685
- if (seen.has(current)) return { found: false, complete: false };
6686
- seen.add(current);
6687
- const def = current._def;
6688
- let result;
6689
- switch (def.tag) {
6690
- case "field":
6691
- case "expect":
6692
- case "recover":
6693
- case "scanTo":
6694
- case "unknown":
6695
- result = { found: true, complete: true };
6696
- break;
6697
- case "lazy": {
6698
- const name = current._ruleName;
6699
- const resolvedWinner = name === void 0 ? void 0 : this.winners?.[name];
6700
- if (resolvedWinner !== void 0 && !winnerWrapsReference2(resolvedWinner, current)) {
6701
- result = hasSideWriter(resolvedWinner);
6702
- break;
6703
- }
6704
- try {
6705
- result = hasSideWriter(def.thunk());
6706
- } catch {
6707
- result = { found: true, complete: true };
6708
- }
6709
- break;
6710
- }
6711
- default: {
6712
- let complete = true;
6713
- result = { found: false, complete: true };
6714
- for (const child of childrenOf(def)) {
6715
- const childResult = hasSideWriter(child);
6716
- if (childResult.found) {
6717
- result = { found: true, complete: true };
6718
- break;
6719
- }
6720
- complete &&= childResult.complete;
6721
- }
6722
- if (!result.found) result = { found: false, complete };
6727
+ return mayLeavePartialCapture(root, /* @__PURE__ */ new Set(), true) || this.reachesSideWriter(root) || (autoNot?.length ?? 0) > 0 && capturesLeaf(root);
6728
+ }
6729
+ /**
6730
+ * Whether a field, recovered error, interpreted scanner or unresolvable shape
6731
+ * is reachable from `root` — the writer census of `failureNeedsRollback`,
6732
+ * entering each combinator once per `Encoder` (see `reachesMarked`).
6733
+ */
6734
+ reachesSideWriter(root) {
6735
+ return reachesMarked(root, (node2) => this.sideWriterSuccessors(node2), this.sideWriterMemo);
6736
+ }
6737
+ /** The census's edges out of `node`, or `true` when `node` is itself a writer. */
6738
+ sideWriterSuccessors(node2) {
6739
+ const def = node2._def;
6740
+ switch (def.tag) {
6741
+ case "field":
6742
+ case "expect":
6743
+ case "recover":
6744
+ case "scanTo":
6745
+ case "unknown":
6746
+ return true;
6747
+ case "lazy": {
6748
+ const name = node2._ruleName;
6749
+ const winner = name === void 0 ? void 0 : this.winners?.[name];
6750
+ if (winner !== void 0 && !winnerWrapsReference2(winner, node2)) return [winner];
6751
+ try {
6752
+ return [def.thunk()];
6753
+ } catch {
6754
+ return true;
6723
6755
  }
6724
6756
  }
6725
- seen.delete(current);
6726
- if (result.found || result.complete) sideWriterMemo.set(current, result.found);
6727
- return result;
6728
- };
6729
- return mayLeavePartialCapture(root, /* @__PURE__ */ new Set(), true) || hasSideWriter(root).found || (autoNot?.length ?? 0) > 0 && capturesLeaf(root);
6757
+ default:
6758
+ return childrenOf(def);
6759
+ }
6730
6760
  }
6731
6761
  /** A first set becomes a char class string, or −1 for `any`. */
6732
6762
  charClass(fs) {
@@ -7057,7 +7087,7 @@ var Encoder = class {
7057
7087
  this.code[head + 4 + kids.length + i] = this.expected(deriveExpected(arms[i]));
7058
7088
  }
7059
7089
  this.choiceRollbackMasks.set(head, rollbackMask);
7060
- if (arms.every((arm) => !mayCommitFailure(arm, /* @__PURE__ */ new Set(), rr))) {
7090
+ if (arms.every((arm) => !mayCommitFailure(arm, rr, this.commitFailureMemo))) {
7061
7091
  this.nonCommittingChoiceSites.add(head);
7062
7092
  }
7063
7093
  return head;