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.
package/dist/index.js CHANGED
@@ -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": {
@@ -3094,7 +3098,7 @@ function sequence(...parsers) {
3094
3098
  if (tolerant) {
3095
3099
  followSentinels ??= parsers.map((_, i) => firstSetSentinel(
3096
3100
  parsers.slice(i + 1).reduce(
3097
- (set, parser2) => union(set, firstSetOf(parser2, /* @__PURE__ */ new Set(), void 0, void 0, false)),
3101
+ (set, parser2) => union(set, firstSetOf(parser2, /* @__PURE__ */ new Set(), void 0, void 0, false, true)),
3098
3102
  { kind: "empty" }
3099
3103
  )
3100
3104
  ));
@@ -3244,7 +3248,8 @@ function derive(c, seen) {
3244
3248
  function expect(combinator, label2) {
3245
3249
  const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
3246
3250
  const meta = {
3247
- firstSet: combinator._meta.firstSet,
3251
+ // It runs on any character: on one its child can't start, it reports the error.
3252
+ firstSet: any(),
3248
3253
  canMatchNewline: combinator._meta.canMatchNewline,
3249
3254
  isTrivia: false
3250
3255
  };
@@ -5661,7 +5666,7 @@ function sourceLeaf(root, fn) {
5661
5666
  }
5662
5667
 
5663
5668
  // src/version.ts
5664
- var PARSEMAN_VERSION = "0.61.6";
5669
+ var PARSEMAN_VERSION = "0.61.7";
5665
5670
 
5666
5671
  // src/table/lex-body.ts
5667
5672
  function buildLexBodyRecognizer(spec, constants) {
@@ -8939,7 +8944,7 @@ var Encoder = class {
8939
8944
  let fs = { kind: "empty" };
8940
8945
  const rr = this.refResolver();
8941
8946
  for (let j = i + 1; j < parsers.length; j++) {
8942
- fs = union(fs, firstSetOf(parsers[j], /* @__PURE__ */ new Set(), rr, void 0, false));
8947
+ fs = union(fs, firstSetOf(parsers[j], /* @__PURE__ */ new Set(), rr, void 0, false, true));
8943
8948
  }
8944
8949
  return this.charClass(fs);
8945
8950
  }
@@ -11437,17 +11442,17 @@ var WRAPPERS = /* @__PURE__ */ new Set([
11437
11442
  OP_SCOPE_PLAIN,
11438
11443
  OP_FIELD,
11439
11444
  OP_LABEL,
11440
- OP_EXPECT,
11441
11445
  OP_WITHCTX,
11442
11446
  OP_RULE,
11443
11447
  OP_ATTEMPT,
11444
11448
  OP_COV,
11445
11449
  OP_GAPGATE
11446
11450
  ]);
11447
- function rowNullable(code, k, ip, memo) {
11448
- const hit = memo.get(ip);
11451
+ function rowNullable(code, k, ip, memo, recovers = true) {
11452
+ const key = recovers ? ip : ~ip;
11453
+ const hit = memo.get(key);
11449
11454
  if (hit !== void 0) return hit;
11450
- memo.set(ip, true);
11455
+ memo.set(key, true);
11451
11456
  const op = code[ip];
11452
11457
  const kids = [];
11453
11458
  let out = true;
@@ -11458,20 +11463,20 @@ function rowNullable(code, k, ip, memo) {
11458
11463
  out = !(re instanceof RegExp) || regexCanMatchEmpty(re.source);
11459
11464
  } else if (op === OP_SEQ || op === OP_SEQV || op === OP_SEQX) {
11460
11465
  childSlots(code, ip, kids);
11461
- out = kids.every((c) => rowNullable(code, k, c, memo));
11466
+ out = kids.every((c) => rowNullable(code, k, c, memo, recovers));
11462
11467
  } else if (op === OP_CHOICE) {
11463
11468
  childSlots(code, ip, kids);
11464
- out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo));
11469
+ out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo, recovers));
11465
11470
  } else if (op === OP_REP || op === OP_REPV) {
11466
- out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo);
11471
+ out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo, recovers);
11467
11472
  } else if (op === OP_SEED) {
11468
- out = rowNullable(code, k, code[ip + 1], memo);
11473
+ out = rowNullable(code, k, code[ip + 1], memo, recovers);
11469
11474
  } else if (op === OP_CONT) {
11470
- out = rowNullable(code, k, code[ip + 1], memo) && rowNullable(code, k, code[ip + 3], memo);
11471
- } else if (WRAPPERS.has(op)) {
11472
- if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo);
11475
+ out = rowNullable(code, k, code[ip + 1], memo, recovers) && rowNullable(code, k, code[ip + 3], memo, recovers);
11476
+ } else if (WRAPPERS.has(op) || op === OP_EXPECT && !recovers) {
11477
+ if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo, recovers);
11473
11478
  }
11474
- memo.set(ip, out);
11479
+ memo.set(key, out);
11475
11480
  return out;
11476
11481
  }
11477
11482
  function holdsGap(code, k, base, n, i, memo) {
@@ -11480,7 +11485,7 @@ function holdsGap(code, k, base, n, i, memo) {
11480
11485
  if (code[term] !== OP_NOT && code[term] !== OP_PEEK) return false;
11481
11486
  const next = code[base + i + 1];
11482
11487
  if (code[next] === OP_ADJ || leadingTriviaFieldAt(code, k, next)) return false;
11483
- return !rowNullable(code, k, next, memo);
11488
+ return !rowNullable(code, k, next, memo, false);
11484
11489
  }
11485
11490
 
11486
11491
  // src/table/gap-gate.ts
@@ -11802,11 +11807,35 @@ ${fast}
11802
11807
  ${scanned}
11803
11808
  }`;
11804
11809
  }
11805
- function emitHoldTerm(callee, dst, t, l, skip) {
11810
+ var TRIVIA_LOG_LENGTH = "ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)";
11811
+ function emitHoldTerm(callee, dst, t, l, skip, recovers) {
11806
11812
  const fast = `const ${t}v=${callee}(input,cur,ctx)
11807
11813
  if(${t}v===FAIL)return FAIL
11808
11814
  ${dst}=${t}v
11809
11815
  cur=EC.e`;
11816
+ if (recovers) {
11817
+ 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`;
11818
+ if (l.tri === TRI_NONE) return `${marked}
11819
+ ${fast}`;
11820
+ const held2 = `${t}tl=${TRIVIA_LOG_LENGTH}
11821
+ ${t}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
11822
+ ${t}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
11823
+ ${t}s=${skip}(input,cur,ctx)
11824
+ ${t}stl=${TRIVIA_LOG_LENGTH}
11825
+ ${t}slg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
11826
+ ${t}srt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
11827
+ const ${t}v=${callee}(input,${t}s,ctx)
11828
+ if(${t}v===FAIL)return FAIL
11829
+ ${dst}=${t}v
11830
+ cur=${t}s`;
11831
+ return l.tri !== TRI_UNKNOWN ? `${marked}
11832
+ ${held2}` : `${marked}
11833
+ if(ctx.trivia===undefined){
11834
+ ${fast}
11835
+ }else{
11836
+ ${held2}
11837
+ }`;
11838
+ }
11810
11839
  if (l.tri === TRI_NONE) return fast;
11811
11840
  const held = `const ${t}s=${skip}(input,cur,ctx)
11812
11841
  const ${t}v=${callee}(input,${t}s,ctx)
@@ -11820,6 +11849,9 @@ ${fast}
11820
11849
  ${held}
11821
11850
  }`;
11822
11851
  }
11852
+ function emitHeldGapUndo(t) {
11853
+ 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}`;
11854
+ }
11823
11855
  function leadSkip(hasTrivia, leadTrivia, skip) {
11824
11856
  if (hasTrivia === "false") return "{}";
11825
11857
  const call = `itemStart=${skip}(input,itemStart,ctx)`;
@@ -12828,6 +12860,7 @@ return v
12828
12860
  }
12829
12861
  parts.push("let cur=EC.e");
12830
12862
  const names = ["v0"];
12863
+ let heldUndo;
12831
12864
  for (let i = 1; i < n; i++) {
12832
12865
  const vn = `v${i}`;
12833
12866
  parts.push(`let ${vn}`);
@@ -12844,7 +12877,16 @@ return v
12844
12877
  );
12845
12878
  } else {
12846
12879
  const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
12847
- 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));
12880
+ if (holdsGap(code, k, base, n, i, nullable2)) {
12881
+ const t2 = tmp();
12882
+ const recovers = rowNullable(code, k, code[base + i + 1], nullable2);
12883
+ parts.push(emitHoldTerm(callee, vn, t2, L, skipFor(L), recovers));
12884
+ heldUndo = recovers ? t2 : void 0;
12885
+ } else {
12886
+ parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L), L.tri >= 0 ? triviaMiss(L.tri) : void 0));
12887
+ if (heldUndo !== void 0) parts.push(emitHeldGapUndo(heldUndo));
12888
+ heldUndo = void 0;
12889
+ }
12848
12890
  }
12849
12891
  names.push(vn);
12850
12892
  }
@@ -16345,8 +16387,46 @@ function assemble(t, prog, cfg) {
16345
16387
  }
16346
16388
  if (hasAdj) {
16347
16389
  const first2 = linkFirst();
16390
+ let heldFrom = 0, heldTl = 0, heldScanTl = 0, heldLog = 0, heldScanLog = 0, heldRoot = 0, heldScanRoot = 0;
16348
16391
  const runnerAt = (i) => {
16349
16392
  const kidIp = code[base + i];
16393
+ if (i > 1 && holdsGap(code, k, base, n, i - 1, NULLABLE) && rowNullable(code, k, kidIp, NULLABLE)) {
16394
+ const kid = link(kidIp);
16395
+ return (input, cur, ctx) => {
16396
+ const from = heldFrom, tl = heldTl, scanTl = heldScanTl, log = heldLog;
16397
+ const scanLog = heldScanLog, root = heldRoot, scanRoot = heldScanRoot;
16398
+ const next = step(kid, input, cur, ctx);
16399
+ if (next !== cur || from === cur) return next;
16400
+ rollbackScannedTriviaAt(ctx, tl, scanTl, log, scanLog, root, scanRoot);
16401
+ return from;
16402
+ };
16403
+ }
16404
+ if (holdsGap(code, k, base, n, i, NULLABLE) && rowNullable(code, k, code[base + i + 1], NULLABLE)) {
16405
+ const kid = link(kidIp);
16406
+ return (input, cur, ctx) => {
16407
+ if (ctx.trivia === void 0) {
16408
+ const v2 = kid(input, cur, ctx);
16409
+ if (v2 === FAIL) return -1;
16410
+ TERMV = v2;
16411
+ heldFrom = cur;
16412
+ return EC.e;
16413
+ }
16414
+ const tl = cstTlLen(ctx), log = ctx._triviaLog?.length ?? 0, root = ctx._rootTriviaLog?.length ?? 0;
16415
+ const scanEnd = skipTrivia(input, cur, ctx);
16416
+ const scanTl = cstTlLen(ctx), scanLog = ctx._triviaLog?.length ?? 0, scanRoot = ctx._rootTriviaLog?.length ?? 0;
16417
+ const v = kid(input, scanEnd, ctx);
16418
+ if (v === FAIL) return -1;
16419
+ TERMV = v;
16420
+ heldFrom = cur;
16421
+ heldTl = tl;
16422
+ heldScanTl = scanTl;
16423
+ heldLog = log;
16424
+ heldScanLog = scanLog;
16425
+ heldRoot = root;
16426
+ heldScanRoot = scanRoot;
16427
+ return scanEnd;
16428
+ };
16429
+ }
16350
16430
  if (holdsGap(code, k, base, n, i, NULLABLE)) {
16351
16431
  const kid = link(kidIp);
16352
16432
  return (input, cur, ctx) => {