parseman 0.61.5 → 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/cli/index.js CHANGED
@@ -206,8 +206,9 @@ function matchesEmptyBody(p, seen, resolve2) {
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, resolve2) {
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, fs, 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(), resolve2, activeTrivia, consuming = true) {
301
+ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve2, 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, resolve2, activeTrivia, consuming);
305
+ return firstSetBody(p, seen, resolve2, activeTrivia, consuming, follow);
306
306
  } finally {
307
307
  seen.delete(p);
308
308
  }
309
309
  }
310
- function firstSetBody(p, seen, resolve2, activeTrivia, consuming) {
311
- const fs = (c) => firstSetOf(c, seen, resolve2, activeTrivia, consuming);
310
+ function firstSetBody(p, seen, resolve2, activeTrivia, consuming, follow) {
311
+ const fs = (c) => firstSetOf(c, seen, resolve2, activeTrivia, consuming, follow);
312
312
  const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve2);
313
313
  const d = p._def;
314
314
  switch (d.tag) {
@@ -329,7 +329,7 @@ function firstSetBody(p, seen, resolve2, activeTrivia, consuming) {
329
329
  }
330
330
  }
331
331
  const through = activeTrivia === null && resolve2 !== void 0;
332
- return firstSetOf(target, seen, resolve2, through ? triviaThroughRef(p, target, null) : activeTrivia, consuming);
332
+ return firstSetOf(target, seen, resolve2, 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, resolve2, activeTrivia, consuming) {
339
339
  case "sequence": {
340
340
  return sequenceSet(d.parsers, fs, 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 ? fs(d.parser) : any();
342
346
  case "peek": {
343
347
  const inner = d.parser;
344
348
  return empties(inner) ? any() : fs(inner);
@@ -352,7 +356,6 @@ function firstSetBody(p, seen, resolve2, 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, resolve2, activeTrivia, consuming) {
360
363
  return fs(d.parser);
361
364
  // A token runs its body with trivia cleared (`token.ts`).
362
365
  case "token":
363
- return firstSetOf(d.parser, seen, resolve2, activeTrivia === void 0 ? void 0 : null, consuming);
366
+ return firstSetOf(d.parser, seen, resolve2, 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
  resolve2,
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": {
@@ -2959,7 +2963,8 @@ function derive(c, seen) {
2959
2963
  function expect(combinator, label2) {
2960
2964
  const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
2961
2965
  const meta = {
2962
- firstSet: combinator._meta.firstSet,
2966
+ // It runs on any character: on one its child can't start, it reports the error.
2967
+ firstSet: any(),
2963
2968
  canMatchNewline: combinator._meta.canMatchNewline,
2964
2969
  isTrivia: false
2965
2970
  };
@@ -5708,7 +5713,7 @@ function regex(pattern, flags = "") {
5708
5713
  }
5709
5714
 
5710
5715
  // src/version.ts
5711
- var PARSEMAN_VERSION = "0.61.5";
5716
+ var PARSEMAN_VERSION = "0.61.7";
5712
5717
 
5713
5718
  // src/table/lex-body.ts
5714
5719
  function buildLexBodyRecognizer(spec, constants) {
@@ -6677,7 +6682,7 @@ function sequence(...parsers) {
6677
6682
  if (tolerant) {
6678
6683
  followSentinels ??= parsers.map((_, i) => firstSetSentinel(
6679
6684
  parsers.slice(i + 1).reduce(
6680
- (set, parser2) => union(set, firstSetOf(parser2, /* @__PURE__ */ new Set(), void 0, void 0, false)),
6685
+ (set, parser2) => union(set, firstSetOf(parser2, /* @__PURE__ */ new Set(), void 0, void 0, false, true)),
6681
6686
  { kind: "empty" }
6682
6687
  )
6683
6688
  ));
@@ -8543,7 +8548,7 @@ var Encoder = class {
8543
8548
  let fs = { kind: "empty" };
8544
8549
  const rr = this.refResolver();
8545
8550
  for (let j = i + 1; j < parsers.length; j++) {
8546
- fs = union(fs, firstSetOf(parsers[j], /* @__PURE__ */ new Set(), rr, void 0, false));
8551
+ fs = union(fs, firstSetOf(parsers[j], /* @__PURE__ */ new Set(), rr, void 0, false, true));
8547
8552
  }
8548
8553
  return this.charClass(fs);
8549
8554
  }
@@ -11038,17 +11043,17 @@ var WRAPPERS = /* @__PURE__ */ new Set([
11038
11043
  OP_SCOPE_PLAIN,
11039
11044
  OP_FIELD,
11040
11045
  OP_LABEL,
11041
- OP_EXPECT,
11042
11046
  OP_WITHCTX,
11043
11047
  OP_RULE,
11044
11048
  OP_ATTEMPT,
11045
11049
  OP_COV,
11046
11050
  OP_GAPGATE
11047
11051
  ]);
11048
- function rowNullable(code, k, ip, memo) {
11049
- const hit = memo.get(ip);
11052
+ function rowNullable(code, k, ip, memo, recovers = true) {
11053
+ const key = recovers ? ip : ~ip;
11054
+ const hit = memo.get(key);
11050
11055
  if (hit !== void 0) return hit;
11051
- memo.set(ip, true);
11056
+ memo.set(key, true);
11052
11057
  const op = code[ip];
11053
11058
  const kids = [];
11054
11059
  let out = true;
@@ -11059,20 +11064,20 @@ function rowNullable(code, k, ip, memo) {
11059
11064
  out = !(re instanceof RegExp) || regexCanMatchEmpty(re.source);
11060
11065
  } else if (op === OP_SEQ || op === OP_SEQV || op === OP_SEQX) {
11061
11066
  childSlots(code, ip, kids);
11062
- out = kids.every((c) => rowNullable(code, k, c, memo));
11067
+ out = kids.every((c) => rowNullable(code, k, c, memo, recovers));
11063
11068
  } else if (op === OP_CHOICE) {
11064
11069
  childSlots(code, ip, kids);
11065
- out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo));
11070
+ out = kids.length === 0 || kids.some((c) => rowNullable(code, k, c, memo, recovers));
11066
11071
  } else if (op === OP_REP || op === OP_REPV) {
11067
- out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo);
11072
+ out = code[ip + 2] === 0 || rowNullable(code, k, code[ip + 1], memo, recovers);
11068
11073
  } else if (op === OP_SEED) {
11069
- out = rowNullable(code, k, code[ip + 1], memo);
11074
+ out = rowNullable(code, k, code[ip + 1], memo, recovers);
11070
11075
  } else if (op === OP_CONT) {
11071
- out = rowNullable(code, k, code[ip + 1], memo) && rowNullable(code, k, code[ip + 3], memo);
11072
- } else if (WRAPPERS.has(op)) {
11073
- if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo);
11076
+ out = rowNullable(code, k, code[ip + 1], memo, recovers) && rowNullable(code, k, code[ip + 3], memo, recovers);
11077
+ } else if (WRAPPERS.has(op) || op === OP_EXPECT && !recovers) {
11078
+ if (childSlots(code, ip, kids) && kids.length === 1) out = rowNullable(code, k, kids[0], memo, recovers);
11074
11079
  }
11075
- memo.set(ip, out);
11080
+ memo.set(key, out);
11076
11081
  return out;
11077
11082
  }
11078
11083
  function holdsGap(code, k, base, n, i, memo) {
@@ -11081,7 +11086,7 @@ function holdsGap(code, k, base, n, i, memo) {
11081
11086
  if (code[term] !== OP_NOT && code[term] !== OP_PEEK) return false;
11082
11087
  const next = code[base + i + 1];
11083
11088
  if (code[next] === OP_ADJ || leadingTriviaFieldAt(code, k, next)) return false;
11084
- return !rowNullable(code, k, next, memo);
11089
+ return !rowNullable(code, k, next, memo, false);
11085
11090
  }
11086
11091
 
11087
11092
  // src/table/gap-gate.ts
@@ -11403,11 +11408,35 @@ ${fast}
11403
11408
  ${scanned}
11404
11409
  }`;
11405
11410
  }
11406
- function emitHoldTerm(callee, dst, t2, l, skip) {
11411
+ var TRIVIA_LOG_LENGTH = "ctx._cstBuf!==undefined?(ctx._cstBuf.tl!==undefined?ctx._cstBuf.tl.length:0):(ctx._cstTriviaLog!==undefined?ctx._cstTriviaLog.length:0)";
11412
+ function emitHoldTerm(callee, dst, t2, l, skip, recovers) {
11407
11413
  const fast = `const ${t2}v=${callee}(input,cur,ctx)
11408
11414
  if(${t2}v===FAIL)return FAIL
11409
11415
  ${dst}=${t2}v
11410
11416
  cur=EC.e`;
11417
+ if (recovers) {
11418
+ 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`;
11419
+ if (l.tri === TRI_NONE) return `${marked}
11420
+ ${fast}`;
11421
+ const held2 = `${t2}tl=${TRIVIA_LOG_LENGTH}
11422
+ ${t2}lg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
11423
+ ${t2}rt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
11424
+ ${t2}s=${skip}(input,cur,ctx)
11425
+ ${t2}stl=${TRIVIA_LOG_LENGTH}
11426
+ ${t2}slg=ctx._triviaLog!==undefined?ctx._triviaLog.length:0
11427
+ ${t2}srt=ctx._rootTriviaLog!==undefined?ctx._rootTriviaLog.length:0
11428
+ const ${t2}v=${callee}(input,${t2}s,ctx)
11429
+ if(${t2}v===FAIL)return FAIL
11430
+ ${dst}=${t2}v
11431
+ cur=${t2}s`;
11432
+ return l.tri !== TRI_UNKNOWN ? `${marked}
11433
+ ${held2}` : `${marked}
11434
+ if(ctx.trivia===undefined){
11435
+ ${fast}
11436
+ }else{
11437
+ ${held2}
11438
+ }`;
11439
+ }
11411
11440
  if (l.tri === TRI_NONE) return fast;
11412
11441
  const held = `const ${t2}s=${skip}(input,cur,ctx)
11413
11442
  const ${t2}v=${callee}(input,${t2}s,ctx)
@@ -11421,6 +11450,9 @@ ${fast}
11421
11450
  ${held}
11422
11451
  }`;
11423
11452
  }
11453
+ function emitHeldGapUndo(t2) {
11454
+ 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}`;
11455
+ }
11424
11456
  function leadSkip(hasTrivia, leadTrivia, skip) {
11425
11457
  if (hasTrivia === "false") return "{}";
11426
11458
  const call = `itemStart=${skip}(input,itemStart,ctx)`;
@@ -12429,6 +12461,7 @@ return v
12429
12461
  }
12430
12462
  parts.push("let cur=EC.e");
12431
12463
  const names = ["v0"];
12464
+ let heldUndo;
12432
12465
  for (let i = 1; i < n; i++) {
12433
12466
  const vn = `v${i}`;
12434
12467
  parts.push(`let ${vn}`);
@@ -12445,7 +12478,16 @@ return v
12445
12478
  );
12446
12479
  } else {
12447
12480
  const callee = leadingTriviaFieldAt(code, k, childIp) ? `(LEAD.at=cur,${kids[i]})` : kids[i];
12448
- 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));
12481
+ if (holdsGap(code, k, base, n, i, nullable2)) {
12482
+ const t3 = tmp();
12483
+ const recovers = rowNullable(code, k, code[base + i + 1], nullable2);
12484
+ parts.push(emitHoldTerm(callee, vn, t3, L, skipFor(L), recovers));
12485
+ heldUndo = recovers ? t3 : void 0;
12486
+ } else {
12487
+ parts.push(emitTerm(callee, vn, tmp(), L, skipFor(L), L.tri >= 0 ? triviaMiss(L.tri) : void 0));
12488
+ if (heldUndo !== void 0) parts.push(emitHeldGapUndo(heldUndo));
12489
+ heldUndo = void 0;
12490
+ }
12449
12491
  }
12450
12492
  names.push(vn);
12451
12493
  }
@@ -16018,8 +16060,46 @@ function assemble(t2, prog, cfg) {
16018
16060
  }
16019
16061
  if (hasAdj) {
16020
16062
  const first2 = linkFirst();
16063
+ let heldFrom = 0, heldTl = 0, heldScanTl = 0, heldLog = 0, heldScanLog = 0, heldRoot = 0, heldScanRoot = 0;
16021
16064
  const runnerAt = (i) => {
16022
16065
  const kidIp = code[base + i];
16066
+ if (i > 1 && holdsGap(code, k, base, n, i - 1, NULLABLE) && rowNullable(code, k, kidIp, NULLABLE)) {
16067
+ const kid = link(kidIp);
16068
+ return (input, cur, ctx) => {
16069
+ const from = heldFrom, tl = heldTl, scanTl = heldScanTl, log = heldLog;
16070
+ const scanLog = heldScanLog, root = heldRoot, scanRoot = heldScanRoot;
16071
+ const next = step(kid, input, cur, ctx);
16072
+ if (next !== cur || from === cur) return next;
16073
+ rollbackScannedTriviaAt(ctx, tl, scanTl, log, scanLog, root, scanRoot);
16074
+ return from;
16075
+ };
16076
+ }
16077
+ if (holdsGap(code, k, base, n, i, NULLABLE) && rowNullable(code, k, code[base + i + 1], NULLABLE)) {
16078
+ const kid = link(kidIp);
16079
+ return (input, cur, ctx) => {
16080
+ if (ctx.trivia === void 0) {
16081
+ const v2 = kid(input, cur, ctx);
16082
+ if (v2 === FAIL) return -1;
16083
+ TERMV = v2;
16084
+ heldFrom = cur;
16085
+ return EC.e;
16086
+ }
16087
+ const tl = cstTlLen(ctx), log = ctx._triviaLog?.length ?? 0, root = ctx._rootTriviaLog?.length ?? 0;
16088
+ const scanEnd = skipTrivia(input, cur, ctx);
16089
+ const scanTl = cstTlLen(ctx), scanLog = ctx._triviaLog?.length ?? 0, scanRoot = ctx._rootTriviaLog?.length ?? 0;
16090
+ const v = kid(input, scanEnd, ctx);
16091
+ if (v === FAIL) return -1;
16092
+ TERMV = v;
16093
+ heldFrom = cur;
16094
+ heldTl = tl;
16095
+ heldScanTl = scanTl;
16096
+ heldLog = log;
16097
+ heldScanLog = scanLog;
16098
+ heldRoot = root;
16099
+ heldScanRoot = scanRoot;
16100
+ return scanEnd;
16101
+ };
16102
+ }
16023
16103
  if (holdsGap(code, k, base, n, i, NULLABLE)) {
16024
16104
  const kid = link(kidIp);
16025
16105
  return (input, cur, ctx) => {