parseman 0.61.6 → 0.61.8

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.
@@ -198,8 +198,9 @@ function matchesEmptyBody(p, seen, resolve) {
198
198
  case "optional":
199
199
  case "not":
200
200
  case "peek":
201
+ case "expect":
201
202
  return true;
202
- // zero repetitions / absent / lookahead
203
+ // zero repetitions / absent / lookahead / recovered
203
204
  // Default `sepBy` is `(item (sep item)*)?` — it MATCHES THE EMPTY STRING.
204
205
  // Any `min >= 1` requires that many ITEMS, so it is nullable only when the
205
206
  // item is. (Keying this off `min === 1` reported every `{ min: 2 }` list as
@@ -220,7 +221,6 @@ function matchesEmptyBody(p, seen, resolve) {
220
221
  case "trivia":
221
222
  case "token":
222
223
  case "leaf":
223
- case "expect":
224
224
  case "withCtx":
225
225
  case "node":
226
226
  case "grammar":
@@ -290,17 +290,17 @@ function sequenceSet(parsers, fs, empties, trivia2, consuming = true) {
290
290
  function sequenceFirstSet(parsers) {
291
291
  return sequenceSet(parsers, (p) => p._meta.firstSet, matchesEmpty, void 0, false);
292
292
  }
293
- function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve, activeTrivia, consuming = true) {
293
+ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve, activeTrivia, consuming = true, follow = false) {
294
294
  if (seen.has(p)) return any();
295
295
  seen.add(p);
296
296
  try {
297
- return firstSetBody(p, seen, resolve, activeTrivia, consuming);
297
+ return firstSetBody(p, seen, resolve, activeTrivia, consuming, follow);
298
298
  } finally {
299
299
  seen.delete(p);
300
300
  }
301
301
  }
302
- function firstSetBody(p, seen, resolve, activeTrivia, consuming) {
303
- const fs = (c) => firstSetOf(c, seen, resolve, activeTrivia, consuming);
302
+ function firstSetBody(p, seen, resolve, activeTrivia, consuming, follow) {
303
+ const fs = (c) => firstSetOf(c, seen, resolve, activeTrivia, consuming, follow);
304
304
  const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve);
305
305
  const d = p._def;
306
306
  switch (d.tag) {
@@ -321,7 +321,7 @@ function firstSetBody(p, seen, resolve, activeTrivia, consuming) {
321
321
  }
322
322
  }
323
323
  const through = activeTrivia === null && resolve !== void 0;
324
- return firstSetOf(target, seen, resolve, through ? triviaThroughRef(p, target, null) : activeTrivia, consuming);
324
+ return firstSetOf(target, seen, resolve, through ? triviaThroughRef(p, target, null) : activeTrivia, consuming, follow);
325
325
  }
326
326
  case "choice": {
327
327
  let out = empty();
@@ -331,6 +331,10 @@ function firstSetBody(p, seen, resolve, activeTrivia, consuming) {
331
331
  case "sequence": {
332
332
  return sequenceSet(d.parsers, fs, empties, activeTrivia, consuming);
333
333
  }
334
+ // Runs on any character: on one its child can't start, it reports the error. A
335
+ // resync sentinel still stops where the child could start.
336
+ case "expect":
337
+ return follow ? fs(d.parser) : any();
334
338
  case "peek": {
335
339
  const inner = d.parser;
336
340
  return empties(inner) ? any() : fs(inner);
@@ -344,7 +348,6 @@ function firstSetBody(p, seen, resolve, activeTrivia, consuming) {
344
348
  case "leaf":
345
349
  case "node":
346
350
  case "sepBy":
347
- case "expect":
348
351
  // A transaction accepts exactly what its inner accepts. Its own `_meta` is
349
352
  // the inner's construction-time set, which reads `any` when the inner opens
350
353
  // with a rule reference — resolve through it like any other wrapper.
@@ -352,14 +355,15 @@ function firstSetBody(p, seen, resolve, activeTrivia, consuming) {
352
355
  return fs(d.parser);
353
356
  // A token runs its body with trivia cleared (`token.ts`).
354
357
  case "token":
355
- return firstSetOf(d.parser, seen, resolve, activeTrivia === void 0 ? void 0 : null, consuming);
358
+ return firstSetOf(d.parser, seen, resolve, activeTrivia === void 0 ? void 0 : null, consuming, follow);
356
359
  case "grammar":
357
360
  return firstSetOf(
358
361
  d.parser,
359
362
  seen,
360
363
  resolve,
361
364
  d.clearTrivia ? null : d.triviaParser ?? activeTrivia,
362
- consuming
365
+ consuming,
366
+ follow
363
367
  );
364
368
  // A run starts with its first line's prefix; a nullable prefix starts with anything.
365
369
  case "lines": {
@@ -2712,7 +2716,8 @@ function derive(c, seen) {
2712
2716
  function expect(combinator, label2) {
2713
2717
  const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
2714
2718
  const meta = {
2715
- firstSet: combinator._meta.firstSet,
2719
+ // It runs on any character: on one its child can't start, it reports the error.
2720
+ firstSet: any(),
2716
2721
  canMatchNewline: combinator._meta.canMatchNewline,
2717
2722
  isTrivia: false
2718
2723
  };
@@ -4072,7 +4077,7 @@ function regex(pattern, flags = "") {
4072
4077
  }
4073
4078
 
4074
4079
  // src/version.ts
4075
- var PARSEMAN_VERSION = "0.61.6";
4080
+ var PARSEMAN_VERSION = "0.61.8";
4076
4081
 
4077
4082
  // src/table/lex-body.ts
4078
4083
  function buildLexBodyRecognizer(spec, constants) {
@@ -5041,7 +5046,7 @@ function sequence(...parsers) {
5041
5046
  if (tolerant) {
5042
5047
  followSentinels ??= parsers.map((_, i) => firstSetSentinel(
5043
5048
  parsers.slice(i + 1).reduce(
5044
- (set, parser2) => union(set, firstSetOf(parser2, /* @__PURE__ */ new Set(), void 0, void 0, false)),
5049
+ (set, parser2) => union(set, firstSetOf(parser2, /* @__PURE__ */ new Set(), void 0, void 0, false, true)),
5045
5050
  { kind: "empty" }
5046
5051
  )
5047
5052
  ));
@@ -8330,7 +8335,7 @@ var Encoder = class {
8330
8335
  let fs = { kind: "empty" };
8331
8336
  const rr = this.refResolver();
8332
8337
  for (let j = i + 1; j < parsers.length; j++) {
8333
- fs = union(fs, firstSetOf(parsers[j], /* @__PURE__ */ new Set(), rr, void 0, false));
8338
+ fs = union(fs, firstSetOf(parsers[j], /* @__PURE__ */ new Set(), rr, void 0, false, true));
8334
8339
  }
8335
8340
  return this.charClass(fs);
8336
8341
  }
@@ -10825,17 +10830,17 @@ var WRAPPERS = /* @__PURE__ */ new Set([
10825
10830
  OP_SCOPE_PLAIN,
10826
10831
  OP_FIELD,
10827
10832
  OP_LABEL,
10828
- OP_EXPECT,
10829
10833
  OP_WITHCTX,
10830
10834
  OP_RULE,
10831
10835
  OP_ATTEMPT,
10832
10836
  OP_COV,
10833
10837
  OP_GAPGATE
10834
10838
  ]);
10835
- function rowNullable(code, k, ip, memo) {
10836
- const hit = memo.get(ip);
10839
+ function rowNullable(code, k, ip, memo, recovers = true) {
10840
+ const key = recovers ? ip : ~ip;
10841
+ const hit = memo.get(key);
10837
10842
  if (hit !== void 0) return hit;
10838
- memo.set(ip, true);
10843
+ memo.set(key, true);
10839
10844
  const op = code[ip];
10840
10845
  const kids = [];
10841
10846
  let out = true;
@@ -10846,20 +10851,20 @@ function rowNullable(code, k, ip, memo) {
10846
10851
  out = !(re instanceof RegExp) || regexCanMatchEmpty(re.source);
10847
10852
  } else if (op === OP_SEQ || op === OP_SEQV || op === OP_SEQX) {
10848
10853
  childSlots(code, ip, kids);
10849
- out = kids.every((c) => rowNullable(code, k, c, memo));
10854
+ out = kids.every((c) => rowNullable(code, k, c, memo, recovers));
10850
10855
  } else if (op === OP_CHOICE) {
10851
10856
  childSlots(code, ip, kids);
10852
- out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo));
10857
+ out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo, recovers));
10853
10858
  } else if (op === OP_REP || op === OP_REPV) {
10854
- out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo);
10859
+ out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo, recovers);
10855
10860
  } else if (op === OP_SEED) {
10856
- out = rowNullable(code, k, code[ip + 1], memo);
10861
+ out = rowNullable(code, k, code[ip + 1], memo, recovers);
10857
10862
  } else if (op === OP_CONT) {
10858
- out = rowNullable(code, k, code[ip + 1], memo) && rowNullable(code, k, code[ip + 3], memo);
10859
- } else if (WRAPPERS.has(op)) {
10860
- if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo);
10863
+ out = rowNullable(code, k, code[ip + 1], memo, recovers) && rowNullable(code, k, code[ip + 3], memo, recovers);
10864
+ } else if (WRAPPERS.has(op) || op === OP_EXPECT && !recovers) {
10865
+ if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo, recovers);
10861
10866
  }
10862
- memo.set(ip, out);
10867
+ memo.set(key, out);
10863
10868
  return out;
10864
10869
  }
10865
10870
  function holdsGap(code, k, base, n, i, memo) {
@@ -10868,7 +10873,7 @@ function holdsGap(code, k, base, n, i, memo) {
10868
10873
  if (code[term] !== OP_NOT && code[term] !== OP_PEEK) return false;
10869
10874
  const next = code[base + i + 1];
10870
10875
  if (code[next] === OP_ADJ || leadingTriviaFieldAt(code, k, next)) return false;
10871
- return !rowNullable(code, k, next, memo);
10876
+ return !rowNullable(code, k, next, memo, false);
10872
10877
  }
10873
10878
 
10874
10879
  // src/table/gap-gate.ts
@@ -11190,11 +11195,35 @@ ${fast}
11190
11195
  ${scanned}
11191
11196
  }`;
11192
11197
  }
11193
- function emitHoldTerm(callee, dst, t2, l, skip) {
11198
+ var TRIVIA_LOG_LENGTH = "ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)";
11199
+ function emitHoldTerm(callee, dst, t2, l, skip, recovers) {
11194
11200
  const fast = `const ${t2}v=${callee}(input,cur,ctx)
11195
11201
  if(${t2}v===FAIL)return FAIL
11196
11202
  ${dst}=${t2}v
11197
11203
  cur=EC.e`;
11204
+ if (recovers) {
11205
+ const marked = `let ${t2}c=cur,${t2}s=cur,${t2}tl=0,${t2}stl=0,${t2}lg=0,${t2}slg=0,${t2}rt=0,${t2}srt=0`;
11206
+ if (l.tri === TRI_NONE) return `${marked}
11207
+ ${fast}`;
11208
+ const held2 = `${t2}tl=${TRIVIA_LOG_LENGTH}
11209
+ ${t2}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
11210
+ ${t2}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
11211
+ ${t2}s=${skip}(input,cur,ctx)
11212
+ ${t2}stl=${TRIVIA_LOG_LENGTH}
11213
+ ${t2}slg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
11214
+ ${t2}srt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
11215
+ const ${t2}v=${callee}(input,${t2}s,ctx)
11216
+ if(${t2}v===FAIL)return FAIL
11217
+ ${dst}=${t2}v
11218
+ cur=${t2}s`;
11219
+ return l.tri !== TRI_UNKNOWN ? `${marked}
11220
+ ${held2}` : `${marked}
11221
+ if(ctx.trivia===undefined){
11222
+ ${fast}
11223
+ }else{
11224
+ ${held2}
11225
+ }`;
11226
+ }
11198
11227
  if (l.tri === TRI_NONE) return fast;
11199
11228
  const held = `const ${t2}s=${skip}(input,cur,ctx)
11200
11229
  const ${t2}v=${callee}(input,${t2}s,ctx)
@@ -11208,6 +11237,9 @@ ${fast}
11208
11237
  ${held}
11209
11238
  }`;
11210
11239
  }
11240
+ function emitHeldGapUndo(t2) {
11241
+ return `if(cur===${t2}s&&${t2}s!==${t2}c){rollbackScannedTriviaAt(ctx,${t2}tl,${t2}stl,${t2}lg,${t2}slg,${t2}rt,${t2}srt);cur=${t2}c}`;
11242
+ }
11211
11243
  function leadSkip(hasTrivia, leadTrivia, skip) {
11212
11244
  if (hasTrivia === "false") return "{}";
11213
11245
  const call = `itemStart=${skip}(input,itemStart,ctx)`;
@@ -12216,6 +12248,7 @@ return v
12216
12248
  }
12217
12249
  parts.push("let cur=EC.e");
12218
12250
  const names = ["v0"];
12251
+ let heldUndo;
12219
12252
  for (let i = 1; i < n; i++) {
12220
12253
  const vn = `v${i}`;
12221
12254
  parts.push(`let ${vn}`);
@@ -12232,7 +12265,16 @@ return v
12232
12265
  );
12233
12266
  } else {
12234
12267
  const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
12235
- parts.push(holdsGap(code, k, base, n, i, nullable2) ? emitHoldTerm(callee, vn, tmp(), L, skipFor(L)) : emitTerm(callee, vn, tmp(), L, skipFor(L), L.tri >= 0 ? triviaMiss(L.tri) : void 0));
12268
+ if (holdsGap(code, k, base, n, i, nullable2)) {
12269
+ const t3 = tmp();
12270
+ const recovers = rowNullable(code, k, code[base + i + 1], nullable2);
12271
+ parts.push(emitHoldTerm(callee, vn, t3, L, skipFor(L), recovers));
12272
+ heldUndo = recovers ? t3 : void 0;
12273
+ } else {
12274
+ parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L), L.tri >= 0 ? triviaMiss(L.tri) : void 0));
12275
+ if (heldUndo !== void 0) parts.push(emitHeldGapUndo(heldUndo));
12276
+ heldUndo = void 0;
12277
+ }
12236
12278
  }
12237
12279
  names.push(vn);
12238
12280
  }
@@ -13827,11 +13869,15 @@ function failCleanAnalysis(code) {
13827
13869
  case OP_CONT:
13828
13870
  out = clean(code[ip + 1]) && neverFails(code[ip + 3]);
13829
13871
  break;
13830
- // An arm's failure and the fallback's are committed; only the selector's is
13831
- // not, and without a fallback an unknown key fails after the selector wrote.
13832
- case OP_DISPATCH:
13833
- out = code[ip + 3] >= 0 && clean(code[ip + 1]);
13872
+ // An arm's failure and a committing fallback's are committed; only the
13873
+ // selector's is not. An uncommitted fallback's failure leaves the selector's
13874
+ // capture, unless the fallback reads it through `routed()`, which rolls that
13875
+ // capture back first. With no fallback, the dispatch fails after the selector wrote.
13876
+ case OP_DISPATCH: {
13877
+ const flags = code[ip + 4];
13878
+ out = code[ip + 3] >= 0 && ((flags & 2) === 0 || (flags & 1) === 1) && clean(code[ip + 1]);
13834
13879
  break;
13880
+ }
13835
13881
  default: {
13836
13882
  const c = passChild(code, ip);
13837
13883
  out = c >= 0 && clean(c);
@@ -15889,8 +15935,46 @@ function assemble(t2, prog, cfg) {
15889
15935
  }
15890
15936
  if (hasAdj) {
15891
15937
  const first2 = linkFirst();
15938
+ let heldFrom = 0, heldTl = 0, heldScanTl = 0, heldLog = 0, heldScanLog = 0, heldRoot = 0, heldScanRoot = 0;
15892
15939
  const runnerAt = (i) => {
15893
15940
  const kidIp = code[base + i];
15941
+ if (i > 1 && holdsGap(code, k, base, n, i - 1, NULLABLE) && rowNullable(code, k, kidIp, NULLABLE)) {
15942
+ const kid = link(kidIp);
15943
+ return (input, cur, ctx) => {
15944
+ const from = heldFrom, tl = heldTl, scanTl = heldScanTl, log = heldLog;
15945
+ const scanLog = heldScanLog, root = heldRoot, scanRoot = heldScanRoot;
15946
+ const next = step(kid, input, cur, ctx);
15947
+ if (next !== cur || from === cur) return next;
15948
+ rollbackScannedTriviaAt(ctx, tl, scanTl, log, scanLog, root, scanRoot);
15949
+ return from;
15950
+ };
15951
+ }
15952
+ if (holdsGap(code, k, base, n, i, NULLABLE) && rowNullable(code, k, code[base + i + 1], NULLABLE)) {
15953
+ const kid = link(kidIp);
15954
+ return (input, cur, ctx) => {
15955
+ if (ctx.trivia === void 0) {
15956
+ const v2 = kid(input, cur, ctx);
15957
+ if (v2 === FAIL) return -1;
15958
+ TERMV = v2;
15959
+ heldFrom = cur;
15960
+ return EC.e;
15961
+ }
15962
+ const tl = cstTlLen(ctx), log = ctx._triviaLog?.length ?? 0, root = ctx._rootTriviaLog?.length ?? 0;
15963
+ const scanEnd = skipTrivia(input, cur, ctx);
15964
+ const scanTl = cstTlLen(ctx), scanLog = ctx._triviaLog?.length ?? 0, scanRoot = ctx._rootTriviaLog?.length ?? 0;
15965
+ const v = kid(input, scanEnd, ctx);
15966
+ if (v === FAIL) return -1;
15967
+ TERMV = v;
15968
+ heldFrom = cur;
15969
+ heldTl = tl;
15970
+ heldScanTl = scanTl;
15971
+ heldLog = log;
15972
+ heldScanLog = scanLog;
15973
+ heldRoot = root;
15974
+ heldScanRoot = scanRoot;
15975
+ return scanEnd;
15976
+ };
15977
+ }
15894
15978
  if (holdsGap(code, k, base, n, i, NULLABLE)) {
15895
15979
  const kid = link(kidIp);
15896
15980
  return (input, cur, ctx) => {