parseman 0.61.6 → 0.61.7

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.
@@ -206,8 +206,9 @@ function matchesEmptyBody(p, seen, resolve3) {
206
206
  case "optional":
207
207
  case "not":
208
208
  case "peek":
209
+ case "expect":
209
210
  return true;
210
- // zero repetitions / absent / lookahead
211
+ // zero repetitions / absent / lookahead / recovered
211
212
  // Default `sepBy` is `(item (sep item)*)?` — it MATCHES THE EMPTY STRING.
212
213
  // Any `min >= 1` requires that many ITEMS, so it is nullable only when the
213
214
  // item is. (Keying this off `min === 1` reported every `{ min: 2 }` list as
@@ -228,7 +229,6 @@ function matchesEmptyBody(p, seen, resolve3) {
228
229
  case "trivia":
229
230
  case "token":
230
231
  case "leaf":
231
- case "expect":
232
232
  case "withCtx":
233
233
  case "node":
234
234
  case "grammar":
@@ -298,17 +298,17 @@ function sequenceSet(parsers, fs3, empties, trivia2, consuming = true) {
298
298
  function sequenceFirstSet(parsers) {
299
299
  return sequenceSet(parsers, (p) => p._meta.firstSet, matchesEmpty, void 0, false);
300
300
  }
301
- function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve3, activeTrivia, consuming = true) {
301
+ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve3, activeTrivia, consuming = true, follow = false) {
302
302
  if (seen.has(p)) return any();
303
303
  seen.add(p);
304
304
  try {
305
- return firstSetBody(p, seen, resolve3, activeTrivia, consuming);
305
+ return firstSetBody(p, seen, resolve3, activeTrivia, consuming, follow);
306
306
  } finally {
307
307
  seen.delete(p);
308
308
  }
309
309
  }
310
- function firstSetBody(p, seen, resolve3, activeTrivia, consuming) {
311
- const fs3 = (c) => firstSetOf(c, seen, resolve3, activeTrivia, consuming);
310
+ function firstSetBody(p, seen, resolve3, activeTrivia, consuming, follow) {
311
+ const fs3 = (c) => firstSetOf(c, seen, resolve3, activeTrivia, consuming, follow);
312
312
  const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve3);
313
313
  const d = p._def;
314
314
  switch (d.tag) {
@@ -329,7 +329,7 @@ function firstSetBody(p, seen, resolve3, activeTrivia, consuming) {
329
329
  }
330
330
  }
331
331
  const through = activeTrivia === null && resolve3 !== void 0;
332
- return firstSetOf(target, seen, resolve3, through ? triviaThroughRef(p, target, null) : activeTrivia, consuming);
332
+ return firstSetOf(target, seen, resolve3, through ? triviaThroughRef(p, target, null) : activeTrivia, consuming, follow);
333
333
  }
334
334
  case "choice": {
335
335
  let out = empty();
@@ -339,6 +339,10 @@ function firstSetBody(p, seen, resolve3, activeTrivia, consuming) {
339
339
  case "sequence": {
340
340
  return sequenceSet(d.parsers, fs3, empties, activeTrivia, consuming);
341
341
  }
342
+ // Runs on any character: on one its child can't start, it reports the error. A
343
+ // resync sentinel still stops where the child could start.
344
+ case "expect":
345
+ return follow ? fs3(d.parser) : any();
342
346
  case "peek": {
343
347
  const inner = d.parser;
344
348
  return empties(inner) ? any() : fs3(inner);
@@ -352,7 +356,6 @@ function firstSetBody(p, seen, resolve3, activeTrivia, consuming) {
352
356
  case "leaf":
353
357
  case "node":
354
358
  case "sepBy":
355
- case "expect":
356
359
  // A transaction accepts exactly what its inner accepts. Its own `_meta` is
357
360
  // the inner's construction-time set, which reads `any` when the inner opens
358
361
  // with a rule reference — resolve through it like any other wrapper.
@@ -360,14 +363,15 @@ function firstSetBody(p, seen, resolve3, activeTrivia, consuming) {
360
363
  return fs3(d.parser);
361
364
  // A token runs its body with trivia cleared (`token.ts`).
362
365
  case "token":
363
- return firstSetOf(d.parser, seen, resolve3, activeTrivia === void 0 ? void 0 : null, consuming);
366
+ return firstSetOf(d.parser, seen, resolve3, activeTrivia === void 0 ? void 0 : null, consuming, follow);
364
367
  case "grammar":
365
368
  return firstSetOf(
366
369
  d.parser,
367
370
  seen,
368
371
  resolve3,
369
372
  d.clearTrivia ? null : d.triviaParser ?? activeTrivia,
370
- consuming
373
+ consuming,
374
+ follow
371
375
  );
372
376
  // A run starts with its first line's prefix; a nullable prefix starts with anything.
373
377
  case "lines": {
@@ -3650,7 +3654,7 @@ function sequence(...parsers) {
3650
3654
  if (tolerant) {
3651
3655
  followSentinels ??= parsers.map((_, i) => firstSetSentinel(
3652
3656
  parsers.slice(i + 1).reduce(
3653
- (set, parser2) => union(set, firstSetOf(parser2, /* @__PURE__ */ new Set(), void 0, void 0, false)),
3657
+ (set, parser2) => union(set, firstSetOf(parser2, /* @__PURE__ */ new Set(), void 0, void 0, false, true)),
3654
3658
  { kind: "empty" }
3655
3659
  )
3656
3660
  ));
@@ -3800,7 +3804,8 @@ function derive(c, seen) {
3800
3804
  function expect(combinator, label2) {
3801
3805
  const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
3802
3806
  const meta = {
3803
- firstSet: combinator._meta.firstSet,
3807
+ // It runs on any character: on one its child can't start, it reports the error.
3808
+ firstSet: any(),
3804
3809
  canMatchNewline: combinator._meta.canMatchNewline,
3805
3810
  isTrivia: false
3806
3811
  };
@@ -5630,7 +5635,7 @@ function sourceLeaf(root, fn) {
5630
5635
  }
5631
5636
 
5632
5637
  // src/version.ts
5633
- var PARSEMAN_VERSION = "0.61.6";
5638
+ var PARSEMAN_VERSION = "0.61.7";
5634
5639
 
5635
5640
  // src/table/lex-body.ts
5636
5641
  function buildLexBodyRecognizer(spec, constants) {
@@ -8562,7 +8567,7 @@ var Encoder = class {
8562
8567
  let fs3 = { kind: "empty" };
8563
8568
  const rr = this.refResolver();
8564
8569
  for (let j = i + 1; j < parsers.length; j++) {
8565
- fs3 = union(fs3, firstSetOf(parsers[j], /* @__PURE__ */ new Set(), rr, void 0, false));
8570
+ fs3 = union(fs3, firstSetOf(parsers[j], /* @__PURE__ */ new Set(), rr, void 0, false, true));
8566
8571
  }
8567
8572
  return this.charClass(fs3);
8568
8573
  }
@@ -11057,17 +11062,17 @@ var WRAPPERS = /* @__PURE__ */ new Set([
11057
11062
  OP_SCOPE_PLAIN,
11058
11063
  OP_FIELD,
11059
11064
  OP_LABEL,
11060
- OP_EXPECT,
11061
11065
  OP_WITHCTX,
11062
11066
  OP_RULE,
11063
11067
  OP_ATTEMPT,
11064
11068
  OP_COV,
11065
11069
  OP_GAPGATE
11066
11070
  ]);
11067
- function rowNullable(code, k, ip, memo) {
11068
- const hit = memo.get(ip);
11071
+ function rowNullable(code, k, ip, memo, recovers = true) {
11072
+ const key = recovers ? ip : ~ip;
11073
+ const hit = memo.get(key);
11069
11074
  if (hit !== void 0) return hit;
11070
- memo.set(ip, true);
11075
+ memo.set(key, true);
11071
11076
  const op = code[ip];
11072
11077
  const kids = [];
11073
11078
  let out = true;
@@ -11078,20 +11083,20 @@ function rowNullable(code, k, ip, memo) {
11078
11083
  out = !(re instanceof RegExp) || regexCanMatchEmpty(re.source);
11079
11084
  } else if (op === OP_SEQ || op === OP_SEQV || op === OP_SEQX) {
11080
11085
  childSlots(code, ip, kids);
11081
- out = kids.every((c) => rowNullable(code, k, c, memo));
11086
+ out = kids.every((c) => rowNullable(code, k, c, memo, recovers));
11082
11087
  } else if (op === OP_CHOICE) {
11083
11088
  childSlots(code, ip, kids);
11084
- out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo));
11089
+ out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo, recovers));
11085
11090
  } else if (op === OP_REP || op === OP_REPV) {
11086
- out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo);
11091
+ out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo, recovers);
11087
11092
  } else if (op === OP_SEED) {
11088
- out = rowNullable(code, k, code[ip + 1], memo);
11093
+ out = rowNullable(code, k, code[ip + 1], memo, recovers);
11089
11094
  } else if (op === OP_CONT) {
11090
- out = rowNullable(code, k, code[ip + 1], memo) && rowNullable(code, k, code[ip + 3], memo);
11091
- } else if (WRAPPERS.has(op)) {
11092
- if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo);
11095
+ out = rowNullable(code, k, code[ip + 1], memo, recovers) && rowNullable(code, k, code[ip + 3], memo, recovers);
11096
+ } else if (WRAPPERS.has(op) || op === OP_EXPECT && !recovers) {
11097
+ if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo, recovers);
11093
11098
  }
11094
- memo.set(ip, out);
11099
+ memo.set(key, out);
11095
11100
  return out;
11096
11101
  }
11097
11102
  function holdsGap(code, k, base, n, i, memo) {
@@ -11100,7 +11105,7 @@ function holdsGap(code, k, base, n, i, memo) {
11100
11105
  if (code[term] !== OP_NOT && code[term] !== OP_PEEK) return false;
11101
11106
  const next = code[base + i + 1];
11102
11107
  if (code[next] === OP_ADJ || leadingTriviaFieldAt(code, k, next)) return false;
11103
- return !rowNullable(code, k, next, memo);
11108
+ return !rowNullable(code, k, next, memo, false);
11104
11109
  }
11105
11110
 
11106
11111
  // src/table/gap-gate.ts
@@ -11422,11 +11427,35 @@ ${fast}
11422
11427
  ${scanned}
11423
11428
  }`;
11424
11429
  }
11425
- function emitHoldTerm(callee, dst, t, l, skip) {
11430
+ var TRIVIA_LOG_LENGTH = "ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)";
11431
+ function emitHoldTerm(callee, dst, t, l, skip, recovers) {
11426
11432
  const fast = `const ${t}v=${callee}(input,cur,ctx)
11427
11433
  if(${t}v===FAIL)return FAIL
11428
11434
  ${dst}=${t}v
11429
11435
  cur=EC.e`;
11436
+ if (recovers) {
11437
+ const marked = `let ${t}c=cur,${t}s=cur,${t}tl=0,${t}stl=0,${t}lg=0,${t}slg=0,${t}rt=0,${t}srt=0`;
11438
+ if (l.tri === TRI_NONE) return `${marked}
11439
+ ${fast}`;
11440
+ const held2 = `${t}tl=${TRIVIA_LOG_LENGTH}
11441
+ ${t}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
11442
+ ${t}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
11443
+ ${t}s=${skip}(input,cur,ctx)
11444
+ ${t}stl=${TRIVIA_LOG_LENGTH}
11445
+ ${t}slg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
11446
+ ${t}srt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
11447
+ const ${t}v=${callee}(input,${t}s,ctx)
11448
+ if(${t}v===FAIL)return FAIL
11449
+ ${dst}=${t}v
11450
+ cur=${t}s`;
11451
+ return l.tri !== TRI_UNKNOWN ? `${marked}
11452
+ ${held2}` : `${marked}
11453
+ if(ctx.trivia===undefined){
11454
+ ${fast}
11455
+ }else{
11456
+ ${held2}
11457
+ }`;
11458
+ }
11430
11459
  if (l.tri === TRI_NONE) return fast;
11431
11460
  const held = `const ${t}s=${skip}(input,cur,ctx)
11432
11461
  const ${t}v=${callee}(input,${t}s,ctx)
@@ -11440,6 +11469,9 @@ ${fast}
11440
11469
  ${held}
11441
11470
  }`;
11442
11471
  }
11472
+ function emitHeldGapUndo(t) {
11473
+ return `if(cur===${t}s&&${t}s!==${t}c){rollbackScannedTriviaAt(ctx,${t}tl,${t}stl,${t}lg,${t}slg,${t}rt,${t}srt);cur=${t}c}`;
11474
+ }
11443
11475
  function leadSkip(hasTrivia, leadTrivia, skip) {
11444
11476
  if (hasTrivia === "false") return "{}";
11445
11477
  const call = `itemStart=${skip}(input,itemStart,ctx)`;
@@ -12448,6 +12480,7 @@ return v
12448
12480
  }
12449
12481
  parts.push("let cur=EC.e");
12450
12482
  const names = ["v0"];
12483
+ let heldUndo;
12451
12484
  for (let i = 1; i < n; i++) {
12452
12485
  const vn = `v${i}`;
12453
12486
  parts.push(`let ${vn}`);
@@ -12464,7 +12497,16 @@ return v
12464
12497
  );
12465
12498
  } else {
12466
12499
  const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
12467
- 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));
12500
+ if (holdsGap(code, k, base, n, i, nullable2)) {
12501
+ const t2 = tmp();
12502
+ const recovers = rowNullable(code, k, code[base + i + 1], nullable2);
12503
+ parts.push(emitHoldTerm(callee, vn, t2, L, skipFor(L), recovers));
12504
+ heldUndo = recovers ? t2 : void 0;
12505
+ } else {
12506
+ parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L), L.tri >= 0 ? triviaMiss(L.tri) : void 0));
12507
+ if (heldUndo !== void 0) parts.push(emitHeldGapUndo(heldUndo));
12508
+ heldUndo = void 0;
12509
+ }
12468
12510
  }
12469
12511
  names.push(vn);
12470
12512
  }
@@ -15965,8 +16007,46 @@ function assemble(t, prog, cfg) {
15965
16007
  }
15966
16008
  if (hasAdj) {
15967
16009
  const first2 = linkFirst();
16010
+ let heldFrom = 0, heldTl = 0, heldScanTl = 0, heldLog = 0, heldScanLog = 0, heldRoot = 0, heldScanRoot = 0;
15968
16011
  const runnerAt = (i) => {
15969
16012
  const kidIp = code[base + i];
16013
+ if (i > 1 && holdsGap(code, k, base, n, i - 1, NULLABLE) && rowNullable(code, k, kidIp, NULLABLE)) {
16014
+ const kid = link(kidIp);
16015
+ return (input, cur, ctx) => {
16016
+ const from = heldFrom, tl = heldTl, scanTl = heldScanTl, log = heldLog;
16017
+ const scanLog = heldScanLog, root = heldRoot, scanRoot = heldScanRoot;
16018
+ const next = step(kid, input, cur, ctx);
16019
+ if (next !== cur || from === cur) return next;
16020
+ rollbackScannedTriviaAt(ctx, tl, scanTl, log, scanLog, root, scanRoot);
16021
+ return from;
16022
+ };
16023
+ }
16024
+ if (holdsGap(code, k, base, n, i, NULLABLE) && rowNullable(code, k, code[base + i + 1], NULLABLE)) {
16025
+ const kid = link(kidIp);
16026
+ return (input, cur, ctx) => {
16027
+ if (ctx.trivia === void 0) {
16028
+ const v2 = kid(input, cur, ctx);
16029
+ if (v2 === FAIL) return -1;
16030
+ TERMV = v2;
16031
+ heldFrom = cur;
16032
+ return EC.e;
16033
+ }
16034
+ const tl = cstTlLen(ctx), log = ctx._triviaLog?.length ?? 0, root = ctx._rootTriviaLog?.length ?? 0;
16035
+ const scanEnd = skipTrivia(input, cur, ctx);
16036
+ const scanTl = cstTlLen(ctx), scanLog = ctx._triviaLog?.length ?? 0, scanRoot = ctx._rootTriviaLog?.length ?? 0;
16037
+ const v = kid(input, scanEnd, ctx);
16038
+ if (v === FAIL) return -1;
16039
+ TERMV = v;
16040
+ heldFrom = cur;
16041
+ heldTl = tl;
16042
+ heldScanTl = scanTl;
16043
+ heldLog = log;
16044
+ heldScanLog = scanLog;
16045
+ heldRoot = root;
16046
+ heldScanRoot = scanRoot;
16047
+ return scanEnd;
16048
+ };
16049
+ }
15970
16050
  if (holdsGap(code, k, base, n, i, NULLABLE)) {
15971
16051
  const kid = link(kidIp);
15972
16052
  return (input, cur, ctx) => {