parseman 0.60.6 → 0.61.0

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.
Files changed (40) hide show
  1. package/dist/analysis/diagnostics.js +47 -36
  2. package/dist/analysis/diagnostics.js.map +3 -3
  3. package/dist/cli/index.js +47 -36
  4. package/dist/cli/index.js.map +3 -3
  5. package/dist/combinators/choice.d.ts.map +1 -1
  6. package/dist/combinators/expect.d.ts.map +1 -1
  7. package/dist/combinators/link-scope.d.ts +7 -0
  8. package/dist/combinators/link-scope.d.ts.map +1 -0
  9. package/dist/combinators/node.d.ts.map +1 -1
  10. package/dist/combinators/parser.d.ts.map +1 -1
  11. package/dist/compiler/token-capability.js +1 -0
  12. package/dist/compiler/token-capability.js.map +1 -1
  13. package/dist/compiler/value-usage.d.ts.map +1 -1
  14. package/dist/functional/run.d.ts.map +1 -1
  15. package/dist/index.js +91 -66
  16. package/dist/index.js.map +3 -3
  17. package/dist/language-service/index.js +1 -1
  18. package/dist/language-service/index.js.map +1 -1
  19. package/dist/plugin/index.js +254 -229
  20. package/dist/plugin/index.js.map +3 -3
  21. package/dist/run/index.js +1 -1
  22. package/dist/run/index.js.map +1 -1
  23. package/dist/spec/index.js.map +1 -1
  24. package/dist/table/emit.d.ts.map +1 -1
  25. package/dist/table/index.js +11 -6
  26. package/dist/table/index.js.map +3 -3
  27. package/dist/table/program.d.ts +3 -1
  28. package/dist/table/program.d.ts.map +1 -1
  29. package/dist/version.d.ts +1 -1
  30. package/package.json +1 -1
  31. package/src/combinators/choice.ts +3 -1
  32. package/src/combinators/expect.ts +1 -0
  33. package/src/combinators/link-scope.ts +19 -0
  34. package/src/combinators/node.ts +11 -2
  35. package/src/combinators/parser.ts +37 -31
  36. package/src/compiler/value-usage.ts +16 -29
  37. package/src/functional/run.ts +3 -1
  38. package/src/table/emit.ts +5 -1
  39. package/src/table/program.ts +8 -2
  40. package/src/version.ts +1 -1
package/dist/index.js CHANGED
@@ -3203,6 +3203,7 @@ function derive(c, seen) {
3203
3203
  case "optional":
3204
3204
  case "many":
3205
3205
  case "oneOrMore":
3206
+ case "sepBy":
3206
3207
  case "transform":
3207
3208
  case "not":
3208
3209
  case "peek":
@@ -3353,7 +3354,7 @@ function choice(...args) {
3353
3354
  const result = parsers[idx].parse(input, pos, ctx);
3354
3355
  if (result.ok) return result;
3355
3356
  expected.push(...result.expected);
3356
- if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
3357
+ if (result.committed) return { ok: false, expected, span: result.span, committed: true };
3357
3358
  return { ok: false, expected, span: { start: pos, end: pos } };
3358
3359
  }
3359
3360
  if (ctx._probe !== void 0 || ctx._tolerant) for (const p of parsers) p.parse(input, pos, ctx);
@@ -4348,15 +4349,20 @@ function markUnusedValues(root) {
4348
4349
  case "many":
4349
4350
  case "oneOrMore":
4350
4351
  mark(def, consumed);
4351
- visit(def.parser, consumed);
4352
- return;
4353
4352
  case "optional":
4353
+ // `optional` returns `inner | null` — no aggregate array/tuple to elide, so
4354
+ // it carries no valueUnused flag. Still descend so an inner many/sequence
4355
+ // under a node() is analyzed (it benefits even when its optional wrapper
4356
+ // doesn't).
4357
+ case "label":
4358
+ case "trivia":
4359
+ case "attempt":
4360
+ case "withCtx":
4361
+ case "expect":
4354
4362
  visit(def.parser, consumed);
4355
4363
  return;
4356
4364
  case "sequence":
4357
4365
  mark(def, consumed);
4358
- for (const p of def.parsers) visit(p, consumed);
4359
- return;
4360
4366
  case "choice":
4361
4367
  for (const p of def.parsers) visit(p, consumed);
4362
4368
  return;
@@ -4367,22 +4373,24 @@ function markUnusedValues(root) {
4367
4373
  if (def.otherwise) visit(def.otherwise, consumed);
4368
4374
  return;
4369
4375
  case "node":
4376
+ // builds from captured children, NOT the inner parser value.
4377
+ case "not":
4378
+ case "peek":
4379
+ // lookahead — value never observed
4380
+ case "token":
4370
4381
  visit(def.parser, false);
4371
4382
  return;
4372
4383
  case "transform":
4373
- visit(def.parser, true);
4374
- return;
4384
+ // the map fn reads the value → always consumed.
4375
4385
  case "field":
4386
+ // the field capture records the parsed value → always consumed.
4387
+ case "leaf":
4376
4388
  visit(def.parser, true);
4377
4389
  return;
4378
4390
  case "sepBy":
4379
4391
  visit(def.parser, true);
4380
4392
  visit(def.separator, false);
4381
4393
  return;
4382
- case "not":
4383
- case "peek":
4384
- visit(def.parser, false);
4385
- return;
4386
4394
  case "grammar":
4387
4395
  visit(def.parser, consumed);
4388
4396
  if (def.triviaParser) visit(def.triviaParser, false);
@@ -4391,19 +4399,6 @@ function markUnusedValues(root) {
4391
4399
  visit(def.parser, consumed);
4392
4400
  visit(def.sentinel, false);
4393
4401
  return;
4394
- case "token":
4395
- visit(def.parser, false);
4396
- return;
4397
- case "label":
4398
- case "trivia":
4399
- case "attempt":
4400
- case "withCtx":
4401
- case "expect":
4402
- visit(def.parser, consumed);
4403
- return;
4404
- case "leaf":
4405
- visit(def.parser, true);
4406
- return;
4407
4402
  case "lazy":
4408
4403
  return;
4409
4404
  default:
@@ -4433,6 +4428,21 @@ function markUnusedValues(root) {
4433
4428
  visit(resolveRoot2(root), true);
4434
4429
  }
4435
4430
 
4431
+ // src/combinators/link-scope.ts
4432
+ var scope;
4433
+ function afterLink(settle) {
4434
+ scope?.push(settle);
4435
+ }
4436
+ function collectAfterLink(pending, build) {
4437
+ const outer = scope;
4438
+ scope = outer ?? pending;
4439
+ try {
4440
+ return build();
4441
+ } finally {
4442
+ scope = outer;
4443
+ }
4444
+ }
4445
+
4436
4446
  // src/cst/root-trivia-scope.ts
4437
4447
  var ROOT_TRIVIA_SCOPE_REFUSAL = "parser(): selected root trivia requires classifiedTrivia() for every local trivia scope, or rootCapture: 'opaque'.";
4438
4448
  function refuseUnclassifiedRootScope(strict) {
@@ -4779,6 +4789,7 @@ function linkRules(recipes, link) {
4779
4789
  }
4780
4790
  });
4781
4791
  const winners = /* @__PURE__ */ new Map();
4792
+ const afterLink2 = [];
4782
4793
  const priorHoles = /* @__PURE__ */ new Map();
4783
4794
  const prior = new Proxy({}, {
4784
4795
  get(_target, key) {
@@ -4791,38 +4802,42 @@ function linkRules(recipes, link) {
4791
4802
  return hole;
4792
4803
  }
4793
4804
  });
4794
- for (const recipe of recipes) {
4795
- const definitions = recipe.factory(proxy, prior);
4796
- for (const key of Object.keys(definitions)) {
4797
- winners.set(key, { parser: definitions[key], options: recipe.options });
4798
- }
4799
- }
4800
- const keys = [...winners.keys()];
4801
4805
  const copies = /* @__PURE__ */ new Map();
4802
- for (const [key, { parser: defined }] of winners) {
4803
- const placeholder = cache[key];
4804
- const parser2 = ownRule(defined, copies);
4805
- if (placeholder === parser2) {
4806
- throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
4807
- }
4808
- if (isDefinableRef(placeholder)) {
4809
- if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
4810
- placeholder.define(parser2);
4811
- placeholder._meta.firstSet = parser2._meta.firstSet;
4812
- placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
4813
- } else if (isNamedRuleRefForAnotherRule(parser2, key) || link !== void 0) {
4814
- if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
4815
- const alias = ref();
4816
- tagRule(alias, key);
4817
- alias.define(parser2);
4818
- alias._meta.firstSet = parser2._meta.firstSet;
4819
- alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
4820
- cache[key] = alias;
4821
- } else {
4822
- tagRule(parser2, key);
4823
- cache[key] = parser2;
4806
+ try {
4807
+ for (const recipe of recipes) {
4808
+ const definitions = collectAfterLink(afterLink2, () => recipe.factory(proxy, prior));
4809
+ for (const key of Object.keys(definitions)) {
4810
+ winners.set(key, { parser: definitions[key], options: recipe.options });
4811
+ }
4812
+ }
4813
+ for (const [key, { parser: defined }] of winners) {
4814
+ const placeholder = cache[key];
4815
+ const parser2 = ownRule(defined, copies);
4816
+ if (placeholder === parser2) {
4817
+ throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
4818
+ }
4819
+ if (isDefinableRef(placeholder)) {
4820
+ if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
4821
+ placeholder.define(parser2);
4822
+ placeholder._meta.firstSet = parser2._meta.firstSet;
4823
+ placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
4824
+ } else if (isNamedRuleRefForAnotherRule(parser2, key) || link !== void 0) {
4825
+ if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
4826
+ const alias = ref();
4827
+ tagRule(alias, key);
4828
+ alias.define(parser2);
4829
+ alias._meta.firstSet = parser2._meta.firstSet;
4830
+ alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
4831
+ cache[key] = alias;
4832
+ } else {
4833
+ tagRule(parser2, key);
4834
+ cache[key] = parser2;
4835
+ }
4824
4836
  }
4837
+ } finally {
4838
+ for (const settle of afterLink2) settle();
4825
4839
  }
4840
+ const keys = [...winners.keys()];
4826
4841
  for (const key of keys) {
4827
4842
  const options = winners.get(key).options;
4828
4843
  let rule = cache[key];
@@ -5307,8 +5322,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
5307
5322
  const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || buildArity !== void 0 || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...buildArity !== void 0 ? { buildArity } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
5308
5323
  const capturesTrivia = captureTrivia || (build ? buildReadsTrivia(def) : project === void 0);
5309
5324
  const readsState = build ? buildReadsState(def) : project === void 0;
5310
- const hasOwnFields = parserHasOwnFields(combinator);
5311
- const capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
5325
+ let hasOwnFields = parserHasOwnFields(combinator);
5326
+ let capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
5327
+ if (!hasOwnFields) {
5328
+ afterLink(() => {
5329
+ hasOwnFields = parserHasOwnFields(combinator);
5330
+ capturesFields = hasOwnFields && (build ? buildReadsFields(def) : project === void 0);
5331
+ });
5332
+ }
5312
5333
  const guardable = combinator._meta.firstSet.kind !== "any" && !matchesEmpty(combinator);
5313
5334
  let failExpected;
5314
5335
  return {
@@ -5621,6 +5642,9 @@ function sourceLeaf(root, fn) {
5621
5642
  return makeLeaf(root, fn, true);
5622
5643
  }
5623
5644
 
5645
+ // src/version.ts
5646
+ var PARSEMAN_VERSION = "0.61.0";
5647
+
5624
5648
  // src/table/lex-body.ts
5625
5649
  function buildLexBodyRecognizer(spec, constants) {
5626
5650
  const raw = constants[spec[0]];
@@ -6236,11 +6260,12 @@ function assemblyExtraIps(prog) {
6236
6260
  }
6237
6261
  function expandCompact(p) {
6238
6262
  if ("code" in p) return p;
6263
+ if (p.es === void 0) throw new Error(`parseman: this parser was printed by an earlier parseman; reprint it with parseman ${PARSEMAN_VERSION}`);
6239
6264
  return ownTableProgram({
6240
6265
  code: p.c,
6241
6266
  k: p.k,
6242
6267
  cc: p.x,
6243
- fx: p.e,
6268
+ fx: p.e.map((set) => set.map((i) => p.es[i])),
6244
6269
  disp: p.d,
6245
6270
  rules: p.r,
6246
6271
  fns: p.f,
@@ -7649,7 +7674,7 @@ function selectOptionalSuffixLexBody(ir) {
7649
7674
  function reinstallsRuleTrivia(reference, target) {
7650
7675
  return (reference._meta.grammarTrivia ?? target._meta.grammarTrivia) !== void 0 && hasOwnTriviaBoundary(target);
7651
7676
  }
7652
- function directTokenBodyParser(parser2, resolve, scope) {
7677
+ function directTokenBodyParser(parser2, resolve, scope2) {
7653
7678
  const outer = parser2._def;
7654
7679
  if (outer.tag !== "token") return void 0;
7655
7680
  let body = outer.parser;
@@ -7659,7 +7684,7 @@ function directTokenBodyParser(parser2, resolve, scope) {
7659
7684
  const wrapper = body._def;
7660
7685
  if (wrapper.tag === "grammar") {
7661
7686
  if (wrapper.clearTrivia !== true || wrapper.triviaParser !== void 0 || wrapper.captureTrivia === true || wrapper.rootCapture === "opaque" || wrapper.constructionTrackLines !== "inherit" || wrapper.constructionCaptureTriviaKinds !== void 0) return void 0;
7662
- if (scope !== void 0) scope.cleared = true;
7687
+ if (scope2 !== void 0) scope2.cleared = true;
7663
7688
  body = wrapper.parser;
7664
7689
  continue;
7665
7690
  }
@@ -7916,10 +7941,10 @@ function directFixedLexNode(parser2, resolve, active, pureOnly = false, cleared
7916
7941
  }
7917
7942
  }
7918
7943
  function directFixedTokenBody(parser2, resolve) {
7919
- const scope = { cleared: false };
7920
- const body = directTokenBodyParser(parser2, resolve, scope);
7944
+ const scope2 = { cleared: false };
7945
+ const body = directTokenBodyParser(parser2, resolve, scope2);
7921
7946
  if (body === void 0) return void 0;
7922
- const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set(), false, scope.cleared);
7947
+ const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set(), false, scope2.cleared);
7923
7948
  return root === void 0 ? void 0 : { kind: "fixed-tree", root };
7924
7949
  }
7925
7950
  function directBalancedTokenBody(parser2, resolve) {
@@ -13918,9 +13943,6 @@ function clearOf(ranges, input, from, to) {
13918
13943
  return true;
13919
13944
  }
13920
13945
 
13921
- // src/version.ts
13922
- var PARSEMAN_VERSION = "0.60.6";
13923
-
13924
13946
  // src/table/assemble.ts
13925
13947
  import { PlainBuf as PlainBuf2, PlainField, PlainLeaf as PlainLeaf9, PlainNode as PlainNode2, PlainSpan as PlainSpan10 } from "./cst/plain.js";
13926
13948
 
@@ -17928,12 +17950,15 @@ function assertPrintable(prog, who) {
17928
17950
  }
17929
17951
  }
17930
17952
  function programFields(prog, fns, opts = {}) {
17953
+ const tokens = [...new Set(prog.fx.flat())];
17954
+ const tokenAt = new Map(tokens.map((token2, i) => [token2, i]));
17931
17955
  return [
17932
17956
  ...emitAssemblies(prog, opts.assemblies ?? []),
17933
17957
  `c:[${prog.code.join(",")}],`,
17934
17958
  `k:[${prog.k.map(emitConst).join(",")}],`,
17935
17959
  `x:${emitClassPool(prog.cc)},`,
17936
- `e:[${prog.fx.map((f) => `[${f.map(jsString).join(",")}]`).join(",")}],`,
17960
+ `e:[${prog.fx.map((f) => `[${f.map((token2) => tokenAt.get(token2)).join(",")}]`).join(",")}],`,
17961
+ `es:[${tokens.map(jsString).join(",")}],`,
17937
17962
  `d:[${prog.disp.map((a) => `[${a.join(",")}]`).join(",")}],`,
17938
17963
  `r:${JSON.stringify(prog.rules)},`,
17939
17964
  ...prog.lines === 1 ? ["l:1,"] : [],
@@ -21056,7 +21081,7 @@ function runOnce(entry, input, options) {
21056
21081
  const r = invoke(entry, input, 0, ctx);
21057
21082
  const value = r.ok ? r.value : void 0;
21058
21083
  let span = r.span ?? { start: 0, end: 0 };
21059
- const expected = r.ok ? [] : r.expected ?? [];
21084
+ const expected = r.ok ? [] : [...new Set(r.expected ?? [])];
21060
21085
  let unconsumedFrom = null;
21061
21086
  if (r.ok) {
21062
21087
  let pos = span.end;