parseman 0.50.6 → 0.51.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 (59) hide show
  1. package/dist/analysis/choice-cost.d.ts.map +1 -1
  2. package/dist/analysis/commitment.d.ts.map +1 -1
  3. package/dist/analysis/diagnostics.js +214 -67
  4. package/dist/analysis/diagnostics.js.map +2 -2
  5. package/dist/analysis/duplication.d.ts.map +1 -1
  6. package/dist/analysis/gating.d.ts.map +1 -1
  7. package/dist/cli/index.js +220 -68
  8. package/dist/cli/index.js.map +2 -2
  9. package/dist/combinators/dispatch.d.ts.map +1 -1
  10. package/dist/combinators/first-set.d.ts +2 -26
  11. package/dist/combinators/first-set.d.ts.map +1 -1
  12. package/dist/combinators/scanTo.d.ts +23 -1
  13. package/dist/combinators/scanTo.d.ts.map +1 -1
  14. package/dist/compiler/fields.d.ts.map +1 -1
  15. package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
  16. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  17. package/dist/compiler/token-capability.js +40 -29
  18. package/dist/compiler/token-capability.js.map +1 -1
  19. package/dist/coverage.d.ts.map +1 -1
  20. package/dist/cst/reflection.d.ts.map +1 -1
  21. package/dist/index.js +241 -74
  22. package/dist/index.js.map +2 -2
  23. package/dist/plugin/index.js +228 -71
  24. package/dist/plugin/index.js.map +2 -2
  25. package/dist/spec/index.js +164 -48
  26. package/dist/spec/index.js.map +2 -2
  27. package/dist/table/assemble.d.ts.map +1 -1
  28. package/dist/table/emit.d.ts.map +1 -1
  29. package/dist/table/encode.d.ts.map +1 -1
  30. package/dist/table/exec.d.ts.map +1 -1
  31. package/dist/table/index.js +220 -68
  32. package/dist/table/index.js.map +2 -2
  33. package/dist/table/program.d.ts +2 -0
  34. package/dist/table/program.d.ts.map +1 -1
  35. package/dist/types.d.ts +2 -0
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/version.d.ts +1 -1
  38. package/package.json +1 -1
  39. package/src/analysis/choice-cost.ts +6 -1
  40. package/src/analysis/commitment.ts +10 -2
  41. package/src/analysis/duplication.ts +7 -2
  42. package/src/analysis/gating.ts +6 -1
  43. package/src/analysis/rebuild.ts +1 -1
  44. package/src/combinators/dispatch.ts +4 -1
  45. package/src/combinators/first-set.ts +58 -36
  46. package/src/combinators/scanTo.ts +163 -9
  47. package/src/compiler/fields.ts +8 -2
  48. package/src/compiler/grammar-coverage-ids.ts +6 -1
  49. package/src/compiler/ir-serialize.ts +7 -2
  50. package/src/compiler/token-alphabet.ts +1 -1
  51. package/src/coverage.ts +7 -1
  52. package/src/cst/reflection.ts +6 -1
  53. package/src/table/assemble.ts +11 -1
  54. package/src/table/emit.ts +4 -0
  55. package/src/table/encode.ts +16 -8
  56. package/src/table/exec.ts +7 -1
  57. package/src/table/program.ts +2 -0
  58. package/src/types.ts +1 -1
  59. package/src/version.ts +1 -1
@@ -31,7 +31,7 @@ function intersects(a, b) {
31
31
  return false;
32
32
  }
33
33
  function fromChar(code) {
34
- return { kind: "ranges", ranges: [{ lo: code, hi: code }] };
34
+ return fromRange(code, code);
35
35
  }
36
36
  function startsFirstSet(combinator, input, pos) {
37
37
  const fs = combinator._meta.firstSet;
@@ -124,11 +124,10 @@ function matchesEmptyBody(p, seen, resolve) {
124
124
  }
125
125
  }
126
126
  function isZeroWidthAssertion(p) {
127
- const tag = p._def.tag;
128
- return tag === "not" || tag === "adjacency";
127
+ return p._tag === "not" || p._tag === "adjacency";
129
128
  }
130
129
  function isPositiveLookahead(p) {
131
- return p._def.tag === "peek";
130
+ return p._tag === "peek";
132
131
  }
133
132
  function narrowBy(acc, constraint) {
134
133
  if (constraint.kind === "any") return acc;
@@ -144,34 +143,42 @@ function narrowBy(acc, constraint) {
144
143
  return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
145
144
  }
146
145
  function applyAssertion(fs, assertion) {
147
- if (assertion === null) return fs;
148
- if (fs.kind === "empty") return assertion;
149
- return narrowBy(fs, assertion) ?? fs;
146
+ return assertion === null ? fs : fs.kind === "empty" ? assertion : narrowBy(fs, assertion);
150
147
  }
151
- function sequenceFirstSet(parsers) {
152
- let fs = empty();
153
- let assertion = null;
154
- for (const p of parsers) {
148
+ function sequenceSet(parsers, fs, empties, trivia2) {
149
+ const afterBoundary = (i) => {
150
+ const rest = at(i);
151
+ return trivia2 ? union(rest, fs(trivia2)) : rest;
152
+ };
153
+ const at = (i) => {
154
+ const p = parsers[i];
155
155
  if (isPositiveLookahead(p)) {
156
- assertion = narrowBy(assertion, p._meta.firstSet);
157
- continue;
156
+ const constraint = fs(p);
157
+ return i + 1 === parsers.length ? constraint : applyAssertion(afterBoundary(i + 1), constraint);
158
158
  }
159
- if (!isZeroWidthAssertion(p)) fs = union(fs, p._meta.firstSet);
160
- if (!matchesEmpty(p)) return applyAssertion(fs, assertion);
161
- }
162
- return applyAssertion(fs, assertion);
159
+ if (isZeroWidthAssertion(p)) {
160
+ return i + 1 === parsers.length ? empty() : afterBoundary(i + 1);
161
+ }
162
+ const first = fs(p);
163
+ if (!empties(p) || i + 1 === parsers.length) return first;
164
+ return union(first, afterBoundary(i + 1));
165
+ };
166
+ return at(0);
163
167
  }
164
- function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve) {
168
+ function sequenceFirstSet(parsers) {
169
+ return sequenceSet(parsers, (p) => p._meta.firstSet, matchesEmpty);
170
+ }
171
+ function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve, activeTrivia) {
165
172
  if (seen.has(p)) return any();
166
173
  seen.add(p);
167
174
  try {
168
- return firstSetBody(p, seen, resolve);
175
+ return firstSetBody(p, seen, resolve, activeTrivia);
169
176
  } finally {
170
177
  seen.delete(p);
171
178
  }
172
179
  }
173
- function firstSetBody(p, seen, resolve) {
174
- const fs = (c) => firstSetOf(c, seen, resolve);
180
+ function firstSetBody(p, seen, resolve, activeTrivia) {
181
+ const fs = (c) => firstSetOf(c, seen, resolve, activeTrivia);
175
182
  const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve);
176
183
  const d = p._def;
177
184
  switch (d.tag) {
@@ -197,17 +204,7 @@ function firstSetBody(p, seen, resolve) {
197
204
  return out;
198
205
  }
199
206
  case "sequence": {
200
- let out = empty();
201
- let assertion = null;
202
- for (const term of d.parsers) {
203
- if (isPositiveLookahead(term)) {
204
- assertion = narrowBy(assertion, fs(term));
205
- continue;
206
- }
207
- if (!isZeroWidthAssertion(term)) out = union(out, fs(term));
208
- if (!empties(term)) return applyAssertion(out, assertion);
209
- }
210
- return applyAssertion(out, assertion);
207
+ return sequenceSet(d.parsers, fs, empties, activeTrivia);
211
208
  }
212
209
  case "peek": {
213
210
  const inner = d.parser;
@@ -222,12 +219,16 @@ function firstSetBody(p, seen, resolve) {
222
219
  case "token":
223
220
  case "leaf":
224
221
  case "node":
225
- case "grammar":
226
- case "expect":
227
- return fs(d.parser);
228
222
  case "sepBy":
223
+ case "expect":
229
224
  return fs(d.parser);
230
- // both min 0 and min 1 start with the item
225
+ case "grammar":
226
+ return firstSetOf(
227
+ d.parser,
228
+ seen,
229
+ resolve,
230
+ d.clearTrivia ? null : d.triviaParser ?? activeTrivia
231
+ );
231
232
  default:
232
233
  return p._meta.firstSet;
233
234
  }
@@ -1705,7 +1706,12 @@ function childrenOf(def) {
1705
1706
  case "sepBy":
1706
1707
  return [def.parser, def.separator];
1707
1708
  case "scanTo":
1708
- return [def.sentinel, ...def.skip];
1709
+ return [
1710
+ def.sentinel,
1711
+ ...def.skip,
1712
+ ...def.recoverAt === void 0 ? [] : [def.recoverAt],
1713
+ ...def.stopAt === void 0 ? [] : [def.stopAt]
1714
+ ];
1709
1715
  case "routed":
1710
1716
  return def.fallback ? [def.fallback] : [];
1711
1717
  case "literal":
@@ -3750,7 +3756,7 @@ function parserUsesRouted(parser2, seen = /* @__PURE__ */ new Set()) {
3750
3756
  case "grammar":
3751
3757
  return parserUsesRouted(def.parser, seen) || (def.triviaParser ? parserUsesRouted(def.triviaParser, seen) : false);
3752
3758
  case "scanTo":
3753
- return parserUsesRouted(def.sentinel, seen) || def.skip.some((entry) => parserUsesRouted(entry, seen));
3759
+ return parserUsesRouted(def.sentinel, seen) || def.skip.some((entry) => parserUsesRouted(entry, seen)) || def.recoverAt !== void 0 && parserUsesRouted(def.recoverAt, seen) || def.stopAt !== void 0 && parserUsesRouted(def.stopAt, seen);
3754
3760
  case "recover":
3755
3761
  return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.sentinel, seen);
3756
3762
  case "lazy":
@@ -4657,7 +4663,7 @@ function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
4657
4663
  case "grammar":
4658
4664
  return parserHasOwnFields(d.parser, seen) || (d.triviaParser ? parserHasOwnFields(d.triviaParser, seen) : false);
4659
4665
  case "scanTo":
4660
- return parserHasOwnFields(d.sentinel, seen) || d.skip.some((x) => parserHasOwnFields(x, seen));
4666
+ return parserHasOwnFields(d.sentinel, seen) || d.skip.some((x) => parserHasOwnFields(x, seen)) || d.recoverAt !== void 0 && parserHasOwnFields(d.recoverAt, seen) || d.stopAt !== void 0 && parserHasOwnFields(d.stopAt, seen);
4661
4667
  case "recover":
4662
4668
  return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.sentinel, seen);
4663
4669
  case "routed":
@@ -5034,7 +5040,7 @@ function resolveScanSkip(explicitSkip, raw, ctx) {
5034
5040
  out.push(...explicitSkip);
5035
5041
  return out;
5036
5042
  }
5037
- function scanTo(sentinel, { skip, raw = false, orEOF = false } = {}) {
5043
+ function scanTo(sentinel, { skip, raw = false, orEOF = false, recoverAt, stopAt } = {}) {
5038
5044
  const meta = {
5039
5045
  firstSet: any(),
5040
5046
  canMatchNewline: true,
@@ -5044,7 +5050,15 @@ function scanTo(sentinel, { skip, raw = false, orEOF = false } = {}) {
5044
5050
  return {
5045
5051
  _tag: "scanTo",
5046
5052
  _meta: meta,
5047
- _def: { tag: "scanTo", sentinel, skip: explicitSkip, raw, orEOF },
5053
+ _def: {
5054
+ tag: "scanTo",
5055
+ sentinel,
5056
+ skip: explicitSkip,
5057
+ raw,
5058
+ orEOF,
5059
+ ...recoverAt === void 0 ? {} : { recoverAt },
5060
+ ...stopAt === void 0 ? {} : { stopAt }
5061
+ },
5048
5062
  parse(input, pos, ctx) {
5049
5063
  let cur = pos;
5050
5064
  const skip2 = resolveScanSkip(explicitSkip, raw, ctx);
@@ -5056,28 +5070,130 @@ function scanTo(sentinel, { skip, raw = false, orEOF = false } = {}) {
5056
5070
  pushCstLeaf(ctx, leaf2);
5057
5071
  }
5058
5072
  };
5059
- while (cur < input.length) {
5060
- const s = sentinel.parse(input, cur, probeCtx);
5061
- if (s.ok) {
5073
+ if (recoverAt === void 0 && stopAt === void 0) {
5074
+ while (cur < input.length) {
5075
+ const s = sentinel.parse(input, cur, probeCtx);
5076
+ if (s.ok) {
5077
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
5078
+ emit(cur);
5079
+ return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
5080
+ }
5081
+ let advanced = false;
5082
+ for (const skipper of skip2) {
5083
+ const r = skipper.parse(input, cur, probeCtx);
5084
+ if (r.ok && r.span.end > cur) {
5085
+ cur = r.span.end;
5086
+ advanced = true;
5087
+ break;
5088
+ }
5089
+ }
5090
+ if (!advanced) cur++;
5091
+ }
5092
+ if (orEOF) {
5062
5093
  if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
5063
5094
  emit(cur);
5064
5095
  return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
5065
5096
  }
5097
+ const sentDef2 = sentinel._def;
5098
+ const expected2 = sentDef2.tag === "literal" ? [JSON.stringify(sentDef2.value)] : ["sentinel"];
5099
+ return { ok: false, expected: expected2, span: { start: pos, end: cur } };
5100
+ }
5101
+ let recovery = -1;
5102
+ let firstSentinel = -1;
5103
+ let sentinelCount = 0;
5104
+ let recoveryErrorCount = -1;
5105
+ let sentinelErrorCount = -1;
5106
+ const succeed = (end) => {
5107
+ if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
5108
+ emit(end);
5109
+ return { ok: true, value: input.slice(pos, end), span: { start: pos, end } };
5110
+ };
5111
+ const recoveredEnd = () => {
5112
+ const acceptSentinel = firstSentinel >= 0 && (sentinelCount & 1) === 1;
5113
+ const errors = ctx._errors;
5114
+ if (errors !== void 0) {
5115
+ const keep = acceptSentinel ? sentinelErrorCount : recoveryErrorCount;
5116
+ if (keep >= 0 && errors.length > keep) errors.length = keep;
5117
+ }
5118
+ return acceptSentinel ? firstSentinel : recovery;
5119
+ };
5120
+ while (cur < input.length) {
5121
+ const sentinelProbeErrorCount = ctx._errors?.length ?? -1;
5122
+ const s = sentinel.parse(input, cur, probeCtx);
5123
+ const sentinelProbeErrors = ctx._errors;
5124
+ if (sentinelProbeErrors !== void 0 && sentinelProbeErrorCount >= 0 && sentinelProbeErrors.length > sentinelProbeErrorCount) {
5125
+ sentinelProbeErrors.length = sentinelProbeErrorCount;
5126
+ }
5127
+ if (s.ok) {
5128
+ if (recovery < 0) return succeed(cur);
5129
+ if (s.span.end <= cur) {
5130
+ throw new TypeError("scanTo recovery requires a sentinel that consumes input");
5131
+ }
5132
+ if (firstSentinel < 0) {
5133
+ firstSentinel = cur;
5134
+ sentinelErrorCount = sentinelProbeErrorCount;
5135
+ }
5136
+ sentinelCount++;
5137
+ cur = s.span.end;
5138
+ continue;
5139
+ }
5140
+ if (stopAt !== void 0) {
5141
+ const errorCount = ctx._errors?.length ?? -1;
5142
+ const stop = stopAt.parse(input, cur, probeCtx);
5143
+ const errors = ctx._errors;
5144
+ if (errors !== void 0 && errorCount >= 0 && errors.length > errorCount) {
5145
+ errors.length = errorCount;
5146
+ }
5147
+ if (stop.ok) {
5148
+ if (recovery < 0) {
5149
+ recovery = cur;
5150
+ recoveryErrorCount = errorCount;
5151
+ }
5152
+ return succeed(recoveredEnd());
5153
+ }
5154
+ }
5066
5155
  let advanced = false;
5067
5156
  for (const skipper of skip2) {
5157
+ const errorCount = ctx._errors?.length ?? -1;
5068
5158
  const r = skipper.parse(input, cur, probeCtx);
5069
5159
  if (r.ok && r.span.end > cur) {
5070
5160
  cur = r.span.end;
5071
5161
  advanced = true;
5072
5162
  break;
5073
5163
  }
5164
+ const errors = ctx._errors;
5165
+ if (errors !== void 0 && errorCount >= 0 && errors.length > errorCount) {
5166
+ errors.length = errorCount;
5167
+ }
5168
+ }
5169
+ if (advanced) continue;
5170
+ if (recoverAt !== void 0) {
5171
+ const errorCount = ctx._errors?.length ?? -1;
5172
+ const recover = recoverAt.parse(input, cur, probeCtx);
5173
+ const errors = ctx._errors;
5174
+ if (errors !== void 0 && errorCount >= 0 && errors.length > errorCount) {
5175
+ errors.length = errorCount;
5176
+ }
5177
+ if (recover.ok) {
5178
+ if (recover.span.end <= cur) {
5179
+ throw new TypeError("scanTo recoverAt must consume input");
5180
+ }
5181
+ if (recovery < 0) {
5182
+ recovery = cur;
5183
+ recoveryErrorCount = errorCount;
5184
+ }
5185
+ if (firstSentinel >= 0 && (sentinelCount & 1) === 1) {
5186
+ return succeed(recoveredEnd());
5187
+ }
5188
+ cur = recover.span.end;
5189
+ continue;
5190
+ }
5074
5191
  }
5075
- if (!advanced) cur++;
5192
+ cur++;
5076
5193
  }
5194
+ if (recovery >= 0) return succeed(recoveredEnd());
5077
5195
  if (orEOF) {
5078
- if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
5079
- emit(cur);
5080
- return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
5196
+ return succeed(cur);
5081
5197
  }
5082
5198
  const sentDef = sentinel._def;
5083
5199
  const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];