parseman 0.47.1 → 0.48.1
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/README.md +27 -21
- package/dist/analysis/diagnostics.js +2964 -347
- package/dist/analysis/diagnostics.js.map +3 -3
- package/dist/cli/index.js +2960 -343
- package/dist/cli/index.js.map +3 -3
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/expect.d.ts +1 -0
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/expected.d.ts +8 -0
- package/dist/combinators/expected.d.ts.map +1 -0
- package/dist/combinators/first-set.d.ts +8 -0
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/grammar.d.ts.map +1 -1
- package/dist/combinators/keywords.d.ts +4 -0
- package/dist/combinators/keywords.d.ts.map +1 -1
- package/dist/combinators/literal.d.ts.map +1 -1
- package/dist/combinators/not.d.ts.map +1 -1
- package/dist/combinators/peek.d.ts.map +1 -1
- package/dist/combinators/regex.d.ts.map +1 -1
- package/dist/combinators/repeat.d.ts.map +1 -1
- package/dist/combinators/sequence.d.ts.map +1 -1
- package/dist/combinators/trivia-skip.d.ts +16 -3
- package/dist/combinators/trivia-skip.d.ts.map +1 -1
- package/dist/compiler/direct-projection.d.ts +12 -0
- package/dist/compiler/direct-projection.d.ts.map +1 -0
- package/dist/compiler/token-alphabet.d.ts +845 -5
- package/dist/compiler/token-alphabet.d.ts.map +1 -1
- package/dist/compiler/token-capability.d.ts +3 -0
- package/dist/compiler/token-capability.d.ts.map +1 -0
- package/dist/compiler/token-capability.js +3192 -0
- package/dist/compiler/token-capability.js.map +6 -0
- package/dist/cst/trivia-charscan.d.ts +3 -0
- package/dist/cst/trivia-charscan.d.ts.map +1 -1
- package/dist/cst/trivia-css-scanner.d.ts +5 -0
- package/dist/cst/trivia-css-scanner.d.ts.map +1 -0
- package/dist/cst/trivia-kinds.d.ts.map +1 -1
- package/dist/index.js +2973 -343
- package/dist/index.js.map +3 -3
- package/dist/language-service/index.js +5 -1
- package/dist/language-service/index.js.map +1 -1
- package/dist/plugin/index.js +2982 -352
- package/dist/plugin/index.js.map +3 -3
- package/dist/spec/index.js +325 -47
- package/dist/spec/index.js.map +3 -3
- package/dist/table/assemble.d.ts.map +1 -1
- package/dist/table/child-slots.d.ts.map +1 -1
- package/dist/table/compile-rule-map.d.ts +3 -1
- package/dist/table/compile-rule-map.d.ts.map +1 -1
- package/dist/table/emit-assembly.d.ts +12 -13
- package/dist/table/emit-assembly.d.ts.map +1 -1
- package/dist/table/emit.d.ts.map +1 -1
- package/dist/table/encode.d.ts.map +1 -1
- package/dist/table/exec-baseline.d.ts.map +1 -1
- package/dist/table/exec.d.ts.map +1 -1
- package/dist/table/index.js +2937 -311
- package/dist/table/index.js.map +3 -3
- package/dist/table/lex-body.d.ts +9 -0
- package/dist/table/lex-body.d.ts.map +1 -0
- package/dist/table/lex-program.d.ts +25 -0
- package/dist/table/lex-program.d.ts.map +1 -0
- package/dist/table/ops.d.ts +47 -11
- package/dist/table/ops.d.ts.map +1 -1
- package/dist/table/program.d.ts +50 -2
- package/dist/table/program.d.ts.map +1 -1
- package/dist/table/scalar-terminal.d.ts +13 -0
- package/dist/table/scalar-terminal.d.ts.map +1 -0
- package/dist/table/site-labels.d.ts.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +11 -11
- package/src/combinators/choice.ts +10 -1
- package/src/combinators/expect.ts +1 -0
- package/src/combinators/expected.ts +17 -0
- package/src/combinators/first-set.ts +58 -5
- package/src/combinators/grammar.ts +8 -3
- package/src/combinators/keywords.ts +22 -6
- package/src/combinators/literal.ts +2 -1
- package/src/combinators/not.ts +5 -1
- package/src/combinators/peek.ts +5 -1
- package/src/combinators/regex.ts +5 -3
- package/src/combinators/repeat.ts +4 -10
- package/src/combinators/sequence.ts +17 -14
- package/src/combinators/trivia-skip.ts +46 -13
- package/src/compiler/direct-projection.ts +43 -0
- package/src/compiler/token-alphabet.ts +4316 -12
- package/src/compiler/token-capability.ts +6 -0
- package/src/cst/trivia-charscan.ts +34 -0
- package/src/cst/trivia-css-scanner.ts +142 -0
- package/src/cst/trivia-kinds.ts +3 -1
- package/src/plugin/index.ts +4 -4
- package/src/table/assemble.ts +1253 -240
- package/src/table/child-slots.ts +2 -1
- package/src/table/compile-rule-map.ts +21 -3
- package/src/table/emit-assembly.ts +335 -87
- package/src/table/emit.ts +16 -2
- package/src/table/encode.ts +248 -60
- package/src/table/exec-baseline.ts +3 -7
- package/src/table/exec.ts +134 -25
- package/src/table/lex-body.ts +30 -0
- package/src/table/lex-program.ts +431 -0
- package/src/table/ops.ts +49 -11
- package/src/table/program.ts +46 -2
- package/src/table/scalar-terminal.ts +51 -0
- package/src/table/site-labels.ts +11 -1
- package/src/table/stamp.ts +1 -1
- package/src/types.ts +1 -1
- package/src/version.ts +1 -1
- package/dist/analysis/diagnostics.cjs +0 -13824
- package/dist/analysis/diagnostics.cjs.map +0 -6
- package/dist/cli/index.cjs +0 -14925
- package/dist/cli/index.cjs.map +0 -6
- package/dist/index.cjs +0 -16391
- package/dist/index.cjs.map +0 -6
- package/dist/language-service/index.cjs +0 -1304
- package/dist/language-service/index.cjs.map +0 -6
- package/dist/oracle/index.cjs +0 -254
- package/dist/oracle/index.cjs.map +0 -6
- package/dist/plugin/index.cjs +0 -16097
- package/dist/plugin/index.cjs.map +0 -6
- package/dist/run/index.cjs +0 -577
- package/dist/run/index.cjs.map +0 -6
- package/dist/spec/index.cjs +0 -6236
- package/dist/spec/index.cjs.map +0 -6
- package/dist/table/index.cjs +0 -11463
- package/dist/table/index.cjs.map +0 -6
|
@@ -0,0 +1,3192 @@
|
|
|
1
|
+
// src/combinators/first-set.ts
|
|
2
|
+
function classifyFinalChoice(arms, resolve) {
|
|
3
|
+
const firstSets = [];
|
|
4
|
+
const nullable = [];
|
|
5
|
+
let exclusive = true;
|
|
6
|
+
for (const arm of arms) {
|
|
7
|
+
const empty2 = matchesEmpty(arm, /* @__PURE__ */ new Set(), resolve);
|
|
8
|
+
nullable.push(empty2);
|
|
9
|
+
firstSets.push(empty2 ? { kind: "any" } : firstSetOf(arm, /* @__PURE__ */ new Set(), resolve));
|
|
10
|
+
if (empty2) exclusive = false;
|
|
11
|
+
}
|
|
12
|
+
if (exclusive) {
|
|
13
|
+
const ascii = new Uint8Array(128);
|
|
14
|
+
let highOwners = 0;
|
|
15
|
+
for (let arm = 0; arm < firstSets.length && exclusive; arm++) {
|
|
16
|
+
const first = firstSets[arm];
|
|
17
|
+
if (first.kind !== "ranges" || first.ranges.length === 0) {
|
|
18
|
+
exclusive = false;
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
let ownsHigh = false;
|
|
22
|
+
for (const range of first.ranges) {
|
|
23
|
+
if (range.hi >= 128) ownsHigh = true;
|
|
24
|
+
for (let code = Math.max(0, range.lo); code <= Math.min(127, range.hi); code++) {
|
|
25
|
+
if (ascii[code] !== 0) {
|
|
26
|
+
exclusive = false;
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
ascii[code] = 1;
|
|
30
|
+
}
|
|
31
|
+
if (!exclusive) break;
|
|
32
|
+
}
|
|
33
|
+
if (ownsHigh && ++highOwners > 1) exclusive = false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { exclusive, firstSets, nullable };
|
|
37
|
+
}
|
|
38
|
+
function resolveNamedRef(p, resolve) {
|
|
39
|
+
if (resolve === void 0) return void 0;
|
|
40
|
+
const name = p._ruleName;
|
|
41
|
+
return name === void 0 ? void 0 : resolve(name);
|
|
42
|
+
}
|
|
43
|
+
function union(a, b) {
|
|
44
|
+
if (a.kind === "any" || b.kind === "any") return { kind: "any" };
|
|
45
|
+
if (a.kind === "empty") return b;
|
|
46
|
+
if (b.kind === "empty") return a;
|
|
47
|
+
return { kind: "ranges", ranges: mergeRanges([...a.ranges, ...b.ranges]) };
|
|
48
|
+
}
|
|
49
|
+
function intersects(a, b) {
|
|
50
|
+
if (a.kind === "any" || b.kind === "any") return true;
|
|
51
|
+
if (a.kind === "empty" || b.kind === "empty") return false;
|
|
52
|
+
for (const ra of a.ranges) {
|
|
53
|
+
for (const rb of b.ranges) {
|
|
54
|
+
if (ra.lo <= rb.hi && rb.lo <= ra.hi) return true;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
function any() {
|
|
60
|
+
return { kind: "any" };
|
|
61
|
+
}
|
|
62
|
+
function empty() {
|
|
63
|
+
return { kind: "empty" };
|
|
64
|
+
}
|
|
65
|
+
function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
66
|
+
if (seen.has(p)) return true;
|
|
67
|
+
seen.add(p);
|
|
68
|
+
try {
|
|
69
|
+
return matchesEmptyBody(p, seen, resolve);
|
|
70
|
+
} finally {
|
|
71
|
+
seen.delete(p);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function matchesEmptyBody(p, seen, resolve) {
|
|
75
|
+
const me = (c) => matchesEmpty(c, seen, resolve);
|
|
76
|
+
const d = p._def;
|
|
77
|
+
switch (d.tag) {
|
|
78
|
+
case "literal":
|
|
79
|
+
return d.value.length === 0;
|
|
80
|
+
case "keywords":
|
|
81
|
+
return false;
|
|
82
|
+
// The routed token itself is the selector's match, never empty; a fallback can be.
|
|
83
|
+
case "routed":
|
|
84
|
+
return d.fallback === void 0 ? false : me(d.fallback);
|
|
85
|
+
case "regex":
|
|
86
|
+
try {
|
|
87
|
+
const m = new RegExp(d.source).exec("");
|
|
88
|
+
return m != null && m[0] === "";
|
|
89
|
+
} catch {
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
92
|
+
case "many":
|
|
93
|
+
case "optional":
|
|
94
|
+
case "not":
|
|
95
|
+
case "peek":
|
|
96
|
+
return true;
|
|
97
|
+
// zero repetitions / absent / lookahead
|
|
98
|
+
// Default `sepBy` is `(item (sep item)*)?` — it MATCHES THE EMPTY STRING.
|
|
99
|
+
// Any `min >= 1` requires that many ITEMS, so it is nullable only when the
|
|
100
|
+
// item is. (Keying this off `min === 1` reported every `{ min: 2 }` list as
|
|
101
|
+
// nullable — safe, but wrong, and it put a bogus `nullable-prefix` note on
|
|
102
|
+
// the gating diagnostic for a list that can never match empty.)
|
|
103
|
+
case "sepBy":
|
|
104
|
+
return d.min >= 1 ? me(d.parser) : true;
|
|
105
|
+
case "oneOrMore":
|
|
106
|
+
return me(d.parser);
|
|
107
|
+
case "sequence":
|
|
108
|
+
return d.parsers.every(me);
|
|
109
|
+
case "choice":
|
|
110
|
+
return d.parsers.some(me);
|
|
111
|
+
case "dispatch":
|
|
112
|
+
return me(d.selector);
|
|
113
|
+
case "transform":
|
|
114
|
+
case "label":
|
|
115
|
+
case "trivia":
|
|
116
|
+
case "token":
|
|
117
|
+
case "leaf":
|
|
118
|
+
case "expect":
|
|
119
|
+
case "withCtx":
|
|
120
|
+
case "node":
|
|
121
|
+
case "grammar":
|
|
122
|
+
case "recover":
|
|
123
|
+
return me(d.parser);
|
|
124
|
+
case "lazy":
|
|
125
|
+
try {
|
|
126
|
+
return me(d.thunk());
|
|
127
|
+
} catch {
|
|
128
|
+
const t = resolveNamedRef(p, resolve);
|
|
129
|
+
return t ? me(t) : true;
|
|
130
|
+
}
|
|
131
|
+
default:
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function isZeroWidthAssertion(p) {
|
|
136
|
+
const tag = p._def.tag;
|
|
137
|
+
return tag === "not" || tag === "adjacency";
|
|
138
|
+
}
|
|
139
|
+
function isPositiveLookahead(p) {
|
|
140
|
+
return p._def.tag === "peek";
|
|
141
|
+
}
|
|
142
|
+
function narrowBy(acc, constraint) {
|
|
143
|
+
if (constraint.kind === "any") return acc;
|
|
144
|
+
if (acc === null) return constraint;
|
|
145
|
+
if (acc.kind === "any") return constraint;
|
|
146
|
+
if (acc.kind === "empty" || constraint.kind === "empty") return { kind: "empty" };
|
|
147
|
+
const ranges = [];
|
|
148
|
+
for (const a of acc.ranges) for (const b of constraint.ranges) {
|
|
149
|
+
const lo = Math.max(a.lo, b.lo);
|
|
150
|
+
const hi = Math.min(a.hi, b.hi);
|
|
151
|
+
if (lo <= hi) ranges.push({ lo, hi });
|
|
152
|
+
}
|
|
153
|
+
return ranges.length === 0 ? { kind: "empty" } : { kind: "ranges", ranges };
|
|
154
|
+
}
|
|
155
|
+
function applyAssertion(fs, assertion) {
|
|
156
|
+
if (assertion === null) return fs;
|
|
157
|
+
if (fs.kind === "empty") return assertion;
|
|
158
|
+
return narrowBy(fs, assertion) ?? fs;
|
|
159
|
+
}
|
|
160
|
+
function firstSetOf(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
161
|
+
if (seen.has(p)) return any();
|
|
162
|
+
seen.add(p);
|
|
163
|
+
try {
|
|
164
|
+
return firstSetBody(p, seen, resolve);
|
|
165
|
+
} finally {
|
|
166
|
+
seen.delete(p);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function firstSetBody(p, seen, resolve) {
|
|
170
|
+
const fs = (c) => firstSetOf(c, seen, resolve);
|
|
171
|
+
const empties = (c) => matchesEmpty(c, /* @__PURE__ */ new Set(), resolve);
|
|
172
|
+
const d = p._def;
|
|
173
|
+
switch (d.tag) {
|
|
174
|
+
case "literal":
|
|
175
|
+
case "regex":
|
|
176
|
+
case "keywords":
|
|
177
|
+
return p._meta.firstSet;
|
|
178
|
+
// terminals: no refs, cached set is exact
|
|
179
|
+
case "dispatch":
|
|
180
|
+
return fs(d.selector);
|
|
181
|
+
case "lazy":
|
|
182
|
+
try {
|
|
183
|
+
return fs(d.thunk());
|
|
184
|
+
} catch {
|
|
185
|
+
const t = resolveNamedRef(p, resolve);
|
|
186
|
+
return t ? fs(t) : any();
|
|
187
|
+
}
|
|
188
|
+
case "choice": {
|
|
189
|
+
let out = empty();
|
|
190
|
+
for (const arm of d.parsers) out = union(out, fs(arm));
|
|
191
|
+
return out;
|
|
192
|
+
}
|
|
193
|
+
case "sequence": {
|
|
194
|
+
let out = empty();
|
|
195
|
+
let assertion = null;
|
|
196
|
+
for (const term of d.parsers) {
|
|
197
|
+
if (isPositiveLookahead(term)) {
|
|
198
|
+
assertion = narrowBy(assertion, fs(term));
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
if (!isZeroWidthAssertion(term)) out = union(out, fs(term));
|
|
202
|
+
if (!empties(term)) return applyAssertion(out, assertion);
|
|
203
|
+
}
|
|
204
|
+
return applyAssertion(out, assertion);
|
|
205
|
+
}
|
|
206
|
+
case "peek": {
|
|
207
|
+
const inner = d.parser;
|
|
208
|
+
return empties(inner) ? any() : fs(inner);
|
|
209
|
+
}
|
|
210
|
+
case "oneOrMore":
|
|
211
|
+
case "many":
|
|
212
|
+
case "optional":
|
|
213
|
+
case "transform":
|
|
214
|
+
case "label":
|
|
215
|
+
case "trivia":
|
|
216
|
+
case "token":
|
|
217
|
+
case "leaf":
|
|
218
|
+
case "node":
|
|
219
|
+
case "grammar":
|
|
220
|
+
case "expect":
|
|
221
|
+
return fs(d.parser);
|
|
222
|
+
case "sepBy":
|
|
223
|
+
return fs(d.parser);
|
|
224
|
+
// both min 0 and min 1 start with the item
|
|
225
|
+
default:
|
|
226
|
+
return p._meta.firstSet;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
function mergeRanges(ranges) {
|
|
230
|
+
if (ranges.length === 0) return [];
|
|
231
|
+
const sorted = [...ranges].sort((a, b) => a.lo - b.lo);
|
|
232
|
+
const out = [{ lo: sorted[0].lo, hi: sorted[0].hi }];
|
|
233
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
234
|
+
const top = out[out.length - 1];
|
|
235
|
+
const cur = sorted[i];
|
|
236
|
+
if (cur.lo <= top.hi + 1) {
|
|
237
|
+
if (cur.hi > top.hi) top.hi = cur.hi;
|
|
238
|
+
} else {
|
|
239
|
+
out.push({ lo: cur.lo, hi: cur.hi });
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
return out;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// src/regex/classes.ts
|
|
246
|
+
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
247
|
+
|
|
248
|
+
// src/combinators/dispatch.ts
|
|
249
|
+
function parserUsesRouted(parser, seen = /* @__PURE__ */ new Set()) {
|
|
250
|
+
if (seen.has(parser)) return false;
|
|
251
|
+
seen.add(parser);
|
|
252
|
+
const def = parser._def;
|
|
253
|
+
switch (def.tag) {
|
|
254
|
+
case "routed":
|
|
255
|
+
return true;
|
|
256
|
+
case "sequence":
|
|
257
|
+
case "choice":
|
|
258
|
+
return def.parsers.some((entry) => parserUsesRouted(entry, seen));
|
|
259
|
+
case "dispatch":
|
|
260
|
+
return false;
|
|
261
|
+
case "sepBy":
|
|
262
|
+
return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.separator, seen);
|
|
263
|
+
case "grammar":
|
|
264
|
+
return parserUsesRouted(def.parser, seen) || (def.triviaParser ? parserUsesRouted(def.triviaParser, seen) : false);
|
|
265
|
+
case "scanTo":
|
|
266
|
+
return parserUsesRouted(def.sentinel, seen) || def.skip.some((entry) => parserUsesRouted(entry, seen));
|
|
267
|
+
case "recover":
|
|
268
|
+
return parserUsesRouted(def.parser, seen) || parserUsesRouted(def.sentinel, seen);
|
|
269
|
+
case "lazy":
|
|
270
|
+
try {
|
|
271
|
+
return parserUsesRouted(def.thunk(), seen);
|
|
272
|
+
} catch {
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
case "many":
|
|
276
|
+
case "oneOrMore":
|
|
277
|
+
case "optional":
|
|
278
|
+
case "attempt":
|
|
279
|
+
case "transform":
|
|
280
|
+
case "trivia":
|
|
281
|
+
case "token":
|
|
282
|
+
case "leaf":
|
|
283
|
+
case "label":
|
|
284
|
+
case "field":
|
|
285
|
+
case "not":
|
|
286
|
+
case "peek":
|
|
287
|
+
case "node":
|
|
288
|
+
case "withCtx":
|
|
289
|
+
case "expect":
|
|
290
|
+
return parserUsesRouted(def.parser, seen);
|
|
291
|
+
default:
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
function branchUsesRouted(branch) {
|
|
296
|
+
return branch.usesRouted === true || parserUsesRouted(branch.parser);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// src/combinators/expected.ts
|
|
300
|
+
function directTerminalFailureExpected(def) {
|
|
301
|
+
switch (def.tag) {
|
|
302
|
+
case "literal":
|
|
303
|
+
return [JSON.stringify(def.value)];
|
|
304
|
+
case "regex":
|
|
305
|
+
return [`/${def.source}/`];
|
|
306
|
+
case "keywords":
|
|
307
|
+
return ["keyword"];
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
function assertionFailureExpected(positive, childTag) {
|
|
311
|
+
return [`${positive ? "peek" : "not"}(${childTag})`];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/combinators/expect.ts
|
|
315
|
+
function deriveExpected(c) {
|
|
316
|
+
return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
|
|
317
|
+
}
|
|
318
|
+
function derive(c, seen) {
|
|
319
|
+
const deriveExpected2 = (p) => derive(p, seen);
|
|
320
|
+
const def = c._def;
|
|
321
|
+
switch (def.tag) {
|
|
322
|
+
case "literal":
|
|
323
|
+
return [JSON.stringify(def.value)];
|
|
324
|
+
case "regex":
|
|
325
|
+
return [`/${def.source}/`];
|
|
326
|
+
case "keywords":
|
|
327
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
328
|
+
case "label":
|
|
329
|
+
return [def.label];
|
|
330
|
+
case "choice":
|
|
331
|
+
return def.parsers.flatMap(deriveExpected2);
|
|
332
|
+
case "dispatch":
|
|
333
|
+
return deriveExpected2(def.selector);
|
|
334
|
+
// Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
|
|
335
|
+
// `optional(…)`/`many(…)` can match nothing, so the term after it is equally
|
|
336
|
+
// able to fail first — deriving from term 0 alone named a token the parse
|
|
337
|
+
// never actually required. A leading `not(…)` is zero-width and contributes
|
|
338
|
+
// nothing (its own expectation is about what must NOT be here), but it is
|
|
339
|
+
// nullable, so keep scanning past it. Stop at the first term that must match.
|
|
340
|
+
case "sequence": {
|
|
341
|
+
const out = [];
|
|
342
|
+
for (const term of def.parsers) {
|
|
343
|
+
if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
|
|
344
|
+
if (!matchesEmpty(term)) break;
|
|
345
|
+
}
|
|
346
|
+
return out;
|
|
347
|
+
}
|
|
348
|
+
case "attempt":
|
|
349
|
+
return deriveExpected2(def.parser);
|
|
350
|
+
// Delegating wrappers whose first-token failure is their inner parser's — must
|
|
351
|
+
// pass through so a start-failure (and the first-set-miss fast-path in attempt/
|
|
352
|
+
// node, which reads this) names the real expected token, not the wrapper tag.
|
|
353
|
+
case "field":
|
|
354
|
+
case "withCtx":
|
|
355
|
+
case "recover":
|
|
356
|
+
return deriveExpected2(def.parser);
|
|
357
|
+
case "expect":
|
|
358
|
+
return def.expected;
|
|
359
|
+
case "node":
|
|
360
|
+
case "grammar":
|
|
361
|
+
case "trivia":
|
|
362
|
+
case "token":
|
|
363
|
+
case "leaf":
|
|
364
|
+
case "optional":
|
|
365
|
+
case "many":
|
|
366
|
+
case "oneOrMore":
|
|
367
|
+
case "transform":
|
|
368
|
+
case "not":
|
|
369
|
+
case "peek":
|
|
370
|
+
return deriveExpected2(def.parser);
|
|
371
|
+
// A bare routed() can only fail as "there is no routed token here". With a
|
|
372
|
+
// fallback, THAT is the branch that can fail, so its expectations are the useful
|
|
373
|
+
// ones — the routed path either succeeds or is not taken.
|
|
374
|
+
case "routed":
|
|
375
|
+
return def.fallback === void 0 ? ["routed()"] : deriveExpected2(def.fallback);
|
|
376
|
+
// A bare adjacency assertion names the JOIN it requires. Inside a sequence it is
|
|
377
|
+
// skipped entirely (isZeroWidthAssertion, above), which is the normal path.
|
|
378
|
+
case "adjacency":
|
|
379
|
+
return [def.polarity];
|
|
380
|
+
case "lazy": {
|
|
381
|
+
const name = c._ruleName;
|
|
382
|
+
if (seen.has(c)) return name ? [name] : [];
|
|
383
|
+
seen.add(c);
|
|
384
|
+
try {
|
|
385
|
+
return deriveExpected2(def.thunk());
|
|
386
|
+
} catch {
|
|
387
|
+
return name ? [name] : [];
|
|
388
|
+
} finally {
|
|
389
|
+
seen.delete(c);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
default:
|
|
393
|
+
return [];
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// src/combinators/keywords.ts
|
|
398
|
+
function escapeRe(s) {
|
|
399
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
400
|
+
}
|
|
401
|
+
function keywordsRegExp(words, boundary, caseInsensitive) {
|
|
402
|
+
const alt = words.map(escapeRe).join("|");
|
|
403
|
+
const boundarySource = boundary ? `(?![${boundary}])` : "";
|
|
404
|
+
return new RegExp(`(?:${alt})${boundarySource}`, caseInsensitive ? "iy" : "uy");
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// src/compiler/token-alphabet.ts
|
|
408
|
+
function optionalSuffixLexBody(ir) {
|
|
409
|
+
if (ir.kind !== "sequence" || ir.parts.length !== 2) return void 0;
|
|
410
|
+
const [base, suffix] = ir.parts;
|
|
411
|
+
if (base?.kind !== "regex" || suffix?.kind !== "repeat" || suffix.min !== 0 || suffix.max !== 1 || !suffix.greedy || suffix.mode !== "possessive" || suffix.body.kind !== "literal" || suffix.body.caseInsensitive || suffix.body.value.length !== 1) return void 0;
|
|
412
|
+
return {
|
|
413
|
+
kind: "regex-optional-code-unit",
|
|
414
|
+
source: base.source,
|
|
415
|
+
flags: base.flags,
|
|
416
|
+
suffix: suffix.body.value
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
function selectOptionalSuffixLexBody(ir) {
|
|
420
|
+
const body = optionalSuffixLexBody(ir);
|
|
421
|
+
const character = { strategy: "character", estimatedOps: 5 };
|
|
422
|
+
if (body === void 0) return character;
|
|
423
|
+
const token = { strategy: "token", estimatedOps: 2, body };
|
|
424
|
+
return token.estimatedOps < character.estimatedOps ? token : character;
|
|
425
|
+
}
|
|
426
|
+
function directTokenBodyParser(parser, resolve) {
|
|
427
|
+
const outer = parser._def;
|
|
428
|
+
if (outer.tag !== "token") return void 0;
|
|
429
|
+
let body = outer.parser;
|
|
430
|
+
const seen = /* @__PURE__ */ new Set();
|
|
431
|
+
while (!seen.has(body)) {
|
|
432
|
+
seen.add(body);
|
|
433
|
+
const wrapper = body._def;
|
|
434
|
+
if (wrapper.tag === "grammar") {
|
|
435
|
+
if (wrapper.clearTrivia !== true || wrapper.triviaParser !== void 0 || wrapper.captureTrivia === true || wrapper.rootCapture === "opaque" || wrapper.constructionTrackLines !== "inherit" || wrapper.constructionCaptureTriviaKinds !== void 0) return void 0;
|
|
436
|
+
body = wrapper.parser;
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
if (wrapper.tag === "lazy") {
|
|
440
|
+
const target = resolvedLazyTarget(body, resolve);
|
|
441
|
+
if (target === void 0) return void 0;
|
|
442
|
+
body = target;
|
|
443
|
+
continue;
|
|
444
|
+
}
|
|
445
|
+
return body;
|
|
446
|
+
}
|
|
447
|
+
return void 0;
|
|
448
|
+
}
|
|
449
|
+
function directOptionalSuffixTokenBody(parser, resolve) {
|
|
450
|
+
const inner = directTokenBodyParser(parser, resolve);
|
|
451
|
+
if (inner === void 0) return void 0;
|
|
452
|
+
const sequence = inner._def;
|
|
453
|
+
if (sequence.tag !== "sequence" || sequence.parsers.length !== 2) return void 0;
|
|
454
|
+
let baseParser = sequence.parsers[0];
|
|
455
|
+
const seenBase = /* @__PURE__ */ new Set();
|
|
456
|
+
while (baseParser !== void 0 && baseParser._def.tag === "lazy" && !seenBase.has(baseParser)) {
|
|
457
|
+
seenBase.add(baseParser);
|
|
458
|
+
baseParser = resolvedLazyTarget(baseParser, resolve);
|
|
459
|
+
}
|
|
460
|
+
const base = baseParser?._def;
|
|
461
|
+
const optional = sequence.parsers[1]?._def;
|
|
462
|
+
if (base?.tag !== "regex" || optional?.tag !== "optional") return void 0;
|
|
463
|
+
const suffix = optional.parser._def;
|
|
464
|
+
if (suffix.tag !== "literal" || suffix.caseInsensitive || suffix.value.length !== 1) return void 0;
|
|
465
|
+
const selected = selectOptionalSuffixLexBody({
|
|
466
|
+
kind: "sequence",
|
|
467
|
+
parts: [
|
|
468
|
+
{ kind: "regex", source: base.source, flags: base.flags },
|
|
469
|
+
{
|
|
470
|
+
kind: "repeat",
|
|
471
|
+
body: { kind: "literal", value: suffix.value, caseInsensitive: false },
|
|
472
|
+
min: 0,
|
|
473
|
+
max: 1,
|
|
474
|
+
greedy: true,
|
|
475
|
+
mode: "possessive"
|
|
476
|
+
}
|
|
477
|
+
]
|
|
478
|
+
});
|
|
479
|
+
return selected.strategy === "token" ? {
|
|
480
|
+
...selected.body,
|
|
481
|
+
baseCanMatchNewline: baseParser._meta.canMatchNewline,
|
|
482
|
+
suffixCanMatchNewline: optional.parser._meta.canMatchNewline,
|
|
483
|
+
expected: directTerminalFailureExpected(base)
|
|
484
|
+
} : void 0;
|
|
485
|
+
}
|
|
486
|
+
function directTerminalTokenBody(parser, resolve) {
|
|
487
|
+
const outer = parser._def;
|
|
488
|
+
if (outer.tag !== "token") return void 0;
|
|
489
|
+
const body = directTokenBodyParser(parser, resolve);
|
|
490
|
+
if (body === void 0) return void 0;
|
|
491
|
+
const def = body._def;
|
|
492
|
+
if (def.tag === "regex") return {
|
|
493
|
+
kind: "regex-terminal",
|
|
494
|
+
source: def.source,
|
|
495
|
+
flags: def.flags,
|
|
496
|
+
canMatchNewline: body._meta.canMatchNewline,
|
|
497
|
+
expected: directTerminalFailureExpected(def)
|
|
498
|
+
};
|
|
499
|
+
if (def.tag !== "keywords") return void 0;
|
|
500
|
+
const re = keywordsRegExp(def.words, def.boundary, def.caseInsensitive);
|
|
501
|
+
return {
|
|
502
|
+
kind: "regex-terminal",
|
|
503
|
+
source: re.source,
|
|
504
|
+
flags: re.flags,
|
|
505
|
+
canMatchNewline: body._meta.canMatchNewline,
|
|
506
|
+
expected: directTerminalFailureExpected(def)
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
function directTerminalParser(parser, resolve) {
|
|
510
|
+
const seen = /* @__PURE__ */ new Set();
|
|
511
|
+
while (!seen.has(parser)) {
|
|
512
|
+
seen.add(parser);
|
|
513
|
+
const def = parser._def;
|
|
514
|
+
if (def.tag === "lazy") {
|
|
515
|
+
const target = resolvedLazyTarget(parser, resolve);
|
|
516
|
+
if (target === void 0) return void 0;
|
|
517
|
+
parser = target;
|
|
518
|
+
continue;
|
|
519
|
+
}
|
|
520
|
+
if (def.tag === "token") {
|
|
521
|
+
parser = def.parser;
|
|
522
|
+
continue;
|
|
523
|
+
}
|
|
524
|
+
if (def.tag === "grammar") return void 0;
|
|
525
|
+
return parser;
|
|
526
|
+
}
|
|
527
|
+
return void 0;
|
|
528
|
+
}
|
|
529
|
+
function directTerminalLexBody(parser, resolve) {
|
|
530
|
+
const terminal = directTerminalParser(parser, resolve);
|
|
531
|
+
if (terminal === void 0) return void 0;
|
|
532
|
+
const def = terminal._def;
|
|
533
|
+
if (def.tag === "literal") {
|
|
534
|
+
if (def.caseInsensitive) return void 0;
|
|
535
|
+
const source = def.value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
536
|
+
return {
|
|
537
|
+
kind: "regex-terminal",
|
|
538
|
+
source,
|
|
539
|
+
flags: "",
|
|
540
|
+
canMatchNewline: terminal._meta.canMatchNewline,
|
|
541
|
+
expected: directTerminalFailureExpected(def)
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
if (def.tag === "regex") return {
|
|
545
|
+
kind: "regex-terminal",
|
|
546
|
+
source: def.source,
|
|
547
|
+
flags: def.flags,
|
|
548
|
+
canMatchNewline: terminal._meta.canMatchNewline,
|
|
549
|
+
expected: directTerminalFailureExpected(def)
|
|
550
|
+
};
|
|
551
|
+
if (def.tag !== "keywords") return void 0;
|
|
552
|
+
const re = keywordsRegExp(def.words, def.boundary, def.caseInsensitive);
|
|
553
|
+
return {
|
|
554
|
+
kind: "regex-terminal",
|
|
555
|
+
source: re.source,
|
|
556
|
+
flags: re.flags,
|
|
557
|
+
canMatchNewline: terminal._meta.canMatchNewline,
|
|
558
|
+
expected: directTerminalFailureExpected(def)
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
function directOrdered4TokenBody(parser, resolve) {
|
|
562
|
+
const body = directTokenBodyParser(parser, resolve);
|
|
563
|
+
return body === void 0 ? void 0 : directOrdered4Body(body, resolve);
|
|
564
|
+
}
|
|
565
|
+
function directOrdered4Body(body, resolve) {
|
|
566
|
+
if (body === void 0) return void 0;
|
|
567
|
+
const choice = body._def;
|
|
568
|
+
if (choice.tag !== "choice" || choice.parsers.length !== 4 || choice.strategy.tag !== "firstMatch" || choice.gates.some((gate) => gate !== null) || choice.autoNot.some((check) => check !== null)) return void 0;
|
|
569
|
+
const arms = [];
|
|
570
|
+
let common;
|
|
571
|
+
for (const arm of choice.parsers) {
|
|
572
|
+
const selected = directTerminalLexBody(arm, resolve);
|
|
573
|
+
if (selected === void 0) return void 0;
|
|
574
|
+
if (selected.canMatchNewline) return void 0;
|
|
575
|
+
const terminal = directTerminalParser(arm, resolve);
|
|
576
|
+
const first = firstSetOf(terminal, /* @__PURE__ */ new Set(), resolve);
|
|
577
|
+
if (first.kind !== "ranges" || first.ranges.length === 0) return void 0;
|
|
578
|
+
if (common === void 0) common = first;
|
|
579
|
+
else if (JSON.stringify(common) !== JSON.stringify(first)) return void 0;
|
|
580
|
+
arms.push(selected);
|
|
581
|
+
}
|
|
582
|
+
return {
|
|
583
|
+
kind: "ordered4-terminals",
|
|
584
|
+
commonFirstSet: common,
|
|
585
|
+
commonMissExpected: deriveExpected(body),
|
|
586
|
+
expected: arms.flatMap((arm) => arm.expected),
|
|
587
|
+
arms
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
function directNot2TokenBody(parser, resolve) {
|
|
591
|
+
const body = directTokenBodyParser(parser, resolve);
|
|
592
|
+
const sequence = body?._def;
|
|
593
|
+
if (sequence?.tag !== "sequence" || sequence.parsers.length !== 3) return void 0;
|
|
594
|
+
const [guard0Parser, guard1Parser, terminalParser] = sequence.parsers;
|
|
595
|
+
const guard0Def = guard0Parser?._def;
|
|
596
|
+
const guard1Def = guard1Parser?._def;
|
|
597
|
+
if (guard0Def?.tag !== "not" || guard1Def?.tag !== "not") return void 0;
|
|
598
|
+
const ordered = directTokenBodyParser(guard0Def.parser, resolve) ?? directTerminalParser(guard0Def.parser, resolve);
|
|
599
|
+
const guard0Body = ordered === void 0 ? void 0 : directOrdered4Body(ordered, resolve);
|
|
600
|
+
const guard1 = directTerminalLexBody(guard1Def.parser, resolve);
|
|
601
|
+
const terminal = terminalParser === void 0 ? void 0 : directTerminalLexBody(terminalParser, resolve);
|
|
602
|
+
if (guard0Body === void 0 || guard1 === void 0 || terminal === void 0 || guard1.canMatchNewline || terminal.canMatchNewline) return void 0;
|
|
603
|
+
return {
|
|
604
|
+
kind: "not2-ordered4-terminal",
|
|
605
|
+
guard0Expected: assertionFailureExpected(false, guard0Def.parser._tag),
|
|
606
|
+
guard1Expected: assertionFailureExpected(false, guard1Def.parser._tag),
|
|
607
|
+
terminalExpected: terminal.expected,
|
|
608
|
+
guard0: guard0Body.arms,
|
|
609
|
+
guard1,
|
|
610
|
+
terminal
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
function directFixedLexNode(parser, resolve, active, pureOnly = false) {
|
|
614
|
+
let current = parser;
|
|
615
|
+
const wrappers = /* @__PURE__ */ new Set();
|
|
616
|
+
while (!wrappers.has(current)) {
|
|
617
|
+
wrappers.add(current);
|
|
618
|
+
const def = current._def;
|
|
619
|
+
if (def.tag === "lazy") {
|
|
620
|
+
const target = resolvedLazyTarget(current, resolve);
|
|
621
|
+
if (target === void 0) return void 0;
|
|
622
|
+
current = target;
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
if (def.tag === "token") {
|
|
626
|
+
current = def.parser;
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
break;
|
|
630
|
+
}
|
|
631
|
+
if (wrappers.has(current) && current !== parser && current._def.tag === "lazy") return void 0;
|
|
632
|
+
if (active.has(current)) return void 0;
|
|
633
|
+
active.add(current);
|
|
634
|
+
try {
|
|
635
|
+
const terminal = directTerminalLexBody(current, resolve);
|
|
636
|
+
if (terminal !== void 0) return { kind: "terminal", terminal };
|
|
637
|
+
const def = current._def;
|
|
638
|
+
if (def.tag === "grammar") {
|
|
639
|
+
if (!pureOnly || def.parser._def.tag !== "token" && (def.clearTrivia !== true || def.triviaParser !== void 0 || def.captureTrivia === true || def.rootCapture === "opaque")) return void 0;
|
|
640
|
+
return directFixedLexNode(def.parser, resolve, active, true);
|
|
641
|
+
}
|
|
642
|
+
if (def.tag === "sequence") {
|
|
643
|
+
if (def.parsers.length < 2 || def.parsers.length > 5) return void 0;
|
|
644
|
+
const parts = def.parsers.map((part) => directFixedLexNode(part, resolve, active, pureOnly));
|
|
645
|
+
if (parts.some((part) => part === void 0)) return void 0;
|
|
646
|
+
return { kind: "sequence", parts };
|
|
647
|
+
}
|
|
648
|
+
if (def.tag === "choice") {
|
|
649
|
+
if (def.parsers.length !== 2 && def.parsers.length !== 4 && def.parsers.length !== 8 || def.strategy.tag !== "firstMatch" || def.gates.some((gate) => gate !== null) || def.autoNot.some((check) => check !== null)) return void 0;
|
|
650
|
+
const arms = def.parsers.map((arm) => directFixedLexNode(arm, resolve, active, pureOnly));
|
|
651
|
+
if (arms.some((arm) => arm === void 0)) return void 0;
|
|
652
|
+
const final = classifyFinalChoice(def.parsers, resolve);
|
|
653
|
+
return {
|
|
654
|
+
kind: "choice",
|
|
655
|
+
arms,
|
|
656
|
+
firstSets: final.firstSets,
|
|
657
|
+
armExpected: def.parsers.map(deriveExpected),
|
|
658
|
+
expected: def.parsers.flatMap(deriveExpected)
|
|
659
|
+
};
|
|
660
|
+
}
|
|
661
|
+
if (def.tag === "not") {
|
|
662
|
+
const body = directFixedLexNode(def.parser, resolve, active, true);
|
|
663
|
+
return body === void 0 ? void 0 : {
|
|
664
|
+
kind: "not",
|
|
665
|
+
body,
|
|
666
|
+
expected: assertionFailureExpected(false, def.parser._tag)
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
if (def.tag === "optional") {
|
|
670
|
+
const body = directFixedLexNode(def.parser, resolve, active, pureOnly);
|
|
671
|
+
return body === void 0 ? void 0 : { kind: "optional", body };
|
|
672
|
+
}
|
|
673
|
+
return void 0;
|
|
674
|
+
} finally {
|
|
675
|
+
active.delete(current);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
function directFixedTokenBody(parser, resolve) {
|
|
679
|
+
const body = directTokenBodyParser(parser, resolve);
|
|
680
|
+
if (body === void 0) return void 0;
|
|
681
|
+
const root = directFixedLexNode(body, resolve, /* @__PURE__ */ new Set());
|
|
682
|
+
return root === void 0 ? void 0 : { kind: "fixed-tree", root };
|
|
683
|
+
}
|
|
684
|
+
function directBalancedTokenBody(parser, resolve) {
|
|
685
|
+
if (directTokenBodyParser(parser, resolve) === void 0) return void 0;
|
|
686
|
+
const spec = balancedSpecOf(parser);
|
|
687
|
+
return spec === void 0 ? void 0 : {
|
|
688
|
+
kind: "balanced-scan",
|
|
689
|
+
open: spec.open,
|
|
690
|
+
close: spec.close,
|
|
691
|
+
raw: spec.raw,
|
|
692
|
+
strict: spec.strict,
|
|
693
|
+
ownSkip: spec.ownSkip
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
function directExecutableTokenBody(parser, resolve) {
|
|
697
|
+
return directOptionalSuffixTokenBody(parser, resolve) ?? directTerminalTokenBody(parser, resolve) ?? directOrdered4TokenBody(parser, resolve) ?? directNot2TokenBody(parser, resolve) ?? directBalancedTokenBody(parser, resolve) ?? directFixedTokenBody(parser, resolve);
|
|
698
|
+
}
|
|
699
|
+
var FIRST_LEXICAL_FAMILY_ID = 3;
|
|
700
|
+
var foldAscii = (value) => value.replace(/[A-Z]/g, (c) => c.toLowerCase());
|
|
701
|
+
function canonicalLexicalOutcomeKey(match) {
|
|
702
|
+
if (match.kind === "exact") {
|
|
703
|
+
const values = [...new Set(match.values.map((value) => match.caseInsensitive ? foldAscii(value) : value))].sort();
|
|
704
|
+
return JSON.stringify({ kind: match.kind, values, caseInsensitive: match.caseInsensitive });
|
|
705
|
+
}
|
|
706
|
+
if (match.kind === "startsWith" || match.kind === "endsWith") {
|
|
707
|
+
return JSON.stringify({
|
|
708
|
+
kind: match.kind,
|
|
709
|
+
value: match.caseInsensitive ? foldAscii(match.value) : match.value,
|
|
710
|
+
caseInsensitive: match.caseInsensitive
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
if (match.kind === "matches") {
|
|
714
|
+
const rawFlags = match.caseInsensitive && !match.flags.includes("i") ? `${match.flags}i` : match.flags;
|
|
715
|
+
const flags = new RegExp("", rawFlags.replace(/g/g, "")).flags;
|
|
716
|
+
return JSON.stringify({ kind: match.kind, value: match.value, flags });
|
|
717
|
+
}
|
|
718
|
+
if (match.kind !== "otherwise") throw new Error("parseman: unknown lexical outcome predicate");
|
|
719
|
+
const excluding = match.excluding;
|
|
720
|
+
const fixed = excluding.filter((entry) => entry.kind === "startsWith" || entry.kind === "endsWith");
|
|
721
|
+
const fixedContainsExact = (exact, candidate) => {
|
|
722
|
+
if (exact.caseInsensitive && !candidate.caseInsensitive && /[A-Za-z]/.test(candidate.value)) return false;
|
|
723
|
+
const needle = candidate.caseInsensitive ? foldAscii(candidate.value) : candidate.value;
|
|
724
|
+
return exact.values.every((raw) => {
|
|
725
|
+
const value = candidate.caseInsensitive ? foldAscii(raw) : raw;
|
|
726
|
+
return candidate.kind === "startsWith" ? value.startsWith(needle) : value.endsWith(needle);
|
|
727
|
+
});
|
|
728
|
+
};
|
|
729
|
+
const reduced = [];
|
|
730
|
+
for (const entry of excluding) {
|
|
731
|
+
if (entry.kind !== "exact") {
|
|
732
|
+
reduced.push(entry);
|
|
733
|
+
continue;
|
|
734
|
+
}
|
|
735
|
+
const values = entry.values.filter((value) => !fixed.some((candidate) => fixedContainsExact({ ...entry, values: [value] }, candidate)));
|
|
736
|
+
if (values.length > 0) reduced.push({ ...entry, values });
|
|
737
|
+
}
|
|
738
|
+
return JSON.stringify({
|
|
739
|
+
kind: match.kind,
|
|
740
|
+
excluding: [...new Set(reduced.map(canonicalLexicalOutcomeKey))].sort()
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
function keyOf(def) {
|
|
744
|
+
switch (def.tag) {
|
|
745
|
+
case "literal":
|
|
746
|
+
return `L\0${def.value}\0${def.caseInsensitive ? "i" : ""}`;
|
|
747
|
+
case "keywords":
|
|
748
|
+
return `K\0${def.words.join("")}\0${def.caseInsensitive ? "i" : ""}\0${def.boundary ?? ""}`;
|
|
749
|
+
case "regex":
|
|
750
|
+
return `R\0${def.source}\0${def.flags}`;
|
|
751
|
+
default:
|
|
752
|
+
return void 0;
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
function winnerWrapsReference(winner, reference) {
|
|
756
|
+
let current = winner;
|
|
757
|
+
const seen = /* @__PURE__ */ new Set();
|
|
758
|
+
while (!seen.has(current)) {
|
|
759
|
+
if (current === reference) return true;
|
|
760
|
+
seen.add(current);
|
|
761
|
+
const def = current._def;
|
|
762
|
+
if (def.tag !== "grammar" && def.tag !== "trivia") return false;
|
|
763
|
+
current = def.parser;
|
|
764
|
+
}
|
|
765
|
+
return false;
|
|
766
|
+
}
|
|
767
|
+
function resolvedLazyTarget(parser, resolve) {
|
|
768
|
+
const def = parser._def;
|
|
769
|
+
if (def.tag !== "lazy") return void 0;
|
|
770
|
+
const name = parser._ruleName;
|
|
771
|
+
if (name !== void 0 && resolve !== void 0) {
|
|
772
|
+
const winner = resolve(name);
|
|
773
|
+
if (winner !== void 0 && !winnerWrapsReference(winner, parser)) return winner;
|
|
774
|
+
}
|
|
775
|
+
try {
|
|
776
|
+
return def.thunk();
|
|
777
|
+
} catch {
|
|
778
|
+
return void 0;
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
function tokenChildren(p, resolve) {
|
|
782
|
+
const d = p._def;
|
|
783
|
+
const out = [];
|
|
784
|
+
const push = (v) => {
|
|
785
|
+
if (v !== void 0) out.push(v);
|
|
786
|
+
};
|
|
787
|
+
const rec = d;
|
|
788
|
+
for (const k of ["parser", "main", "skipped", "separator", "selector", "sentinel", "fallback", "otherwise", "triviaParser"]) {
|
|
789
|
+
const v = rec[k];
|
|
790
|
+
if (v !== null && typeof v === "object" && "_def" in v) push(v);
|
|
791
|
+
}
|
|
792
|
+
if (Array.isArray(rec.parsers)) for (const c of rec.parsers) push(c);
|
|
793
|
+
if (Array.isArray(rec.skip)) for (const c of rec.skip) push(c);
|
|
794
|
+
if (Array.isArray(rec.cases)) for (const c of rec.cases) push(c.parser);
|
|
795
|
+
if (Array.isArray(rec.matchers)) for (const c of rec.matchers) push(c.parser);
|
|
796
|
+
if (d.tag === "lazy") {
|
|
797
|
+
push(resolvedLazyTarget(p, resolve));
|
|
798
|
+
}
|
|
799
|
+
return out;
|
|
800
|
+
}
|
|
801
|
+
function newNormalizeSession() {
|
|
802
|
+
return {
|
|
803
|
+
nextState: 0,
|
|
804
|
+
expected: [],
|
|
805
|
+
expectedIds: /* @__PURE__ */ new Map(),
|
|
806
|
+
events: [],
|
|
807
|
+
wrapperFrames: [],
|
|
808
|
+
wrapperStack: [],
|
|
809
|
+
controls: [],
|
|
810
|
+
controlStack: []
|
|
811
|
+
};
|
|
812
|
+
}
|
|
813
|
+
function withLexicalControl(session, kind, body) {
|
|
814
|
+
if (session === void 0) return body();
|
|
815
|
+
const id = session.controls.length;
|
|
816
|
+
const parentControlId = session.controlStack[session.controlStack.length - 1];
|
|
817
|
+
const node = {
|
|
818
|
+
id,
|
|
819
|
+
...parentControlId === void 0 ? {} : { parentControlId },
|
|
820
|
+
kind,
|
|
821
|
+
stateStart: session.nextState,
|
|
822
|
+
stateEnd: -1
|
|
823
|
+
};
|
|
824
|
+
session.controls.push(node);
|
|
825
|
+
session.controlStack.push(id);
|
|
826
|
+
try {
|
|
827
|
+
const result = body();
|
|
828
|
+
node.stateEnd = session.nextState;
|
|
829
|
+
return result;
|
|
830
|
+
} finally {
|
|
831
|
+
const popped = session.controlStack.pop();
|
|
832
|
+
if (popped !== id) throw new Error("parseman: lexical control stack is not well nested");
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
function withLexicalWrapper(session, kind, parser, body) {
|
|
836
|
+
if (session === void 0) return body();
|
|
837
|
+
const controlId = session.controlStack[session.controlStack.length - 1];
|
|
838
|
+
if (controlId === void 0) throw new Error("parseman: lexical wrapper lacks a control anchor");
|
|
839
|
+
const id = session.wrapperFrames.length;
|
|
840
|
+
const parentFrameId = session.wrapperStack[session.wrapperStack.length - 1];
|
|
841
|
+
const common = {
|
|
842
|
+
id,
|
|
843
|
+
...parentFrameId === void 0 ? {} : { parentFrameId },
|
|
844
|
+
controlId,
|
|
845
|
+
stateStart: session.nextState,
|
|
846
|
+
stateEnd: -1
|
|
847
|
+
};
|
|
848
|
+
const frame = kind === "token" ? { ...common, kind } : { ...common, kind, parser };
|
|
849
|
+
session.wrapperFrames.push(frame);
|
|
850
|
+
session.wrapperStack.push(id);
|
|
851
|
+
try {
|
|
852
|
+
const result = body();
|
|
853
|
+
frame.stateEnd = session.nextState;
|
|
854
|
+
return result;
|
|
855
|
+
} finally {
|
|
856
|
+
const popped = session.wrapperStack.pop();
|
|
857
|
+
if (popped !== id) throw new Error("parseman: lexical wrapper stack is not well nested");
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
function lexicalState(session) {
|
|
861
|
+
return session === void 0 ? -1 : session.nextState++;
|
|
862
|
+
}
|
|
863
|
+
function lexicalExpected(session, expected) {
|
|
864
|
+
const key = JSON.stringify(expected);
|
|
865
|
+
const prior = session.expectedIds.get(key);
|
|
866
|
+
if (prior !== void 0) return prior;
|
|
867
|
+
const id = session.expected.length;
|
|
868
|
+
session.expectedIds.set(key, id);
|
|
869
|
+
session.expected.push([...expected]);
|
|
870
|
+
return id;
|
|
871
|
+
}
|
|
872
|
+
function lexicalFail(session, state, expected) {
|
|
873
|
+
if (session !== void 0) {
|
|
874
|
+
session.events.push({ op: "FAIL", state, expectedId: lexicalExpected(session, expected) });
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
function regexFlags(flags) {
|
|
878
|
+
return new RegExp("", flags.replace(/[gy]/g, "")).flags;
|
|
879
|
+
}
|
|
880
|
+
function sequenceIr(parts) {
|
|
881
|
+
const flat = [];
|
|
882
|
+
for (const part of parts) {
|
|
883
|
+
if (part.kind === "sequence") flat.push(...part.parts);
|
|
884
|
+
else flat.push(part);
|
|
885
|
+
}
|
|
886
|
+
return flat.length === 1 ? flat[0] : { kind: "sequence", parts: flat };
|
|
887
|
+
}
|
|
888
|
+
function provenOptionalLiteralSuffix(source, flags) {
|
|
889
|
+
const match = /^(\[(?:\\.|[^\]\\])+\]\+)(\\[.*+?^$(){}|[\]\\/])\?$/.exec(source);
|
|
890
|
+
if (match === null) return void 0;
|
|
891
|
+
const base = match[1];
|
|
892
|
+
const suffix = match[2].slice(1);
|
|
893
|
+
const baseFlags = regexFlags(flags);
|
|
894
|
+
if (new RegExp(`^(?:${base})$`, baseFlags).test(suffix)) return void 0;
|
|
895
|
+
return { base, suffix };
|
|
896
|
+
}
|
|
897
|
+
function normalizeRegex(source, flags, session) {
|
|
898
|
+
const failure = directTerminalFailureExpected({ tag: "regex", source, flags });
|
|
899
|
+
const proof = provenOptionalLiteralSuffix(source, flags);
|
|
900
|
+
if (proof === void 0) {
|
|
901
|
+
const state = lexicalState(session);
|
|
902
|
+
lexicalFail(session, state, failure);
|
|
903
|
+
return { kind: "regex", source, flags };
|
|
904
|
+
}
|
|
905
|
+
lexicalState(session);
|
|
906
|
+
const baseState = lexicalState(session);
|
|
907
|
+
lexicalFail(session, baseState, failure);
|
|
908
|
+
lexicalState(session);
|
|
909
|
+
lexicalState(session);
|
|
910
|
+
return {
|
|
911
|
+
kind: "sequence",
|
|
912
|
+
parts: [
|
|
913
|
+
{ kind: "regex", source: proof.base, flags },
|
|
914
|
+
{
|
|
915
|
+
kind: "repeat",
|
|
916
|
+
body: {
|
|
917
|
+
kind: "literal",
|
|
918
|
+
value: proof.suffix,
|
|
919
|
+
caseInsensitive: flags.includes("i") && /[A-Za-z]/.test(proof.suffix)
|
|
920
|
+
},
|
|
921
|
+
min: 0,
|
|
922
|
+
max: 1,
|
|
923
|
+
greedy: true,
|
|
924
|
+
mode: "possessive"
|
|
925
|
+
}
|
|
926
|
+
]
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
function normalizeLexical(parser, resolve, stack, session) {
|
|
930
|
+
if (stack.has(parser)) return { refusal: "recursive token body" };
|
|
931
|
+
stack.add(parser);
|
|
932
|
+
try {
|
|
933
|
+
return withLexicalControl(session, parser._def.tag, () => normalizeLexicalBody(parser, resolve, stack, session));
|
|
934
|
+
} finally {
|
|
935
|
+
stack.delete(parser);
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
function normalizeLexicalBody(parser, resolve, stack, session) {
|
|
939
|
+
const done = (result) => result;
|
|
940
|
+
const child = (value) => normalizeLexical(value, resolve, stack, session);
|
|
941
|
+
const def = parser._def;
|
|
942
|
+
switch (def.tag) {
|
|
943
|
+
case "literal": {
|
|
944
|
+
const state = lexicalState(session);
|
|
945
|
+
lexicalFail(session, state, directTerminalFailureExpected(def));
|
|
946
|
+
return done({ ir: {
|
|
947
|
+
kind: "literal",
|
|
948
|
+
value: def.caseInsensitive ? def.value.replace(/[A-Z]/g, (c) => c.toLowerCase()) : def.value,
|
|
949
|
+
caseInsensitive: def.caseInsensitive
|
|
950
|
+
} });
|
|
951
|
+
}
|
|
952
|
+
case "keywords": {
|
|
953
|
+
const state = lexicalState(session);
|
|
954
|
+
lexicalFail(session, state, directTerminalFailureExpected(def));
|
|
955
|
+
const words = [...new Set(def.words.map((word) => def.caseInsensitive ? word.replace(/[A-Z]/g, (c) => c.toLowerCase()) : word))].sort((a, b) => b.length - a.length || (a < b ? -1 : a > b ? 1 : 0));
|
|
956
|
+
return done({ ir: {
|
|
957
|
+
kind: "keywords",
|
|
958
|
+
words,
|
|
959
|
+
caseInsensitive: def.caseInsensitive,
|
|
960
|
+
boundary: def.boundary
|
|
961
|
+
} });
|
|
962
|
+
}
|
|
963
|
+
case "regex":
|
|
964
|
+
return done({ ir: normalizeRegex(def.source, regexFlags(def.flags), session) });
|
|
965
|
+
case "sequence": {
|
|
966
|
+
lexicalState(session);
|
|
967
|
+
const parts = [];
|
|
968
|
+
for (const entry of def.parsers) {
|
|
969
|
+
const normalized = child(entry);
|
|
970
|
+
if ("refusal" in normalized) return done(normalized);
|
|
971
|
+
if (normalized.ir.kind === "sequence") parts.push(...normalized.ir.parts);
|
|
972
|
+
else parts.push(normalized.ir);
|
|
973
|
+
}
|
|
974
|
+
return done({ ir: sequenceIr(parts) });
|
|
975
|
+
}
|
|
976
|
+
case "choice": {
|
|
977
|
+
lexicalState(session);
|
|
978
|
+
if (def.gates.some((gate) => gate !== null)) return done({ refusal: "choice has a dynamic gate" });
|
|
979
|
+
if (def.autoNot.some((check) => check !== null)) return done({ refusal: "choice has contextual prefix rejection" });
|
|
980
|
+
if (!def.disjoint && def.strategy.tag !== "firstMatch") {
|
|
981
|
+
return done({ refusal: `choice strategy ${def.strategy.tag} is not canonical lexical order` });
|
|
982
|
+
}
|
|
983
|
+
const arms = [];
|
|
984
|
+
for (const entry of def.parsers) {
|
|
985
|
+
const normalized = child(entry);
|
|
986
|
+
if ("refusal" in normalized) return done(normalized);
|
|
987
|
+
arms.push(normalized.ir);
|
|
988
|
+
}
|
|
989
|
+
return done({ ir: arms.length === 1 ? arms[0] : { kind: "choice", arms } });
|
|
990
|
+
}
|
|
991
|
+
case "optional": {
|
|
992
|
+
lexicalState(session);
|
|
993
|
+
const normalized = child(def.parser);
|
|
994
|
+
return done("refusal" in normalized ? normalized : {
|
|
995
|
+
ir: { kind: "repeat", body: normalized.ir, min: 0, max: 1, greedy: true, mode: "possessive" }
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
case "many":
|
|
999
|
+
case "oneOrMore": {
|
|
1000
|
+
const state = lexicalState(session);
|
|
1001
|
+
if (matchesEmpty(def.parser)) return done({ refusal: "repeat body may not make progress" });
|
|
1002
|
+
const childStart = session?.nextState ?? -1;
|
|
1003
|
+
const normalized = child(def.parser);
|
|
1004
|
+
if ("refusal" in normalized) return done(normalized);
|
|
1005
|
+
if (session !== void 0 && def.min > 1) {
|
|
1006
|
+
const expected = deriveExpected(def.parser);
|
|
1007
|
+
session.events.push({
|
|
1008
|
+
op: "REQUIRE",
|
|
1009
|
+
state,
|
|
1010
|
+
childStart,
|
|
1011
|
+
childEnd: session.nextState,
|
|
1012
|
+
expectedId: lexicalExpected(session, expected.length > 0 ? expected : [def.parser._tag]),
|
|
1013
|
+
when: "mandatory-iteration-2-to-min",
|
|
1014
|
+
committedChild: "propagate",
|
|
1015
|
+
probe: "child-only",
|
|
1016
|
+
anchor: "repeat-position"
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
return done({
|
|
1020
|
+
ir: { kind: "repeat", body: normalized.ir, min: def.min, max: def.max ?? null, greedy: true, mode: "possessive" }
|
|
1021
|
+
});
|
|
1022
|
+
}
|
|
1023
|
+
case "not":
|
|
1024
|
+
case "peek": {
|
|
1025
|
+
const state = lexicalState(session);
|
|
1026
|
+
const innerStart = session?.nextState ?? -1;
|
|
1027
|
+
const normalized = child(def.parser);
|
|
1028
|
+
if ("refusal" in normalized) return done(normalized);
|
|
1029
|
+
if (session !== void 0) session.events.push({
|
|
1030
|
+
op: "ASSERT",
|
|
1031
|
+
state,
|
|
1032
|
+
innerStart,
|
|
1033
|
+
innerEnd: session.nextState,
|
|
1034
|
+
positive: def.tag === "peek",
|
|
1035
|
+
expectedId: lexicalExpected(session, assertionFailureExpected(def.tag === "peek", def.parser._tag)),
|
|
1036
|
+
snapshotPolicy: "saveLookaheadMark",
|
|
1037
|
+
execution: "deferred"
|
|
1038
|
+
});
|
|
1039
|
+
return done({
|
|
1040
|
+
ir: { kind: "assert", positive: def.tag === "peek", body: normalized.ir }
|
|
1041
|
+
});
|
|
1042
|
+
}
|
|
1043
|
+
case "lazy": {
|
|
1044
|
+
const target = resolvedLazyTarget(parser, resolve);
|
|
1045
|
+
return done(target === void 0 ? { refusal: "unresolved lazy token body" } : child(target));
|
|
1046
|
+
}
|
|
1047
|
+
case "token":
|
|
1048
|
+
return done(withLexicalWrapper(session, "token", parser, () => child(def.parser)));
|
|
1049
|
+
case "trivia":
|
|
1050
|
+
return done(child(def.parser));
|
|
1051
|
+
case "grammar":
|
|
1052
|
+
if (def.parser._def.tag === "token") {
|
|
1053
|
+
return done(withLexicalWrapper(session, "grammar", parser, () => child(def.parser)));
|
|
1054
|
+
}
|
|
1055
|
+
if (def.trackLines) return done({ refusal: "token body has line-tracking effects" });
|
|
1056
|
+
if (def.triviaParser !== void 0 || def.captureTrivia === true || def.rootCapture !== void 0) {
|
|
1057
|
+
return done({ refusal: "token body has a trivia-bearing scope" });
|
|
1058
|
+
}
|
|
1059
|
+
return done(withLexicalWrapper(session, "grammar", parser, () => child(def.parser)));
|
|
1060
|
+
case "transform":
|
|
1061
|
+
return done({ refusal: "transform is effectful" });
|
|
1062
|
+
case "leaf":
|
|
1063
|
+
return done({ refusal: "leaf is effectful" });
|
|
1064
|
+
case "node":
|
|
1065
|
+
return done({ refusal: "node is effectful" });
|
|
1066
|
+
case "field":
|
|
1067
|
+
return done({ refusal: "field is effectful" });
|
|
1068
|
+
case "label":
|
|
1069
|
+
return done({ refusal: "label changes diagnostics" });
|
|
1070
|
+
case "expect":
|
|
1071
|
+
return done({ refusal: "expect changes diagnostics" });
|
|
1072
|
+
case "attempt":
|
|
1073
|
+
return done({ refusal: "attempt changes commitment" });
|
|
1074
|
+
case "withCtx":
|
|
1075
|
+
return done({ refusal: "withCtx is dynamic" });
|
|
1076
|
+
case "guard":
|
|
1077
|
+
return done({ refusal: "guard is dynamic" });
|
|
1078
|
+
case "adjacency":
|
|
1079
|
+
return done({ refusal: "adjacency depends on parser state" });
|
|
1080
|
+
case "recover":
|
|
1081
|
+
return done({ refusal: "recover is effectful" });
|
|
1082
|
+
case "scanTo":
|
|
1083
|
+
return done({ refusal: "scanTo is not a lexical run" });
|
|
1084
|
+
case "sepBy":
|
|
1085
|
+
return done({ refusal: "separated repetition is not a lexical run" });
|
|
1086
|
+
case "dispatch":
|
|
1087
|
+
return done({ refusal: "nested dispatch has semantic outcomes" });
|
|
1088
|
+
case "routed":
|
|
1089
|
+
return done({ refusal: "routed depends on an outer dispatch" });
|
|
1090
|
+
case "unknown":
|
|
1091
|
+
return done({ refusal: "unknown parser body" });
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
function normalizeBalancedLexical(parser, resolve, session) {
|
|
1095
|
+
let marked = parser;
|
|
1096
|
+
let spec = marked._balancedSpec;
|
|
1097
|
+
const tokenWrappers = [];
|
|
1098
|
+
while (marked._def.tag === "token") {
|
|
1099
|
+
tokenWrappers.push(marked);
|
|
1100
|
+
marked = marked._def.parser;
|
|
1101
|
+
spec ??= marked._balancedSpec;
|
|
1102
|
+
}
|
|
1103
|
+
if (spec === void 0) return void 0;
|
|
1104
|
+
const machine = () => withLexicalControl(session, "balanced", () => {
|
|
1105
|
+
lexicalState(session);
|
|
1106
|
+
const openState = lexicalState(session);
|
|
1107
|
+
if (session !== void 0) lexicalFail(session, openState, directTerminalFailureExpected({
|
|
1108
|
+
tag: "literal",
|
|
1109
|
+
value: spec.open,
|
|
1110
|
+
caseInsensitive: false
|
|
1111
|
+
}));
|
|
1112
|
+
lexicalState(session);
|
|
1113
|
+
const skip = [];
|
|
1114
|
+
for (const entry of spec.ownSkip) {
|
|
1115
|
+
const normalized = withLexicalControl(session, "balanced-skip", () => normalizeBalancedLexical(entry, resolve, session) ?? normalizeLexical(entry, resolve, /* @__PURE__ */ new Set(), session));
|
|
1116
|
+
if ("refusal" in normalized) return {
|
|
1117
|
+
refusal: `balanced skipper is not represented: ${normalized.refusal}`
|
|
1118
|
+
};
|
|
1119
|
+
skip.push(normalized.ir);
|
|
1120
|
+
}
|
|
1121
|
+
const closeState = lexicalState(session);
|
|
1122
|
+
if (session !== void 0) {
|
|
1123
|
+
const expectedId = lexicalExpected(session, directTerminalFailureExpected({
|
|
1124
|
+
tag: "literal",
|
|
1125
|
+
value: spec.close,
|
|
1126
|
+
caseInsensitive: false
|
|
1127
|
+
}));
|
|
1128
|
+
session.events.push(spec.strict ? {
|
|
1129
|
+
op: "BAL_CLOSE_STRICT",
|
|
1130
|
+
state: closeState,
|
|
1131
|
+
expectedId,
|
|
1132
|
+
probe: true,
|
|
1133
|
+
committed: false,
|
|
1134
|
+
when: "close-miss-after-open-body-success"
|
|
1135
|
+
} : {
|
|
1136
|
+
op: "BAL_CLOSE_RECOVER",
|
|
1137
|
+
state: closeState,
|
|
1138
|
+
expectedId,
|
|
1139
|
+
probe: true,
|
|
1140
|
+
committed: false,
|
|
1141
|
+
when: "close-miss-after-open-body-success",
|
|
1142
|
+
result: "parseError",
|
|
1143
|
+
errorSpan: "close-position",
|
|
1144
|
+
lineAnnotation: "when-active",
|
|
1145
|
+
errorSink: "when-active",
|
|
1146
|
+
cstErrorCapture: "when-active"
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
return {
|
|
1150
|
+
ir: {
|
|
1151
|
+
kind: "balanced",
|
|
1152
|
+
open: spec.open,
|
|
1153
|
+
close: spec.close,
|
|
1154
|
+
strict: spec.strict,
|
|
1155
|
+
raw: spec.raw,
|
|
1156
|
+
skip
|
|
1157
|
+
}
|
|
1158
|
+
};
|
|
1159
|
+
});
|
|
1160
|
+
const wrap = (index) => {
|
|
1161
|
+
const tokenParser = tokenWrappers[index];
|
|
1162
|
+
return tokenParser === void 0 ? machine() : withLexicalControl(session, "token", () => withLexicalWrapper(session, "token", tokenParser, () => wrap(index + 1)));
|
|
1163
|
+
};
|
|
1164
|
+
return wrap(0);
|
|
1165
|
+
}
|
|
1166
|
+
var CAPABILITY_VARIANT_GAP = "total token replacement body is not implemented for every supported assembly variant";
|
|
1167
|
+
var FIXED_TUPLE_BINDING_GAP = "binding candidate set is incomplete: shared, direct captured, and statically named fixed-tuple bodies have not all been built before pricing; fixed children and routes may not be rediscovered from arrays";
|
|
1168
|
+
var COMPLETE_CAPABILITY = { kind: "complete" };
|
|
1169
|
+
var gap = (reason) => ({ kind: "gap", reason });
|
|
1170
|
+
var COMPLETE_PHASE = {
|
|
1171
|
+
representation: COMPLETE_CAPABILITY,
|
|
1172
|
+
executableLowering: COMPLETE_CAPABILITY
|
|
1173
|
+
};
|
|
1174
|
+
var phaseGap = (representation, loweringReason) => ({
|
|
1175
|
+
representation,
|
|
1176
|
+
executableLowering: representation.kind === "impossible" ? representation : gap(loweringReason)
|
|
1177
|
+
});
|
|
1178
|
+
var ALL_BINDING_READERS = 7;
|
|
1179
|
+
var ALL_BINDING_VARIANTS = 63;
|
|
1180
|
+
var TERMINAL_CAPTURED_TEMPLATE_ID = 11;
|
|
1181
|
+
var DECISION_REFERENCE_TEMPLATE_ID = 12;
|
|
1182
|
+
var DECISION_CAPTURED_TEMPLATE_ID = 13;
|
|
1183
|
+
var DECISION_NAMED_TEMPLATE_ID = 14;
|
|
1184
|
+
function bindingTemplateId(parentTag, ordinal) {
|
|
1185
|
+
if (parentTag === "root") return 1;
|
|
1186
|
+
switch (parentTag) {
|
|
1187
|
+
case "sequence":
|
|
1188
|
+
return 2;
|
|
1189
|
+
case "choice":
|
|
1190
|
+
return 3;
|
|
1191
|
+
case "dispatch":
|
|
1192
|
+
return ordinal === 0 ? 4 : 5;
|
|
1193
|
+
case "many":
|
|
1194
|
+
case "oneOrMore":
|
|
1195
|
+
case "sepBy":
|
|
1196
|
+
return ordinal === 0 ? 6 : 7;
|
|
1197
|
+
case "scanTo":
|
|
1198
|
+
return ordinal === 0 ? 8 : 9;
|
|
1199
|
+
default:
|
|
1200
|
+
return 10;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
function bindingDigest(words, parentTag, childTag) {
|
|
1204
|
+
let hash = 2166136261;
|
|
1205
|
+
const feed = (value) => {
|
|
1206
|
+
hash ^= value & 255;
|
|
1207
|
+
hash = Math.imul(hash, 16777619);
|
|
1208
|
+
};
|
|
1209
|
+
for (const c of `${parentTag}\0${childTag}`) feed(c.charCodeAt(0));
|
|
1210
|
+
for (const word of words) {
|
|
1211
|
+
feed(word);
|
|
1212
|
+
feed(word >>> 8);
|
|
1213
|
+
feed(word >>> 16);
|
|
1214
|
+
feed(word >>> 24);
|
|
1215
|
+
}
|
|
1216
|
+
return hash >>> 0;
|
|
1217
|
+
}
|
|
1218
|
+
function fixedBindingProjection(edge, edgeId, projectionId) {
|
|
1219
|
+
const template = bindingTemplateId(edge.parentTag, edge.childOrdinal);
|
|
1220
|
+
let readerMask = ALL_BINDING_READERS;
|
|
1221
|
+
const variantMask = ALL_BINDING_VARIANTS;
|
|
1222
|
+
if (edge.parentTag === "recover" || edge.parentTag === "withCtx") readerMask = 3;
|
|
1223
|
+
const words = [
|
|
1224
|
+
edge.parentBodyId,
|
|
1225
|
+
edge.childBodyId,
|
|
1226
|
+
edge.childOrdinal,
|
|
1227
|
+
edge.childOrdinal,
|
|
1228
|
+
edge.childOrdinal,
|
|
1229
|
+
template,
|
|
1230
|
+
edge.childBodyId,
|
|
1231
|
+
template,
|
|
1232
|
+
readerMask,
|
|
1233
|
+
variantMask
|
|
1234
|
+
];
|
|
1235
|
+
return {
|
|
1236
|
+
id: projectionId,
|
|
1237
|
+
edgeId,
|
|
1238
|
+
parentBodyId: edge.parentBodyId,
|
|
1239
|
+
childBodyId: edge.childBodyId,
|
|
1240
|
+
childOrdinal: edge.childOrdinal,
|
|
1241
|
+
referenceOperand: edge.childOrdinal,
|
|
1242
|
+
capturedSlotId: edge.childOrdinal,
|
|
1243
|
+
capturedTemplateId: template,
|
|
1244
|
+
namedSymbolId: edge.childBodyId,
|
|
1245
|
+
namedTemplateId: template,
|
|
1246
|
+
readerMask,
|
|
1247
|
+
variantMask,
|
|
1248
|
+
semanticDigest: bindingDigest(words, edge.parentTag, edge.childTag)
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
function derivedCapabilityStatus(obligations) {
|
|
1252
|
+
const phases = [
|
|
1253
|
+
obligations.recognition,
|
|
1254
|
+
obligations.diagnostics,
|
|
1255
|
+
obligations.boundaryPlan,
|
|
1256
|
+
obligations.materializationPlan,
|
|
1257
|
+
obligations.supportedVariants,
|
|
1258
|
+
obligations.bindingAndReachability
|
|
1259
|
+
];
|
|
1260
|
+
const ordered = phases.flatMap((entry) => [entry.representation, entry.executableLowering]);
|
|
1261
|
+
const impossible = ordered.find((entry) => entry.kind === "impossible");
|
|
1262
|
+
if (impossible !== void 0) return impossible;
|
|
1263
|
+
const gaps = phases.map((entry) => entry.executableLowering).filter((entry) => entry.kind === "gap");
|
|
1264
|
+
if (gaps.length > 0) return gap([...new Set(gaps.map((entry) => entry.reason))].join("; "));
|
|
1265
|
+
return COMPLETE_CAPABILITY;
|
|
1266
|
+
}
|
|
1267
|
+
function tokenObligations(recognition, represented = {
|
|
1268
|
+
diagnostics: false,
|
|
1269
|
+
boundaryPlan: gap("token boundary transaction is not represented"),
|
|
1270
|
+
materializationPlan: gap("token range/value/CST materialization is not represented")
|
|
1271
|
+
}) {
|
|
1272
|
+
const representedOrGap = (yes, reason) => yes ? COMPLETE_CAPABILITY : gap(reason);
|
|
1273
|
+
return {
|
|
1274
|
+
recognition: phaseGap(recognition, "token recognizer lowering is not implemented for every supported variant"),
|
|
1275
|
+
diagnostics: phaseGap(
|
|
1276
|
+
representedOrGap(represented.diagnostics, "token diagnostic plan is not represented"),
|
|
1277
|
+
"token diagnostic event lowering is deferred"
|
|
1278
|
+
),
|
|
1279
|
+
boundaryPlan: phaseGap(
|
|
1280
|
+
represented.boundaryPlan,
|
|
1281
|
+
"token boundary transaction lowering is deferred"
|
|
1282
|
+
),
|
|
1283
|
+
materializationPlan: phaseGap(
|
|
1284
|
+
represented.materializationPlan,
|
|
1285
|
+
"token range/value/CST materialization lowering is deferred"
|
|
1286
|
+
),
|
|
1287
|
+
supportedVariants: phaseGap(gap(CAPABILITY_VARIANT_GAP), CAPABILITY_VARIANT_GAP),
|
|
1288
|
+
bindingAndReachability: phaseGap(gap(FIXED_TUPLE_BINDING_GAP), FIXED_TUPLE_BINDING_GAP)
|
|
1289
|
+
};
|
|
1290
|
+
}
|
|
1291
|
+
function executableLexBodyObligations() {
|
|
1292
|
+
return {
|
|
1293
|
+
recognition: COMPLETE_PHASE,
|
|
1294
|
+
diagnostics: COMPLETE_PHASE,
|
|
1295
|
+
boundaryPlan: COMPLETE_PHASE,
|
|
1296
|
+
materializationPlan: COMPLETE_PHASE,
|
|
1297
|
+
supportedVariants: COMPLETE_PHASE,
|
|
1298
|
+
bindingAndReachability: COMPLETE_PHASE
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
function terminalObligations() {
|
|
1302
|
+
return {
|
|
1303
|
+
recognition: COMPLETE_PHASE,
|
|
1304
|
+
diagnostics: COMPLETE_PHASE,
|
|
1305
|
+
boundaryPlan: COMPLETE_PHASE,
|
|
1306
|
+
materializationPlan: COMPLETE_PHASE,
|
|
1307
|
+
supportedVariants: COMPLETE_PHASE,
|
|
1308
|
+
bindingAndReachability: phaseGap(gap(FIXED_TUPLE_BINDING_GAP), FIXED_TUPLE_BINDING_GAP)
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
function decisionObligations(recognition) {
|
|
1312
|
+
return tokenObligations(recognition);
|
|
1313
|
+
}
|
|
1314
|
+
function executableDecisionObligations(recognition, effects) {
|
|
1315
|
+
const recognitionPhase = recognition.kind === "complete" ? COMPLETE_PHASE : phaseGap(recognition, "decision recognition authority is incomplete");
|
|
1316
|
+
return {
|
|
1317
|
+
recognition: recognitionPhase,
|
|
1318
|
+
diagnostics: effects,
|
|
1319
|
+
boundaryPlan: COMPLETE_PHASE,
|
|
1320
|
+
materializationPlan: COMPLETE_PHASE,
|
|
1321
|
+
supportedVariants: effects,
|
|
1322
|
+
bindingAndReachability: effects
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
function decisionLead(parser, context, resolve, seen = /* @__PURE__ */ new Set()) {
|
|
1326
|
+
if (seen.has(parser)) return { gap: "recursive leading decision language" };
|
|
1327
|
+
seen.add(parser);
|
|
1328
|
+
const finish = (result) => {
|
|
1329
|
+
seen.delete(parser);
|
|
1330
|
+
return result;
|
|
1331
|
+
};
|
|
1332
|
+
const def = parser._def;
|
|
1333
|
+
if (keyOf(def) !== void 0 || def.tag === "token" || parser._balancedSpec !== void 0) {
|
|
1334
|
+
const normalized = normalizeBalancedLexical(parser, resolve) ?? normalizeLexical(def.tag === "token" ? def.parser : parser, resolve, /* @__PURE__ */ new Set());
|
|
1335
|
+
if ("refusal" in normalized) return finish({ gap: `leading recognizer: ${normalized.refusal}` });
|
|
1336
|
+
return finish({ lead: {
|
|
1337
|
+
parser,
|
|
1338
|
+
ir: normalized.ir,
|
|
1339
|
+
key: JSON.stringify(normalized.ir)
|
|
1340
|
+
} });
|
|
1341
|
+
}
|
|
1342
|
+
switch (def.tag) {
|
|
1343
|
+
case "dispatch": {
|
|
1344
|
+
const selected = decisionLead(def.selector, context, resolve, seen);
|
|
1345
|
+
if ("gap" in selected) return finish(selected);
|
|
1346
|
+
return finish({ lead: { ...selected.lead, dispatch: def } });
|
|
1347
|
+
}
|
|
1348
|
+
case "lazy": {
|
|
1349
|
+
const target = resolvedLazyTarget(parser, resolve);
|
|
1350
|
+
return finish(target === void 0 ? { gap: "unresolved leading rule reference" } : decisionLead(target, context, resolve, seen));
|
|
1351
|
+
}
|
|
1352
|
+
case "sequence":
|
|
1353
|
+
if (def.parsers.length === 0) return finish({ gap: "empty leading sequence" });
|
|
1354
|
+
if (matchesEmpty(def.parsers[0], /* @__PURE__ */ new Set(), resolve)) {
|
|
1355
|
+
return finish({ gap: "nullable leading sequence needs a total same-position union proof" });
|
|
1356
|
+
}
|
|
1357
|
+
return finish(decisionLead(def.parsers[0], context, resolve, seen));
|
|
1358
|
+
case "attempt":
|
|
1359
|
+
case "transform":
|
|
1360
|
+
case "leaf":
|
|
1361
|
+
case "node":
|
|
1362
|
+
case "field":
|
|
1363
|
+
case "label":
|
|
1364
|
+
case "expect":
|
|
1365
|
+
case "trivia":
|
|
1366
|
+
return finish(decisionLead(def.parser, context, resolve, seen));
|
|
1367
|
+
case "grammar":
|
|
1368
|
+
if (def.triviaParser !== void 0 || def.clearTrivia === true || def.trackLines || def.captureTrivia === true || def.rootCapture !== void 0) {
|
|
1369
|
+
return finish({ gap: "leading grammar wrapper changes lexical context" });
|
|
1370
|
+
}
|
|
1371
|
+
return finish(decisionLead(def.parser, context, resolve, seen));
|
|
1372
|
+
case "choice":
|
|
1373
|
+
return finish({ gap: "nested leading choice needs a compatible range union proof" });
|
|
1374
|
+
case "optional":
|
|
1375
|
+
case "many":
|
|
1376
|
+
case "oneOrMore":
|
|
1377
|
+
case "sepBy":
|
|
1378
|
+
return finish({ gap: "repeated or nullable leading language needs a range-partition proof" });
|
|
1379
|
+
case "peek":
|
|
1380
|
+
return finish({ gap: "positive lookahead needs an exact effect-free compatible view" });
|
|
1381
|
+
case "not":
|
|
1382
|
+
return finish({ gap: "negative lookahead needs a decidable complement" });
|
|
1383
|
+
case "withCtx":
|
|
1384
|
+
case "guard":
|
|
1385
|
+
case "adjacency":
|
|
1386
|
+
case "recover":
|
|
1387
|
+
case "scanTo":
|
|
1388
|
+
case "routed":
|
|
1389
|
+
case "unknown":
|
|
1390
|
+
return finish({ gap: `leading ${def.tag} language is not represented` });
|
|
1391
|
+
case "literal":
|
|
1392
|
+
case "keywords":
|
|
1393
|
+
case "regex":
|
|
1394
|
+
throw new Error("parseman: decision lead terminal escaped its direct case");
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
function finiteLexicalValues(ir) {
|
|
1398
|
+
if (ir.kind === "literal") return [ir.value];
|
|
1399
|
+
if (ir.kind === "keywords") return ir.words;
|
|
1400
|
+
return void 0;
|
|
1401
|
+
}
|
|
1402
|
+
function lexicalIrEnd(ir, input, start = 0) {
|
|
1403
|
+
switch (ir.kind) {
|
|
1404
|
+
case "literal": {
|
|
1405
|
+
const actual = input.slice(start, start + ir.value.length);
|
|
1406
|
+
return (ir.caseInsensitive ? foldAscii(actual) === foldAscii(ir.value) : actual === ir.value) ? start + ir.value.length : void 0;
|
|
1407
|
+
}
|
|
1408
|
+
case "keywords": {
|
|
1409
|
+
for (const word of ir.words) {
|
|
1410
|
+
const actual = input.slice(start, start + word.length);
|
|
1411
|
+
if (ir.caseInsensitive ? foldAscii(actual) === foldAscii(word) : actual === word) {
|
|
1412
|
+
const next = input[start + word.length];
|
|
1413
|
+
if (next === void 0 || ir.boundary === void 0) return start + word.length;
|
|
1414
|
+
try {
|
|
1415
|
+
if (!new RegExp(`[${ir.boundary}]`).test(next)) return start + word.length;
|
|
1416
|
+
} catch {
|
|
1417
|
+
return void 0;
|
|
1418
|
+
}
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
return void 0;
|
|
1422
|
+
}
|
|
1423
|
+
case "regex": {
|
|
1424
|
+
try {
|
|
1425
|
+
const matcher = new RegExp(ir.source, `${regexFlags(ir.flags)}y`);
|
|
1426
|
+
matcher.lastIndex = start;
|
|
1427
|
+
const match = matcher.exec(input);
|
|
1428
|
+
return match === null ? void 0 : matcher.lastIndex;
|
|
1429
|
+
} catch {
|
|
1430
|
+
return void 0;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
case "choice": {
|
|
1434
|
+
for (const arm of ir.arms) {
|
|
1435
|
+
const end = lexicalIrEnd(arm, input, start);
|
|
1436
|
+
if (end !== void 0) return end;
|
|
1437
|
+
}
|
|
1438
|
+
return void 0;
|
|
1439
|
+
}
|
|
1440
|
+
case "sequence": {
|
|
1441
|
+
let end = start;
|
|
1442
|
+
for (const part of ir.parts) {
|
|
1443
|
+
const next = lexicalIrEnd(part, input, end);
|
|
1444
|
+
if (next === void 0) return void 0;
|
|
1445
|
+
end = next;
|
|
1446
|
+
}
|
|
1447
|
+
return end;
|
|
1448
|
+
}
|
|
1449
|
+
case "repeat": {
|
|
1450
|
+
let end = start;
|
|
1451
|
+
let count = 0;
|
|
1452
|
+
while (ir.max === null || count < ir.max) {
|
|
1453
|
+
const next = lexicalIrEnd(ir.body, input, end);
|
|
1454
|
+
if (next === void 0 || next === end) break;
|
|
1455
|
+
end = next;
|
|
1456
|
+
count++;
|
|
1457
|
+
}
|
|
1458
|
+
return count >= ir.min ? end : void 0;
|
|
1459
|
+
}
|
|
1460
|
+
case "assert": {
|
|
1461
|
+
const matched = lexicalIrEnd(ir.body, input, start) !== void 0;
|
|
1462
|
+
return matched === ir.positive ? start : void 0;
|
|
1463
|
+
}
|
|
1464
|
+
case "balanced":
|
|
1465
|
+
return void 0;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
function lexicalIrAcceptsExact(ir, value) {
|
|
1469
|
+
return lexicalIrEnd(ir, value) === value.length;
|
|
1470
|
+
}
|
|
1471
|
+
function asciiCaseVariants(value, caseInsensitive) {
|
|
1472
|
+
if (caseInsensitive && /[^\x00-\x7f]/.test(value)) return void 0;
|
|
1473
|
+
if (!caseInsensitive || !/[A-Za-z]/.test(value)) return [value];
|
|
1474
|
+
let variants = [""];
|
|
1475
|
+
for (const char of value) {
|
|
1476
|
+
const lower = char >= "A" && char <= "Z" ? char.toLowerCase() : char;
|
|
1477
|
+
const upper = char >= "a" && char <= "z" ? char.toUpperCase() : char;
|
|
1478
|
+
if (lower !== upper && variants.length > 2048) return void 0;
|
|
1479
|
+
variants = lower === upper ? variants.map((prefix) => prefix + char) : variants.flatMap((prefix) => [prefix + lower, prefix + upper]);
|
|
1480
|
+
}
|
|
1481
|
+
return variants;
|
|
1482
|
+
}
|
|
1483
|
+
function regexAsciiCaseStable(source) {
|
|
1484
|
+
let index = 0;
|
|
1485
|
+
while (index < source.length) {
|
|
1486
|
+
const char = source[index];
|
|
1487
|
+
if (char === "\\") {
|
|
1488
|
+
const kind = source[index + 1];
|
|
1489
|
+
if (kind === "x") {
|
|
1490
|
+
const value = Number.parseInt(source.slice(index + 2, index + 4), 16);
|
|
1491
|
+
if (Number.isFinite(value) && /[A-Za-z]/.test(String.fromCharCode(value))) return false;
|
|
1492
|
+
index += 4;
|
|
1493
|
+
continue;
|
|
1494
|
+
}
|
|
1495
|
+
if (kind === "u") {
|
|
1496
|
+
const brace = source[index + 2] === "{";
|
|
1497
|
+
const end = brace ? source.indexOf("}", index + 3) : index + 6;
|
|
1498
|
+
const digits = brace ? source.slice(index + 3, end) : source.slice(index + 2, end);
|
|
1499
|
+
const value = Number.parseInt(digits, 16);
|
|
1500
|
+
if (Number.isFinite(value) && value <= 65535 && /[A-Za-z]/.test(String.fromCharCode(value))) return false;
|
|
1501
|
+
index = brace ? end + 1 || source.length : end;
|
|
1502
|
+
continue;
|
|
1503
|
+
}
|
|
1504
|
+
if (kind !== void 0 && "dDsSwWpP".includes(kind)) {
|
|
1505
|
+
index += 2;
|
|
1506
|
+
continue;
|
|
1507
|
+
}
|
|
1508
|
+
if (kind !== void 0 && /[A-Za-z]/.test(kind)) return false;
|
|
1509
|
+
index += 2;
|
|
1510
|
+
continue;
|
|
1511
|
+
}
|
|
1512
|
+
if (char === "[") {
|
|
1513
|
+
let end = index + 1;
|
|
1514
|
+
for (; end < source.length; end++) {
|
|
1515
|
+
if (source[end] === "\\") {
|
|
1516
|
+
end++;
|
|
1517
|
+
continue;
|
|
1518
|
+
}
|
|
1519
|
+
if (source[end] === "]") break;
|
|
1520
|
+
}
|
|
1521
|
+
if (end >= source.length) return false;
|
|
1522
|
+
const body = source.slice(index + 1, end);
|
|
1523
|
+
const lowerRange = body.includes("a-z");
|
|
1524
|
+
const upperRange = body.includes("A-Z");
|
|
1525
|
+
if (lowerRange !== upperRange) return false;
|
|
1526
|
+
const withoutRanges = body.replace(/a-z|A-Z/g, "");
|
|
1527
|
+
const literals = /* @__PURE__ */ new Set();
|
|
1528
|
+
for (let at = 0; at < withoutRanges.length; at++) {
|
|
1529
|
+
if (withoutRanges[at] === "\\") {
|
|
1530
|
+
const kind = withoutRanges[++at];
|
|
1531
|
+
if (kind === "x") {
|
|
1532
|
+
const value = Number.parseInt(withoutRanges.slice(at + 1, at + 3), 16);
|
|
1533
|
+
if (Number.isFinite(value) && /[A-Za-z]/.test(String.fromCharCode(value))) {
|
|
1534
|
+
literals.add(String.fromCharCode(value));
|
|
1535
|
+
}
|
|
1536
|
+
at += 2;
|
|
1537
|
+
} else if (kind === "u") {
|
|
1538
|
+
let digits;
|
|
1539
|
+
if (withoutRanges[at + 1] === "{") {
|
|
1540
|
+
const end2 = withoutRanges.indexOf("}", at + 2);
|
|
1541
|
+
if (end2 < 0) return false;
|
|
1542
|
+
digits = withoutRanges.slice(at + 2, end2);
|
|
1543
|
+
at = end2;
|
|
1544
|
+
} else {
|
|
1545
|
+
digits = withoutRanges.slice(at + 1, at + 5);
|
|
1546
|
+
at += 4;
|
|
1547
|
+
}
|
|
1548
|
+
const value = Number.parseInt(digits, 16);
|
|
1549
|
+
if (Number.isFinite(value) && value <= 65535 && /[A-Za-z]/.test(String.fromCharCode(value))) {
|
|
1550
|
+
literals.add(String.fromCharCode(value));
|
|
1551
|
+
}
|
|
1552
|
+
} else if (kind !== void 0 && /[A-Za-z]/.test(kind) && !"dDsSwWpP".includes(kind)) return false;
|
|
1553
|
+
continue;
|
|
1554
|
+
}
|
|
1555
|
+
if (/[A-Za-z]/.test(withoutRanges[at])) literals.add(withoutRanges[at]);
|
|
1556
|
+
}
|
|
1557
|
+
for (const letter of literals) {
|
|
1558
|
+
const peer = letter === letter.toLowerCase() ? letter.toUpperCase() : letter.toLowerCase();
|
|
1559
|
+
if (!literals.has(peer)) return false;
|
|
1560
|
+
}
|
|
1561
|
+
index = end + 1;
|
|
1562
|
+
continue;
|
|
1563
|
+
}
|
|
1564
|
+
if (/[A-Za-z]/.test(char)) return false;
|
|
1565
|
+
index++;
|
|
1566
|
+
}
|
|
1567
|
+
return true;
|
|
1568
|
+
}
|
|
1569
|
+
function lexicalIrAsciiCaseStable(ir) {
|
|
1570
|
+
switch (ir.kind) {
|
|
1571
|
+
case "literal":
|
|
1572
|
+
return ir.caseInsensitive || !/[A-Za-z]/.test(ir.value);
|
|
1573
|
+
case "keywords":
|
|
1574
|
+
return ir.caseInsensitive || ir.words.every((word) => !/[A-Za-z]/.test(word));
|
|
1575
|
+
case "regex":
|
|
1576
|
+
return ir.flags.includes("i") || regexAsciiCaseStable(ir.source);
|
|
1577
|
+
case "sequence":
|
|
1578
|
+
return ir.parts.every(lexicalIrAsciiCaseStable);
|
|
1579
|
+
case "choice":
|
|
1580
|
+
return ir.arms.every(lexicalIrAsciiCaseStable);
|
|
1581
|
+
case "repeat":
|
|
1582
|
+
case "assert":
|
|
1583
|
+
return lexicalIrAsciiCaseStable(ir.body);
|
|
1584
|
+
case "balanced":
|
|
1585
|
+
return !/[A-Za-z]/.test(ir.open + ir.close) && ir.skip.every(lexicalIrAsciiCaseStable);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
function lexicalContinuationClasses(ir) {
|
|
1589
|
+
if (ir.kind === "regex") {
|
|
1590
|
+
const classesRemoved = ir.source.replace(/\[(?:\\.|[^\]\\])*\]/g, "[]");
|
|
1591
|
+
if (/[|()$^]/.test(classesRemoved) || /\\[bB]/.test(classesRemoved)) return void 0;
|
|
1592
|
+
const tail = /(\[(?:\\.|[^\]\\])+\])(?:\*|\+)$/.exec(ir.source);
|
|
1593
|
+
if (tail === null || /[uv]/.test(ir.flags) || /\\[pP]|\\u\{/.test(tail[1])) return void 0;
|
|
1594
|
+
return [{ source: tail[1], flags: ir.flags }];
|
|
1595
|
+
}
|
|
1596
|
+
if (ir.kind === "sequence" && ir.parts.length === 2) {
|
|
1597
|
+
const [head, tail] = ir.parts;
|
|
1598
|
+
if (tail?.kind !== "repeat" || tail.min !== 0 || tail.max !== 1 || tail.body.kind !== "literal" || [...tail.body.value].length !== 1) return void 0;
|
|
1599
|
+
const headClasses = lexicalContinuationClasses(head);
|
|
1600
|
+
if (headClasses === void 0) return void 0;
|
|
1601
|
+
const escaped = tail.body.value.replace(/[\\\]\-^]/g, "\\$&");
|
|
1602
|
+
return [...headClasses, {
|
|
1603
|
+
source: `[${escaped}]`,
|
|
1604
|
+
flags: tail.body.caseInsensitive ? "i" : ""
|
|
1605
|
+
}];
|
|
1606
|
+
}
|
|
1607
|
+
return void 0;
|
|
1608
|
+
}
|
|
1609
|
+
function boundaryCoversContinuation(family, boundary) {
|
|
1610
|
+
const classes = lexicalContinuationClasses(family);
|
|
1611
|
+
if (classes === void 0) return false;
|
|
1612
|
+
let boundaryMatcher;
|
|
1613
|
+
const matchers = [];
|
|
1614
|
+
try {
|
|
1615
|
+
boundaryMatcher = new RegExp(`^[${boundary}]$`);
|
|
1616
|
+
for (const entry of classes) {
|
|
1617
|
+
matchers.push(new RegExp(`^${entry.source}$`, regexFlags(entry.flags)));
|
|
1618
|
+
}
|
|
1619
|
+
} catch {
|
|
1620
|
+
return false;
|
|
1621
|
+
}
|
|
1622
|
+
for (let code = 0; code <= 65535; code++) {
|
|
1623
|
+
const char = String.fromCharCode(code);
|
|
1624
|
+
if (matchers.some((matcher) => matcher.test(char)) && !boundaryMatcher.test(char)) return false;
|
|
1625
|
+
}
|
|
1626
|
+
return true;
|
|
1627
|
+
}
|
|
1628
|
+
function fixedRegexLiteral(source) {
|
|
1629
|
+
let value = "";
|
|
1630
|
+
for (let index = 0; index < source.length; index++) {
|
|
1631
|
+
const char = source[index];
|
|
1632
|
+
if (char !== "\\") {
|
|
1633
|
+
if (/[.[\]{}()*+?|^$]/.test(char)) return void 0;
|
|
1634
|
+
value += char;
|
|
1635
|
+
continue;
|
|
1636
|
+
}
|
|
1637
|
+
const kind = source[++index];
|
|
1638
|
+
if (kind === void 0 || "dDsSwWpPbB".includes(kind)) return void 0;
|
|
1639
|
+
if (kind === "x") {
|
|
1640
|
+
const code = Number.parseInt(source.slice(index + 1, index + 3), 16);
|
|
1641
|
+
if (!Number.isFinite(code)) return void 0;
|
|
1642
|
+
value += String.fromCharCode(code);
|
|
1643
|
+
index += 2;
|
|
1644
|
+
continue;
|
|
1645
|
+
}
|
|
1646
|
+
if (kind === "u") {
|
|
1647
|
+
if (source[index + 1] === "{") return void 0;
|
|
1648
|
+
const code = Number.parseInt(source.slice(index + 1, index + 5), 16);
|
|
1649
|
+
if (!Number.isFinite(code)) return void 0;
|
|
1650
|
+
value += String.fromCharCode(code);
|
|
1651
|
+
index += 4;
|
|
1652
|
+
continue;
|
|
1653
|
+
}
|
|
1654
|
+
value += kind;
|
|
1655
|
+
}
|
|
1656
|
+
return value;
|
|
1657
|
+
}
|
|
1658
|
+
function familyHasContextFreeFiniteEnd(ir, spellings) {
|
|
1659
|
+
if (ir.kind === "literal") return true;
|
|
1660
|
+
if (ir.kind === "regex") return fixedRegexLiteral(ir.source) !== void 0;
|
|
1661
|
+
if (ir.kind !== "keywords" || ir.boundary !== void 0) return false;
|
|
1662
|
+
return spellings.every((spelling) => !ir.words.some((word) => {
|
|
1663
|
+
const actual = ir.caseInsensitive ? foldAscii(spelling) : spelling;
|
|
1664
|
+
const candidate = ir.caseInsensitive ? foldAscii(word) : word;
|
|
1665
|
+
return candidate.length > actual.length && candidate.startsWith(actual);
|
|
1666
|
+
}));
|
|
1667
|
+
}
|
|
1668
|
+
function compatibleLanguageViews(arm, family) {
|
|
1669
|
+
if (JSON.stringify(arm) === JSON.stringify(family)) return [{ ir: arm, relation: "equal" }];
|
|
1670
|
+
const values = finiteLexicalValues(arm);
|
|
1671
|
+
if (values === void 0 || values.length === 0) return void 0;
|
|
1672
|
+
const familyValues = finiteLexicalValues(family);
|
|
1673
|
+
const foldedArm = arm.kind === "literal" ? arm.caseInsensitive : arm.kind === "keywords" && arm.caseInsensitive;
|
|
1674
|
+
const foldedFamily = family.kind === "literal" ? family.caseInsensitive : family.kind === "keywords" && family.caseInsensitive;
|
|
1675
|
+
const armBoundary = arm.kind === "keywords" ? arm.boundary : void 0;
|
|
1676
|
+
const views = [];
|
|
1677
|
+
for (const value of values) {
|
|
1678
|
+
let relation;
|
|
1679
|
+
const armCaseInsensitive = arm.kind === "literal" ? arm.caseInsensitive : arm.kind === "keywords" && arm.caseInsensitive;
|
|
1680
|
+
const spellings = armCaseInsensitive && !/[^\x00-\x7f]/.test(value) && lexicalIrAsciiCaseStable(family) ? [value] : asciiCaseVariants(value, armCaseInsensitive);
|
|
1681
|
+
const endIsTotal = spellings !== void 0 && (familyHasContextFreeFiniteEnd(family, spellings) || armBoundary !== void 0 && boundaryCoversContinuation(family, armBoundary));
|
|
1682
|
+
if (endIsTotal && spellings !== void 0 && spellings.every((spelling) => lexicalIrAcceptsExact(family, spelling))) {
|
|
1683
|
+
relation = "equal";
|
|
1684
|
+
} else if (familyValues !== void 0 && (family.kind === "literal" || family.kind === "keywords" && family.boundary === void 0) && foldedArm === foldedFamily && familyValues.some((full) => {
|
|
1685
|
+
const a = foldedArm ? foldAscii(value) : value;
|
|
1686
|
+
const f = foldedFamily ? foldAscii(full) : full;
|
|
1687
|
+
if (!f.startsWith(a) || f.length === a.length) return false;
|
|
1688
|
+
if (arm.kind !== "keywords" || arm.boundary === void 0) return true;
|
|
1689
|
+
try {
|
|
1690
|
+
return !new RegExp(`[${arm.boundary}]`).test(full[a.length]);
|
|
1691
|
+
} catch {
|
|
1692
|
+
return false;
|
|
1693
|
+
}
|
|
1694
|
+
})) relation = "prefix";
|
|
1695
|
+
if (relation === void 0) return void 0;
|
|
1696
|
+
const ir = arm.kind === "keywords" ? { ...arm, words: [value] } : arm.kind === "literal" ? { ...arm, value } : (() => {
|
|
1697
|
+
throw new Error("parseman: finite decision view lost its language");
|
|
1698
|
+
})();
|
|
1699
|
+
views.push({ ir, relation });
|
|
1700
|
+
}
|
|
1701
|
+
return views;
|
|
1702
|
+
}
|
|
1703
|
+
function balancedSpecOf(parser) {
|
|
1704
|
+
let current = parser;
|
|
1705
|
+
let spec = current._balancedSpec;
|
|
1706
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1707
|
+
while (spec === void 0 && current._def.tag === "token" && !seen.has(current)) {
|
|
1708
|
+
seen.add(current);
|
|
1709
|
+
current = current._def.parser;
|
|
1710
|
+
spec = current._balancedSpec;
|
|
1711
|
+
}
|
|
1712
|
+
return spec;
|
|
1713
|
+
}
|
|
1714
|
+
function ownedScanConsumers(root, initialContext, contextKeyOf, isSeparateOccurrence, resolve) {
|
|
1715
|
+
const out = [];
|
|
1716
|
+
const stack = /* @__PURE__ */ new Set();
|
|
1717
|
+
const walk = (parser, path, first, context) => {
|
|
1718
|
+
if (stack.has(parser)) return;
|
|
1719
|
+
const def = parser._def;
|
|
1720
|
+
const contextKey = contextKeyOf(context);
|
|
1721
|
+
if (!first && isSeparateOccurrence(parser, contextKey)) return;
|
|
1722
|
+
let childContext = context;
|
|
1723
|
+
if (def.tag === "grammar") childContext = {
|
|
1724
|
+
trivia: def.clearTrivia ? void 0 : def.triviaParser ?? context.trivia,
|
|
1725
|
+
scanSkip: context.scanSkip,
|
|
1726
|
+
trackLines: context.trackLines || def.trackLines,
|
|
1727
|
+
captureTrivia: context.captureTrivia || def.captureTrivia === true,
|
|
1728
|
+
opaqueRootCapture: context.opaqueRootCapture || def.rootCapture === "opaque",
|
|
1729
|
+
dynamicState: context.dynamicState
|
|
1730
|
+
};
|
|
1731
|
+
else if (def.tag === "withCtx") childContext = { ...context, dynamicState: true };
|
|
1732
|
+
else if (def.tag === "token") childContext = { ...context, trivia: void 0 };
|
|
1733
|
+
else if (def.tag === "trivia") childContext = { ...context, trivia: void 0 };
|
|
1734
|
+
const balanced = balancedSpecOf(parser);
|
|
1735
|
+
if (balanced !== void 0) {
|
|
1736
|
+
out.push({
|
|
1737
|
+
path,
|
|
1738
|
+
contextKey: contextKeyOf(childContext),
|
|
1739
|
+
context: childContext,
|
|
1740
|
+
kind: "balanced",
|
|
1741
|
+
raw: balanced.raw,
|
|
1742
|
+
ownSkip: balanced.ownSkip
|
|
1743
|
+
});
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
if (def.tag === "scanTo") {
|
|
1747
|
+
out.push({
|
|
1748
|
+
path,
|
|
1749
|
+
contextKey,
|
|
1750
|
+
context,
|
|
1751
|
+
kind: "scanTo",
|
|
1752
|
+
raw: def.raw,
|
|
1753
|
+
ownSkip: def.raw ? [] : def.skip
|
|
1754
|
+
});
|
|
1755
|
+
return;
|
|
1756
|
+
}
|
|
1757
|
+
stack.add(parser);
|
|
1758
|
+
const children = tokenChildren(parser, resolve);
|
|
1759
|
+
for (let i = 0; i < children.length; i++) {
|
|
1760
|
+
walk(children[i], `${path}/${i}`, false, childContext);
|
|
1761
|
+
}
|
|
1762
|
+
stack.delete(parser);
|
|
1763
|
+
};
|
|
1764
|
+
walk(root, "", true, initialContext);
|
|
1765
|
+
return out;
|
|
1766
|
+
}
|
|
1767
|
+
function containsDynamicScanConsumer(root, resolve, seen = /* @__PURE__ */ new Set()) {
|
|
1768
|
+
if (seen.has(root)) return false;
|
|
1769
|
+
if (balancedSpecOf(root) !== void 0 || root._def.tag === "scanTo") return true;
|
|
1770
|
+
seen.add(root);
|
|
1771
|
+
for (const child of tokenChildren(root, resolve)) {
|
|
1772
|
+
if (containsDynamicScanConsumer(child, resolve, seen)) return true;
|
|
1773
|
+
}
|
|
1774
|
+
return false;
|
|
1775
|
+
}
|
|
1776
|
+
function predicateViews(def) {
|
|
1777
|
+
const out = [];
|
|
1778
|
+
let armId = 0;
|
|
1779
|
+
for (const entry of def.cases) {
|
|
1780
|
+
for (const value of entry.keys) out.push({
|
|
1781
|
+
match: { kind: "exact", values: [value], caseInsensitive: entry.caseInsensitive },
|
|
1782
|
+
armId,
|
|
1783
|
+
parser: entry.parser,
|
|
1784
|
+
usesRouted: branchUsesRouted(entry)
|
|
1785
|
+
});
|
|
1786
|
+
armId++;
|
|
1787
|
+
}
|
|
1788
|
+
for (const entry of def.matchers ?? []) {
|
|
1789
|
+
out.push({
|
|
1790
|
+
match: entry.kind === "matches" ? { kind: "matches", value: entry.value, flags: entry.flags ?? "", caseInsensitive: entry.caseInsensitive } : { kind: entry.kind, value: entry.value, caseInsensitive: entry.caseInsensitive },
|
|
1791
|
+
armId,
|
|
1792
|
+
parser: entry.parser,
|
|
1793
|
+
usesRouted: branchUsesRouted(entry)
|
|
1794
|
+
});
|
|
1795
|
+
armId++;
|
|
1796
|
+
}
|
|
1797
|
+
return out;
|
|
1798
|
+
}
|
|
1799
|
+
function predicatePartitionStableFor(ir, predicates) {
|
|
1800
|
+
const folded = ir.kind === "literal" ? ir.caseInsensitive : ir.kind === "keywords" && ir.caseInsensitive;
|
|
1801
|
+
const values = finiteLexicalValues(ir) ?? [];
|
|
1802
|
+
if (!folded) return true;
|
|
1803
|
+
if (values.some((value) => /[^\x00-\x7f]/.test(value))) return false;
|
|
1804
|
+
if (!values.some((value) => /[A-Za-z]/.test(value))) return true;
|
|
1805
|
+
return predicates.every((match) => {
|
|
1806
|
+
if (match.kind === "matches") return match.caseInsensitive || match.flags.includes("i");
|
|
1807
|
+
if (match.kind === "exact") return match.caseInsensitive || match.values.every((value) => !/[A-Za-z]/.test(value));
|
|
1808
|
+
return match.caseInsensitive || !/[A-Za-z]/.test(match.value);
|
|
1809
|
+
});
|
|
1810
|
+
}
|
|
1811
|
+
function lexicalCapabilityCandidates(roots, resolve) {
|
|
1812
|
+
const parserIds = /* @__PURE__ */ new Map();
|
|
1813
|
+
const parserId = (parser) => {
|
|
1814
|
+
const prior = parserIds.get(parser);
|
|
1815
|
+
if (prior !== void 0) return prior;
|
|
1816
|
+
const id = parserIds.size;
|
|
1817
|
+
parserIds.set(parser, id);
|
|
1818
|
+
return id;
|
|
1819
|
+
};
|
|
1820
|
+
const contextKeyOf = (context) => `t${context.trivia === void 0 ? -1 : parserId(context.trivia)}/s${context.scanSkip.map(parserId).join(",")}/l${context.trackLines ? 1 : 0}/c${context.captureTrivia ? 1 : 0}/r${context.opaqueRootCapture ? 1 : 0}/d${context.dynamicState ? 1 : 0}`;
|
|
1821
|
+
const topPath = /* @__PURE__ */ new Map();
|
|
1822
|
+
const ownedPath = /* @__PURE__ */ new Map();
|
|
1823
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
1824
|
+
const bindingEdges = /* @__PURE__ */ new Map();
|
|
1825
|
+
const contexts = /* @__PURE__ */ new Map();
|
|
1826
|
+
const visit = (parser, path, owned, context) => {
|
|
1827
|
+
const contextKey = contextKeyOf(context);
|
|
1828
|
+
if (!contexts.has(contextKey)) contexts.set(contextKey, context);
|
|
1829
|
+
const seen = owned ? ownedPath : topPath;
|
|
1830
|
+
let paths = seen.get(parser);
|
|
1831
|
+
if (paths === void 0) {
|
|
1832
|
+
paths = /* @__PURE__ */ new Map();
|
|
1833
|
+
seen.set(parser, paths);
|
|
1834
|
+
}
|
|
1835
|
+
const prior = paths.get(contextKey);
|
|
1836
|
+
if (prior !== void 0 && prior <= path) return;
|
|
1837
|
+
paths.set(contextKey, path);
|
|
1838
|
+
const def = parser._def;
|
|
1839
|
+
const recognitionContext = def.tag === "token" ? { ...context, trivia: void 0, captureTrivia: false } : context;
|
|
1840
|
+
const recognitionContextKey = contextKeyOf(recognitionContext);
|
|
1841
|
+
if (!owned && keyOf(def) !== void 0) {
|
|
1842
|
+
const key = `terminal\0${parserId(parser)}\0${contextKey}`;
|
|
1843
|
+
const priorCandidate = candidates.get(key);
|
|
1844
|
+
if (priorCandidate === void 0 || path < priorCandidate.path) {
|
|
1845
|
+
candidates.set(key, {
|
|
1846
|
+
bodyId: parserId(parser),
|
|
1847
|
+
parser,
|
|
1848
|
+
atom: "terminal",
|
|
1849
|
+
path,
|
|
1850
|
+
context,
|
|
1851
|
+
contextKey,
|
|
1852
|
+
recognitionContextKey
|
|
1853
|
+
});
|
|
1854
|
+
}
|
|
1855
|
+
} else if (!owned && (def.tag === "token" || def.tag === "choice" || def.tag === "dispatch")) {
|
|
1856
|
+
const atom = def.tag;
|
|
1857
|
+
const key = `${atom}\0${parserId(parser)}\0${contextKey}`;
|
|
1858
|
+
const priorCandidate = candidates.get(key);
|
|
1859
|
+
if (priorCandidate === void 0 || path < priorCandidate.path) {
|
|
1860
|
+
candidates.set(key, {
|
|
1861
|
+
bodyId: parserId(parser),
|
|
1862
|
+
parser,
|
|
1863
|
+
atom,
|
|
1864
|
+
path,
|
|
1865
|
+
context,
|
|
1866
|
+
contextKey,
|
|
1867
|
+
recognitionContextKey
|
|
1868
|
+
});
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
if (!owned && def.tag === "token") return;
|
|
1872
|
+
const childOwned = owned || def.tag === "token";
|
|
1873
|
+
const children = tokenChildren(parser, resolve);
|
|
1874
|
+
let childContext = context;
|
|
1875
|
+
if (def.tag === "grammar") {
|
|
1876
|
+
childContext = {
|
|
1877
|
+
trivia: def.clearTrivia ? void 0 : def.triviaParser ?? context.trivia,
|
|
1878
|
+
scanSkip: context.scanSkip,
|
|
1879
|
+
trackLines: context.trackLines || def.trackLines,
|
|
1880
|
+
captureTrivia: context.captureTrivia || def.captureTrivia === true,
|
|
1881
|
+
opaqueRootCapture: context.opaqueRootCapture || def.rootCapture === "opaque",
|
|
1882
|
+
dynamicState: context.dynamicState
|
|
1883
|
+
};
|
|
1884
|
+
} else if (def.tag === "withCtx") {
|
|
1885
|
+
childContext = { ...context, dynamicState: true };
|
|
1886
|
+
} else if (def.tag === "token") {
|
|
1887
|
+
childContext = { ...context, trivia: void 0 };
|
|
1888
|
+
}
|
|
1889
|
+
for (let i = 0; i < children.length; i++) {
|
|
1890
|
+
const child = children[i];
|
|
1891
|
+
const childPath = `${path}/${String(i).padStart(4, "0")}`;
|
|
1892
|
+
const edgeKey = `${parserId(parser)}\0${i}\0${contextKey}`;
|
|
1893
|
+
if (!bindingEdges.has(edgeKey)) bindingEdges.set(edgeKey, {
|
|
1894
|
+
path: childPath,
|
|
1895
|
+
contextKey,
|
|
1896
|
+
childContextKey: contextKeyOf(childContext),
|
|
1897
|
+
parentTag: def.tag,
|
|
1898
|
+
childTag: child._def.tag,
|
|
1899
|
+
parentBodyId: parserId(parser),
|
|
1900
|
+
childBodyId: parserId(child),
|
|
1901
|
+
childOrdinal: i
|
|
1902
|
+
});
|
|
1903
|
+
visit(child, childPath, childOwned, childContext);
|
|
1904
|
+
}
|
|
1905
|
+
};
|
|
1906
|
+
for (let i = 0; i < roots.length; i++) {
|
|
1907
|
+
const root = roots[i];
|
|
1908
|
+
const rootPath = String(i).padStart(4, "0");
|
|
1909
|
+
const rootContext = {
|
|
1910
|
+
trivia: root._meta.grammarTrivia,
|
|
1911
|
+
scanSkip: root._meta.grammarScanSkip ?? [],
|
|
1912
|
+
trackLines: root._meta.grammarTrackLines === true,
|
|
1913
|
+
captureTrivia: false,
|
|
1914
|
+
opaqueRootCapture: false,
|
|
1915
|
+
dynamicState: false
|
|
1916
|
+
};
|
|
1917
|
+
const contextKey = contextKeyOf(rootContext);
|
|
1918
|
+
bindingEdges.set(`root\0${i}\0${contextKey}`, {
|
|
1919
|
+
path: rootPath,
|
|
1920
|
+
contextKey,
|
|
1921
|
+
childContextKey: contextKey,
|
|
1922
|
+
parentTag: "root",
|
|
1923
|
+
childTag: root._def.tag,
|
|
1924
|
+
parentBodyId: -1 - i,
|
|
1925
|
+
childBodyId: parserId(root),
|
|
1926
|
+
childOrdinal: i
|
|
1927
|
+
});
|
|
1928
|
+
visit(root, rootPath, false, rootContext);
|
|
1929
|
+
}
|
|
1930
|
+
return {
|
|
1931
|
+
candidates: [...candidates.values()].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : a.atom < b.atom ? -1 : a.atom > b.atom ? 1 : 0),
|
|
1932
|
+
bindingEdges: [...bindingEdges.values()].sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0),
|
|
1933
|
+
contexts,
|
|
1934
|
+
contextKeyOf
|
|
1935
|
+
};
|
|
1936
|
+
}
|
|
1937
|
+
function decisionViewKey(view) {
|
|
1938
|
+
if (view.kind === "whole") return "whole";
|
|
1939
|
+
if (view.kind === "predicate") return `predicate\0${canonicalLexicalOutcomeKey(view.match)}`;
|
|
1940
|
+
return `language\0${view.relation}\0${JSON.stringify(view.ir)}`;
|
|
1941
|
+
}
|
|
1942
|
+
function lexicalDecisionInventory(candidates, contextSnapshotIdByKey, resolve) {
|
|
1943
|
+
const familyIrByKey = /* @__PURE__ */ new Map();
|
|
1944
|
+
const viewsByKey = /* @__PURE__ */ new Map();
|
|
1945
|
+
const pending = [];
|
|
1946
|
+
const addFamily = (lead) => {
|
|
1947
|
+
if (!familyIrByKey.has(lead.key)) familyIrByKey.set(lead.key, lead.ir);
|
|
1948
|
+
return lead.key;
|
|
1949
|
+
};
|
|
1950
|
+
const addView = (familyKey, view) => {
|
|
1951
|
+
const key = `${familyKey}\0${decisionViewKey(view)}`;
|
|
1952
|
+
if (!viewsByKey.has(key)) viewsByKey.set(key, { familyKey, key, view });
|
|
1953
|
+
return key;
|
|
1954
|
+
};
|
|
1955
|
+
const reuseEpochsForChoice = (arms) => {
|
|
1956
|
+
const epochs = [];
|
|
1957
|
+
let pure = [];
|
|
1958
|
+
const flushPure = () => {
|
|
1959
|
+
if (pure.length === 0) return;
|
|
1960
|
+
epochs.push({ armIds: pure, pendingReuse: "unproved", boundary: "none" });
|
|
1961
|
+
pure = [];
|
|
1962
|
+
};
|
|
1963
|
+
for (let armId = 0; armId < arms.length; armId++) {
|
|
1964
|
+
if (!containsDynamicScanConsumer(arms[armId], resolve)) {
|
|
1965
|
+
pure.push(armId);
|
|
1966
|
+
continue;
|
|
1967
|
+
}
|
|
1968
|
+
flushPure();
|
|
1969
|
+
epochs.push({ armIds: [armId], pendingReuse: "forbidden", boundary: "dynamic-scan" });
|
|
1970
|
+
}
|
|
1971
|
+
flushPure();
|
|
1972
|
+
return epochs;
|
|
1973
|
+
};
|
|
1974
|
+
for (const candidate of candidates) {
|
|
1975
|
+
const def = candidate.parser._def;
|
|
1976
|
+
if (candidate.atom !== "terminal" && candidate.atom !== "token") continue;
|
|
1977
|
+
const normalized = normalizeBalancedLexical(candidate.parser, resolve) ?? normalizeLexical(def.tag === "token" ? def.parser : candidate.parser, resolve, /* @__PURE__ */ new Set());
|
|
1978
|
+
if (!("refusal" in normalized)) familyIrByKey.set(JSON.stringify(normalized.ir), normalized.ir);
|
|
1979
|
+
}
|
|
1980
|
+
for (let siteId = 0; siteId < candidates.length; siteId++) {
|
|
1981
|
+
const candidate = candidates[siteId];
|
|
1982
|
+
if (candidate.atom !== "choice" && candidate.atom !== "dispatch") continue;
|
|
1983
|
+
const def = candidate.parser._def;
|
|
1984
|
+
const precisionNotes = [];
|
|
1985
|
+
const contextSnapshotId = contextSnapshotIdByKey.get(candidate.contextKey);
|
|
1986
|
+
if (contextSnapshotId === void 0) throw new Error("parseman: decision occurrence lost its context snapshot");
|
|
1987
|
+
const dynamicScan = candidate.atom === "dispatch" && def.tag === "dispatch" ? containsDynamicScanConsumer(def.selector, resolve) : containsDynamicScanConsumer(candidate.parser, resolve);
|
|
1988
|
+
if (dynamicScan) {
|
|
1989
|
+
precisionNotes.push("dynamic scan consumer forbids pending range reuse");
|
|
1990
|
+
}
|
|
1991
|
+
if (candidate.atom === "dispatch" && dynamicScan) {
|
|
1992
|
+
pending.push({
|
|
1993
|
+
siteId,
|
|
1994
|
+
atom: candidate.atom,
|
|
1995
|
+
path: candidate.path,
|
|
1996
|
+
contextKey: candidate.contextKey,
|
|
1997
|
+
contextSnapshotId,
|
|
1998
|
+
families: [],
|
|
1999
|
+
pendingReuse: "forbidden",
|
|
2000
|
+
reuseEpochs: [{
|
|
2001
|
+
armIds: def.tag === "dispatch" ? Array.from({ length: def.cases.length + (def.matchers?.length ?? 0) + (def.otherwise === void 0 ? 0 : 1) }, (_, armId) => armId) : [],
|
|
2002
|
+
pendingReuse: "forbidden",
|
|
2003
|
+
boundary: "dynamic-scan"
|
|
2004
|
+
}],
|
|
2005
|
+
precisionNotes
|
|
2006
|
+
});
|
|
2007
|
+
continue;
|
|
2008
|
+
}
|
|
2009
|
+
if (candidate.atom === "dispatch") {
|
|
2010
|
+
if (def.tag !== "dispatch") throw new Error("parseman: decision occurrence lost its dispatch");
|
|
2011
|
+
const routeUsesRouted = [
|
|
2012
|
+
...def.cases.map(branchUsesRouted),
|
|
2013
|
+
...(def.matchers ?? []).map(branchUsesRouted),
|
|
2014
|
+
...def.otherwise === void 0 ? [] : [branchUsesRouted({
|
|
2015
|
+
parser: def.otherwise,
|
|
2016
|
+
usesRouted: def.otherwiseUsesRouted
|
|
2017
|
+
})]
|
|
2018
|
+
];
|
|
2019
|
+
const result = decisionLead(def.selector, candidate.context, resolve);
|
|
2020
|
+
if ("gap" in result) {
|
|
2021
|
+
precisionNotes.push(`selector: ${result.gap}`);
|
|
2022
|
+
pending.push({
|
|
2023
|
+
siteId,
|
|
2024
|
+
atom: candidate.atom,
|
|
2025
|
+
path: candidate.path,
|
|
2026
|
+
contextKey: candidate.contextKey,
|
|
2027
|
+
contextSnapshotId,
|
|
2028
|
+
families: [],
|
|
2029
|
+
precisionNotes,
|
|
2030
|
+
pendingReuse: "unproved",
|
|
2031
|
+
reuseEpochs: [{
|
|
2032
|
+
armIds: Array.from({ length: def.cases.length + (def.matchers?.length ?? 0) + (def.otherwise === void 0 ? 0 : 1) }, (_, armId) => armId),
|
|
2033
|
+
pendingReuse: "unproved",
|
|
2034
|
+
boundary: "none"
|
|
2035
|
+
}],
|
|
2036
|
+
routeUsesRouted
|
|
2037
|
+
});
|
|
2038
|
+
continue;
|
|
2039
|
+
}
|
|
2040
|
+
const familyKey = addFamily(result.lead);
|
|
2041
|
+
const predicates = predicateViews(def);
|
|
2042
|
+
const predicateKeys = predicates.map(({ match }) => addView(familyKey, {
|
|
2043
|
+
kind: "predicate",
|
|
2044
|
+
relation: "equal",
|
|
2045
|
+
match
|
|
2046
|
+
}));
|
|
2047
|
+
const arms = [];
|
|
2048
|
+
let offset = 0;
|
|
2049
|
+
for (let armId = 0; armId < def.cases.length; armId++) {
|
|
2050
|
+
const entry = def.cases[armId];
|
|
2051
|
+
const keys = predicateKeys.slice(offset, offset + entry.keys.length);
|
|
2052
|
+
offset += entry.keys.length;
|
|
2053
|
+
arms.push({
|
|
2054
|
+
armId,
|
|
2055
|
+
acceptance: { kind: "outcomes", keys },
|
|
2056
|
+
usesRouted: branchUsesRouted(entry),
|
|
2057
|
+
dynamicGate: false
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
2060
|
+
for (let i = 0; i < (def.matchers?.length ?? 0); i++) {
|
|
2061
|
+
const entry = def.matchers[i];
|
|
2062
|
+
arms.push({
|
|
2063
|
+
armId: arms.length,
|
|
2064
|
+
acceptance: { kind: "outcomes", keys: [predicateKeys[offset++]] },
|
|
2065
|
+
usesRouted: branchUsesRouted(entry),
|
|
2066
|
+
dynamicGate: false
|
|
2067
|
+
});
|
|
2068
|
+
}
|
|
2069
|
+
if (def.otherwise !== void 0) arms.push({
|
|
2070
|
+
armId: arms.length,
|
|
2071
|
+
acceptance: { kind: "otherwise", excludingKeys: predicateKeys },
|
|
2072
|
+
usesRouted: branchUsesRouted({ parser: def.otherwise, usesRouted: def.otherwiseUsesRouted }),
|
|
2073
|
+
dynamicGate: false
|
|
2074
|
+
});
|
|
2075
|
+
pending.push({
|
|
2076
|
+
siteId,
|
|
2077
|
+
atom: candidate.atom,
|
|
2078
|
+
path: candidate.path,
|
|
2079
|
+
contextKey: candidate.contextKey,
|
|
2080
|
+
contextSnapshotId,
|
|
2081
|
+
families: [{ familyKey, arms }],
|
|
2082
|
+
precisionNotes,
|
|
2083
|
+
pendingReuse: dynamicScan ? "forbidden" : "unproved",
|
|
2084
|
+
reuseEpochs: [{
|
|
2085
|
+
armIds: arms.map((arm) => arm.armId),
|
|
2086
|
+
pendingReuse: dynamicScan ? "forbidden" : "unproved",
|
|
2087
|
+
boundary: dynamicScan ? "dynamic-scan" : "none"
|
|
2088
|
+
}],
|
|
2089
|
+
routeUsesRouted
|
|
2090
|
+
});
|
|
2091
|
+
continue;
|
|
2092
|
+
}
|
|
2093
|
+
if (def.tag !== "choice") throw new Error("parseman: decision occurrence lost its choice");
|
|
2094
|
+
const leads = def.parsers.map((arm, armId) => {
|
|
2095
|
+
const result = decisionLead(arm, candidate.context, resolve);
|
|
2096
|
+
if ("gap" in result) precisionNotes.push(`arm ${armId}: ${result.gap}`);
|
|
2097
|
+
return result;
|
|
2098
|
+
});
|
|
2099
|
+
const familyKeys2 = [...new Set(leads.flatMap((result) => "lead" in result ? [addFamily(result.lead)] : []))].sort();
|
|
2100
|
+
if (familyKeys2.length === 0 && precisionNotes.length === 0) {
|
|
2101
|
+
precisionNotes.push("choice has no predecision range family; all arms remain unrestricted");
|
|
2102
|
+
}
|
|
2103
|
+
const families2 = familyKeys2.map((familyKey) => {
|
|
2104
|
+
const familyIr = familyIrByKey.get(familyKey);
|
|
2105
|
+
const wholeKey = addView(familyKey, { kind: "whole", relation: "equal" });
|
|
2106
|
+
const familyDispatches = [...new Set(leads.flatMap((result) => "lead" in result && result.lead.key === familyKey && result.lead.dispatch !== void 0 ? [result.lead.dispatch] : []))];
|
|
2107
|
+
const ambiguousPartition = familyDispatches.length > 1;
|
|
2108
|
+
if (ambiguousPartition) precisionNotes.push(
|
|
2109
|
+
`family ${familyKey}: multiple dispatches need distinct site-local outcome partitions`
|
|
2110
|
+
);
|
|
2111
|
+
const familyPredicates = ambiguousPartition ? [] : familyDispatches.flatMap((dispatch) => predicateViews(dispatch).map((entry) => entry.match));
|
|
2112
|
+
const predicateKeys = familyPredicates.map((match) => addView(familyKey, {
|
|
2113
|
+
kind: "predicate",
|
|
2114
|
+
relation: "equal",
|
|
2115
|
+
match
|
|
2116
|
+
}));
|
|
2117
|
+
const arms = def.parsers.map((arm, armId) => {
|
|
2118
|
+
const dynamicGate = def.gates[armId] !== null || def.autoNot[armId] !== null;
|
|
2119
|
+
const result = leads[armId];
|
|
2120
|
+
if ("gap" in result) return {
|
|
2121
|
+
armId,
|
|
2122
|
+
acceptance: { kind: "unrestricted" },
|
|
2123
|
+
usesRouted: false,
|
|
2124
|
+
dynamicGate
|
|
2125
|
+
};
|
|
2126
|
+
const lead = result.lead;
|
|
2127
|
+
if (lead.key === familyKey) {
|
|
2128
|
+
if (ambiguousPartition) return {
|
|
2129
|
+
armId,
|
|
2130
|
+
acceptance: { kind: "unrestricted" },
|
|
2131
|
+
usesRouted: false,
|
|
2132
|
+
dynamicGate
|
|
2133
|
+
};
|
|
2134
|
+
if (lead.dispatch !== void 0) {
|
|
2135
|
+
const predicates = predicateViews(lead.dispatch);
|
|
2136
|
+
const keys = predicates.map(({ match }) => addView(familyKey, {
|
|
2137
|
+
kind: "predicate",
|
|
2138
|
+
relation: "equal",
|
|
2139
|
+
match
|
|
2140
|
+
}));
|
|
2141
|
+
return {
|
|
2142
|
+
armId,
|
|
2143
|
+
acceptance: lead.dispatch.otherwise === void 0 ? { kind: "outcomes", keys } : { kind: "unrestricted" },
|
|
2144
|
+
usesRouted: false,
|
|
2145
|
+
dynamicGate
|
|
2146
|
+
};
|
|
2147
|
+
}
|
|
2148
|
+
return {
|
|
2149
|
+
armId,
|
|
2150
|
+
acceptance: { kind: "outcomes", keys: [wholeKey] },
|
|
2151
|
+
usesRouted: false,
|
|
2152
|
+
dynamicGate
|
|
2153
|
+
};
|
|
2154
|
+
}
|
|
2155
|
+
const familyLead = leads.find((entry) => "lead" in entry && entry.lead.key === familyKey).lead;
|
|
2156
|
+
const armFirst = firstSetOf(arm, /* @__PURE__ */ new Set(), resolve);
|
|
2157
|
+
const familyFirst = firstSetOf(familyLead.parser, /* @__PURE__ */ new Set(), resolve);
|
|
2158
|
+
if (armFirst.kind === "ranges" && familyFirst.kind === "ranges" && !intersects(armFirst, familyFirst)) {
|
|
2159
|
+
return { armId, acceptance: { kind: "impossible" }, usesRouted: false, dynamicGate };
|
|
2160
|
+
}
|
|
2161
|
+
const compatible = compatibleLanguageViews(lead.ir, familyIr);
|
|
2162
|
+
if (compatible !== void 0) {
|
|
2163
|
+
if (compatible.every((view) => view.relation === "equal") && familyPredicates.length > 0 && predicatePartitionStableFor(lead.ir, familyPredicates)) {
|
|
2164
|
+
const values = finiteLexicalValues(lead.ir);
|
|
2165
|
+
const accepted = /* @__PURE__ */ new Set();
|
|
2166
|
+
let hasOtherwise = false;
|
|
2167
|
+
for (const value of values) {
|
|
2168
|
+
const matching = familyPredicates.flatMap((match, index) => lexicalOutcomeMatches(match, value, 0, value.length) ? [predicateKeys[index]] : []);
|
|
2169
|
+
if (matching.length === 0) hasOtherwise = true;
|
|
2170
|
+
else for (const key of matching) accepted.add(key);
|
|
2171
|
+
}
|
|
2172
|
+
if (hasOtherwise && accepted.size === 0) return {
|
|
2173
|
+
armId,
|
|
2174
|
+
acceptance: { kind: "otherwise", excludingKeys: predicateKeys },
|
|
2175
|
+
usesRouted: false,
|
|
2176
|
+
dynamicGate
|
|
2177
|
+
};
|
|
2178
|
+
if (!hasOtherwise && accepted.size > 0) return {
|
|
2179
|
+
armId,
|
|
2180
|
+
acceptance: { kind: "outcomes", keys: [...accepted] },
|
|
2181
|
+
usesRouted: false,
|
|
2182
|
+
dynamicGate
|
|
2183
|
+
};
|
|
2184
|
+
return { armId, acceptance: { kind: "unrestricted" }, usesRouted: false, dynamicGate };
|
|
2185
|
+
}
|
|
2186
|
+
const keys = compatible.map((view) => addView(familyKey, {
|
|
2187
|
+
kind: "language",
|
|
2188
|
+
relation: view.relation,
|
|
2189
|
+
ir: view.ir
|
|
2190
|
+
}));
|
|
2191
|
+
return {
|
|
2192
|
+
armId,
|
|
2193
|
+
acceptance: { kind: "outcomes", keys },
|
|
2194
|
+
usesRouted: false,
|
|
2195
|
+
dynamicGate
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2198
|
+
return { armId, acceptance: { kind: "unrestricted" }, usesRouted: false, dynamicGate };
|
|
2199
|
+
});
|
|
2200
|
+
return { familyKey, arms };
|
|
2201
|
+
});
|
|
2202
|
+
pending.push({
|
|
2203
|
+
siteId,
|
|
2204
|
+
atom: candidate.atom,
|
|
2205
|
+
path: candidate.path,
|
|
2206
|
+
contextKey: candidate.contextKey,
|
|
2207
|
+
contextSnapshotId,
|
|
2208
|
+
families: families2,
|
|
2209
|
+
precisionNotes: [...new Set(precisionNotes)].sort(),
|
|
2210
|
+
pendingReuse: dynamicScan ? "forbidden" : "unproved",
|
|
2211
|
+
reuseEpochs: reuseEpochsForChoice(def.parsers)
|
|
2212
|
+
});
|
|
2213
|
+
}
|
|
2214
|
+
const familyKeys = [...familyIrByKey.keys()].sort();
|
|
2215
|
+
const familyIdByKey = new Map(familyKeys.map((key, index) => [key, FIRST_LEXICAL_FAMILY_ID + index]));
|
|
2216
|
+
const families = familyKeys.map((semanticKey, index) => ({
|
|
2217
|
+
id: FIRST_LEXICAL_FAMILY_ID + index,
|
|
2218
|
+
semanticKey,
|
|
2219
|
+
ir: familyIrByKey.get(semanticKey)
|
|
2220
|
+
}));
|
|
2221
|
+
const viewKeys = [...viewsByKey.keys()].sort();
|
|
2222
|
+
const firstOutcomeId = FIRST_LEXICAL_FAMILY_ID + familyKeys.length;
|
|
2223
|
+
const outcomeIdByKey = new Map(viewKeys.map((key, index) => [key, firstOutcomeId + index]));
|
|
2224
|
+
const outcomes = viewKeys.map((key, index) => {
|
|
2225
|
+
const pendingView = viewsByKey.get(key);
|
|
2226
|
+
return {
|
|
2227
|
+
id: firstOutcomeId + index,
|
|
2228
|
+
familyId: familyIdByKey.get(pendingView.familyKey),
|
|
2229
|
+
semanticKey: decisionViewKey(pendingView.view),
|
|
2230
|
+
view: pendingView.view
|
|
2231
|
+
};
|
|
2232
|
+
});
|
|
2233
|
+
const decisions = pending.map((site) => ({
|
|
2234
|
+
siteId: site.siteId,
|
|
2235
|
+
atom: site.atom,
|
|
2236
|
+
path: site.path,
|
|
2237
|
+
contextKey: site.contextKey,
|
|
2238
|
+
contextSnapshotId: site.contextSnapshotId,
|
|
2239
|
+
fallback: "unrestricted",
|
|
2240
|
+
precisionNotes: site.precisionNotes,
|
|
2241
|
+
pendingReuse: site.pendingReuse,
|
|
2242
|
+
reuseEpochs: site.reuseEpochs,
|
|
2243
|
+
...site.routeUsesRouted === void 0 ? {} : { routeUsesRouted: site.routeUsesRouted },
|
|
2244
|
+
families: site.families.map((family) => ({
|
|
2245
|
+
familyId: familyIdByKey.get(family.familyKey),
|
|
2246
|
+
arms: family.arms.map((arm) => ({
|
|
2247
|
+
...arm,
|
|
2248
|
+
acceptance: arm.acceptance.kind === "outcomes" ? { kind: "outcomes", outcomeIds: [...new Set(arm.acceptance.keys.map((key) => outcomeIdByKey.get(key)))].sort((a, b) => a - b) } : arm.acceptance.kind === "otherwise" ? { kind: "otherwise", excludingOutcomeIds: [...new Set(arm.acceptance.excludingKeys.map((key) => outcomeIdByKey.get(key)))].sort((a, b) => a - b) } : arm.acceptance
|
|
2249
|
+
}))
|
|
2250
|
+
}))
|
|
2251
|
+
}));
|
|
2252
|
+
const recognitionBySite = new Map(decisions.map((site) => [
|
|
2253
|
+
site.siteId,
|
|
2254
|
+
COMPLETE_CAPABILITY
|
|
2255
|
+
]));
|
|
2256
|
+
return { families, outcomes, decisions, recognitionBySite };
|
|
2257
|
+
}
|
|
2258
|
+
function classifiedLiteralProjection(parser) {
|
|
2259
|
+
let current = parser;
|
|
2260
|
+
const outerFirst = [];
|
|
2261
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2262
|
+
while (!seen.has(current)) {
|
|
2263
|
+
seen.add(current);
|
|
2264
|
+
const def = current._def;
|
|
2265
|
+
if (def.tag === "literal") return { spelling: def.value, transforms: outerFirst.reverse() };
|
|
2266
|
+
if (def.tag === "transform") {
|
|
2267
|
+
outerFirst.push({ fn: def.fn, ...def.fnSrc === void 0 ? {} : { source: def.fnSrc } });
|
|
2268
|
+
current = def.parser;
|
|
2269
|
+
continue;
|
|
2270
|
+
}
|
|
2271
|
+
if (def.tag === "label") {
|
|
2272
|
+
current = def.parser;
|
|
2273
|
+
continue;
|
|
2274
|
+
}
|
|
2275
|
+
return void 0;
|
|
2276
|
+
}
|
|
2277
|
+
return void 0;
|
|
2278
|
+
}
|
|
2279
|
+
function decisionEffectInventory(candidates, decisions, bindingEdges, bindingProjections, resolve) {
|
|
2280
|
+
const finalDecisionAuthorities = [];
|
|
2281
|
+
const decisionEffects = [];
|
|
2282
|
+
const decisionChildEffects = [];
|
|
2283
|
+
const choiceClassAuthorities = [];
|
|
2284
|
+
const choiceExecutionOrders = [];
|
|
2285
|
+
const classifySpellingMaps = [];
|
|
2286
|
+
const classifyProjectionPlans = [];
|
|
2287
|
+
const decisionExpectedAuthorities = [];
|
|
2288
|
+
const decisionCallbackAuthorities = [];
|
|
2289
|
+
const expectedIdByKey = /* @__PURE__ */ new Map();
|
|
2290
|
+
const callbackIds = /* @__PURE__ */ new Map();
|
|
2291
|
+
const sourceIds = /* @__PURE__ */ new Map();
|
|
2292
|
+
const autoNotIds = /* @__PURE__ */ new Map();
|
|
2293
|
+
const edgeByPath = new Map(bindingEdges.map((edge) => [edge.path, edge.id]));
|
|
2294
|
+
const expectedId = (values) => {
|
|
2295
|
+
const key = JSON.stringify(values);
|
|
2296
|
+
const prior = expectedIdByKey.get(key);
|
|
2297
|
+
if (prior !== void 0) return prior;
|
|
2298
|
+
const id = decisionExpectedAuthorities.length;
|
|
2299
|
+
expectedIdByKey.set(key, id);
|
|
2300
|
+
decisionExpectedAuthorities.push({ id, values: [...values] });
|
|
2301
|
+
return id;
|
|
2302
|
+
};
|
|
2303
|
+
const callbackId = (value) => {
|
|
2304
|
+
const prior = callbackIds.get(value);
|
|
2305
|
+
if (prior !== void 0) return prior;
|
|
2306
|
+
const id = decisionCallbackAuthorities.length;
|
|
2307
|
+
callbackIds.set(value, id);
|
|
2308
|
+
decisionCallbackAuthorities.push({ id, callback: value });
|
|
2309
|
+
return id;
|
|
2310
|
+
};
|
|
2311
|
+
const stringId = (map, value) => {
|
|
2312
|
+
const prior = map.get(value);
|
|
2313
|
+
if (prior !== void 0) return prior;
|
|
2314
|
+
const id = map.size;
|
|
2315
|
+
map.set(value, id);
|
|
2316
|
+
return id;
|
|
2317
|
+
};
|
|
2318
|
+
const edgeAt = (path, childIndex) => {
|
|
2319
|
+
const childPath = `${path}/${String(childIndex).padStart(4, "0")}`;
|
|
2320
|
+
const edge = edgeByPath.get(childPath);
|
|
2321
|
+
if (edge === void 0) throw new Error(`parseman: decision child lost binding edge ${childPath}`);
|
|
2322
|
+
return edge;
|
|
2323
|
+
};
|
|
2324
|
+
const childEffect = (siteId, armId, childBindingEdgeId, parser, gate = null, gateSource = null, autoNot = null) => {
|
|
2325
|
+
const id = decisionChildEffects.length;
|
|
2326
|
+
decisionChildEffects.push({
|
|
2327
|
+
id,
|
|
2328
|
+
decisionSiteId: siteId,
|
|
2329
|
+
armId,
|
|
2330
|
+
childBindingEdgeId,
|
|
2331
|
+
expectedAuthorityId: expectedId(deriveExpected(parser)),
|
|
2332
|
+
...gate === null ? {} : { gateCallbackId: callbackId(gate) },
|
|
2333
|
+
...gateSource === null ? {} : { gateSourceId: stringId(sourceIds, gateSource) },
|
|
2334
|
+
...autoNot === null ? {} : { autoNotAuthorityId: stringId(autoNotIds, JSON.stringify(autoNot)) }
|
|
2335
|
+
});
|
|
2336
|
+
return id;
|
|
2337
|
+
};
|
|
2338
|
+
for (const decision of decisions) {
|
|
2339
|
+
const candidate = candidates[decision.siteId];
|
|
2340
|
+
if (candidate === void 0 || candidate.parser._def.tag !== decision.atom) {
|
|
2341
|
+
throw new Error(`parseman: decision effect lost occurrence ${decision.siteId}`);
|
|
2342
|
+
}
|
|
2343
|
+
const def = candidate.parser._def;
|
|
2344
|
+
const authorityId = finalDecisionAuthorities.length;
|
|
2345
|
+
const effectId = decisionEffects.length;
|
|
2346
|
+
let loweringGap;
|
|
2347
|
+
const childEffectIds = [];
|
|
2348
|
+
if (def.tag === "choice") {
|
|
2349
|
+
const finalChoice = classifyFinalChoice(def.parsers, resolve);
|
|
2350
|
+
const authoredArmIds = def.parsers.map((_, armId) => armId);
|
|
2351
|
+
let mode;
|
|
2352
|
+
if (finalChoice.exclusive) {
|
|
2353
|
+
const classAuthorityId = choiceClassAuthorities.length;
|
|
2354
|
+
choiceClassAuthorities.push({
|
|
2355
|
+
id: classAuthorityId,
|
|
2356
|
+
armIds: authoredArmIds,
|
|
2357
|
+
firstSets: finalChoice.firstSets
|
|
2358
|
+
});
|
|
2359
|
+
mode = { kind: "exclusive", classAuthorityId };
|
|
2360
|
+
} else if (def.strategy.tag === "literalsLongestFirst") {
|
|
2361
|
+
const orderAuthorityId = choiceExecutionOrders.length;
|
|
2362
|
+
choiceExecutionOrders.push({
|
|
2363
|
+
id: orderAuthorityId,
|
|
2364
|
+
armIds: [...def.strategy.sortedIndices]
|
|
2365
|
+
});
|
|
2366
|
+
mode = { kind: "longest", orderAuthorityId };
|
|
2367
|
+
} else if (def.strategy.tag === "greedyClassify") {
|
|
2368
|
+
const spellingMapAuthorityId = classifySpellingMaps.length;
|
|
2369
|
+
const projectionAuthorityId = classifyProjectionPlans.length;
|
|
2370
|
+
const spellingEntries = [];
|
|
2371
|
+
const projectionEntries = [];
|
|
2372
|
+
for (let armId = 0; armId < def.parsers.length; armId++) {
|
|
2373
|
+
if (armId === def.strategy.superIndex) continue;
|
|
2374
|
+
const projection = classifiedLiteralProjection(def.parsers[armId]);
|
|
2375
|
+
if (projection === void 0) {
|
|
2376
|
+
throw new Error(`parseman: greedy classifier lost literal arm ${armId}`);
|
|
2377
|
+
}
|
|
2378
|
+
spellingEntries.push({ spelling: projection.spelling, armId });
|
|
2379
|
+
const transformIds = projection.transforms.map((entry) => callbackId(entry.fn));
|
|
2380
|
+
const transformSourceIds = projection.transforms.map((entry) => entry.source === void 0 ? -1 : stringId(sourceIds, entry.source));
|
|
2381
|
+
projectionEntries.push({
|
|
2382
|
+
armId,
|
|
2383
|
+
transformIds,
|
|
2384
|
+
transformSourceIds,
|
|
2385
|
+
transformCount: transformIds.length
|
|
2386
|
+
});
|
|
2387
|
+
if (transformSourceIds.includes(-1)) {
|
|
2388
|
+
loweringGap = "classified transform has no statically named reader projection";
|
|
2389
|
+
}
|
|
2390
|
+
}
|
|
2391
|
+
classifySpellingMaps.push({ id: spellingMapAuthorityId, entries: spellingEntries });
|
|
2392
|
+
classifyProjectionPlans.push({ id: projectionAuthorityId, entries: projectionEntries });
|
|
2393
|
+
mode = {
|
|
2394
|
+
kind: "classify",
|
|
2395
|
+
superArmId: def.strategy.superIndex,
|
|
2396
|
+
spellingMapAuthorityId,
|
|
2397
|
+
projectionAuthorityId
|
|
2398
|
+
};
|
|
2399
|
+
} else mode = { kind: "ordered" };
|
|
2400
|
+
const expectedParsers = mode.kind === "longest" ? mode.orderAuthorityId === void 0 ? def.parsers : choiceExecutionOrders[mode.orderAuthorityId].armIds.map((armId) => def.parsers[armId]) : mode.kind === "classify" ? [def.parsers[mode.superArmId]] : mode.kind === "exclusive" ? def.parsers : void 0;
|
|
2401
|
+
finalDecisionAuthorities.push({
|
|
2402
|
+
id: authorityId,
|
|
2403
|
+
atom: "choice",
|
|
2404
|
+
decisionSiteId: decision.siteId,
|
|
2405
|
+
authoredArmIds,
|
|
2406
|
+
mode,
|
|
2407
|
+
...expectedParsers === void 0 ? {} : {
|
|
2408
|
+
staticMissExpectedAuthorityId: expectedId(
|
|
2409
|
+
expectedParsers.flatMap((parser) => deriveExpected(parser))
|
|
2410
|
+
)
|
|
2411
|
+
}
|
|
2412
|
+
});
|
|
2413
|
+
for (let armId = 0; armId < def.parsers.length; armId++) {
|
|
2414
|
+
const gate = def.gates[armId] ?? null;
|
|
2415
|
+
const gateSource = def.gateSrcs?.[armId] ?? null;
|
|
2416
|
+
if (gate !== null && gateSource === null) {
|
|
2417
|
+
loweringGap = "dynamic choice gate has no statically named reader projection";
|
|
2418
|
+
}
|
|
2419
|
+
childEffectIds.push(childEffect(
|
|
2420
|
+
decision.siteId,
|
|
2421
|
+
armId,
|
|
2422
|
+
edgeAt(candidate.path, armId),
|
|
2423
|
+
def.parsers[armId],
|
|
2424
|
+
gate,
|
|
2425
|
+
gateSource,
|
|
2426
|
+
def.autoNot[armId]
|
|
2427
|
+
));
|
|
2428
|
+
}
|
|
2429
|
+
} else {
|
|
2430
|
+
const routeParsers = [
|
|
2431
|
+
...def.cases.map((entry) => entry.parser),
|
|
2432
|
+
...(def.matchers ?? []).map((entry) => entry.parser),
|
|
2433
|
+
...def.otherwise === void 0 ? [] : [def.otherwise]
|
|
2434
|
+
];
|
|
2435
|
+
const routeBranches = [
|
|
2436
|
+
...def.cases,
|
|
2437
|
+
...def.matchers ?? [],
|
|
2438
|
+
...def.otherwise === void 0 ? [] : [{
|
|
2439
|
+
parser: def.otherwise,
|
|
2440
|
+
usesRouted: def.otherwiseUsesRouted
|
|
2441
|
+
}]
|
|
2442
|
+
];
|
|
2443
|
+
const otherwiseOffset = def.otherwise === void 0 ? 0 : 1;
|
|
2444
|
+
const routeEdgeIndices = [
|
|
2445
|
+
...def.cases.map((_, index) => 1 + otherwiseOffset + index),
|
|
2446
|
+
...(def.matchers ?? []).map((_, index) => 1 + otherwiseOffset + def.cases.length + index),
|
|
2447
|
+
...def.otherwise === void 0 ? [] : [1]
|
|
2448
|
+
];
|
|
2449
|
+
const selectorBindingEdgeId = edgeAt(candidate.path, 0);
|
|
2450
|
+
const orderedRouteIds = routeParsers.map((_, routeId) => routeId);
|
|
2451
|
+
finalDecisionAuthorities.push({
|
|
2452
|
+
id: authorityId,
|
|
2453
|
+
atom: "dispatch",
|
|
2454
|
+
decisionSiteId: decision.siteId,
|
|
2455
|
+
selectorBindingEdgeId,
|
|
2456
|
+
// The Stage-A occurrence owns exact/fold/matcher/otherwise precedence.
|
|
2457
|
+
classifierAuthorityId: decision.siteId,
|
|
2458
|
+
orderedRouteIds,
|
|
2459
|
+
noRouteExpectedAuthorityId: expectedId(def.cases.flatMap((entry) => entry.keys.map((key) => JSON.stringify(key))))
|
|
2460
|
+
});
|
|
2461
|
+
for (let routeId = 0; routeId < routeParsers.length; routeId++) {
|
|
2462
|
+
childEffectIds.push(childEffect(
|
|
2463
|
+
decision.siteId,
|
|
2464
|
+
routeId,
|
|
2465
|
+
edgeAt(candidate.path, routeEdgeIndices[routeId]),
|
|
2466
|
+
routeParsers[routeId]
|
|
2467
|
+
));
|
|
2468
|
+
}
|
|
2469
|
+
const routedAuthority = decision.routeUsesRouted;
|
|
2470
|
+
if (routedAuthority === void 0 || routedAuthority.length !== routeBranches.length || routedAuthority.some((value, index) => value !== branchUsesRouted(routeBranches[index]))) {
|
|
2471
|
+
loweringGap = "dispatch routed policy lost its Stage-A authority";
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
const childBindingProjectionIds = childEffectIds.map((childEffectId) => {
|
|
2475
|
+
const child = decisionChildEffects[childEffectId];
|
|
2476
|
+
if (child === void 0) throw new Error("parseman: decision effect lost its child effect");
|
|
2477
|
+
const edge = bindingEdges[child.childBindingEdgeId];
|
|
2478
|
+
if (edge?.projectionId === void 0) {
|
|
2479
|
+
throw new Error("parseman: decision effect lost its child binding projection");
|
|
2480
|
+
}
|
|
2481
|
+
return edge.projectionId;
|
|
2482
|
+
});
|
|
2483
|
+
let readerMask = ALL_BINDING_READERS;
|
|
2484
|
+
let variantMask = ALL_BINDING_VARIANTS;
|
|
2485
|
+
for (const projectionId of childBindingProjectionIds) {
|
|
2486
|
+
const projection = bindingProjections[projectionId];
|
|
2487
|
+
if (projection === void 0) throw new Error("parseman: decision binding projection disappeared");
|
|
2488
|
+
readerMask &= projection.readerMask;
|
|
2489
|
+
variantMask &= projection.variantMask;
|
|
2490
|
+
}
|
|
2491
|
+
if (childBindingProjectionIds.length === 0) {
|
|
2492
|
+
readerMask = 0;
|
|
2493
|
+
variantMask = 0;
|
|
2494
|
+
}
|
|
2495
|
+
if (loweringGap === void 0 && (readerMask !== ALL_BINDING_READERS || variantMask !== ALL_BINDING_VARIANTS)) {
|
|
2496
|
+
loweringGap = "decision child binding projection is incomplete";
|
|
2497
|
+
}
|
|
2498
|
+
const authority = finalDecisionAuthorities[authorityId];
|
|
2499
|
+
if (authority === void 0) throw new Error("parseman: decision effect lost its final authority");
|
|
2500
|
+
const digestWords = [
|
|
2501
|
+
decision.siteId,
|
|
2502
|
+
authorityId,
|
|
2503
|
+
authority.atom === "choice" ? 0 : 1,
|
|
2504
|
+
DECISION_REFERENCE_TEMPLATE_ID,
|
|
2505
|
+
DECISION_CAPTURED_TEMPLATE_ID,
|
|
2506
|
+
DECISION_NAMED_TEMPLATE_ID,
|
|
2507
|
+
readerMask,
|
|
2508
|
+
variantMask,
|
|
2509
|
+
childEffectIds.length,
|
|
2510
|
+
...(decision.routeUsesRouted ?? []).map((value) => value ? 1 : 0),
|
|
2511
|
+
...childEffectIds.flatMap((childEffectId, index) => {
|
|
2512
|
+
const child = decisionChildEffects[childEffectId];
|
|
2513
|
+
const projection = bindingProjections[childBindingProjectionIds[index]];
|
|
2514
|
+
return [
|
|
2515
|
+
child.armId,
|
|
2516
|
+
child.expectedAuthorityId,
|
|
2517
|
+
child.gateCallbackId ?? -1,
|
|
2518
|
+
child.gateSourceId ?? -1,
|
|
2519
|
+
child.autoNotAuthorityId ?? -1,
|
|
2520
|
+
projection.id,
|
|
2521
|
+
projection.semanticDigest
|
|
2522
|
+
];
|
|
2523
|
+
})
|
|
2524
|
+
];
|
|
2525
|
+
decisionEffects.push({
|
|
2526
|
+
id: effectId,
|
|
2527
|
+
decisionSiteId: decision.siteId,
|
|
2528
|
+
finalDecisionAuthorityId: authorityId,
|
|
2529
|
+
phase: loweringGap === void 0 ? COMPLETE_PHASE : phaseGap(COMPLETE_CAPABILITY, loweringGap),
|
|
2530
|
+
childEffectIds,
|
|
2531
|
+
childBindingProjectionIds,
|
|
2532
|
+
referenceTemplateId: DECISION_REFERENCE_TEMPLATE_ID,
|
|
2533
|
+
capturedTemplateId: DECISION_CAPTURED_TEMPLATE_ID,
|
|
2534
|
+
namedTemplateId: DECISION_NAMED_TEMPLATE_ID,
|
|
2535
|
+
readerMask,
|
|
2536
|
+
variantMask,
|
|
2537
|
+
semanticDigest: bindingDigest(digestWords, authority.atom, String(decision.siteId)),
|
|
2538
|
+
pendingRollbackPolicyId: 0,
|
|
2539
|
+
commitPolicyId: 0
|
|
2540
|
+
});
|
|
2541
|
+
}
|
|
2542
|
+
return {
|
|
2543
|
+
finalDecisionAuthorities,
|
|
2544
|
+
decisionEffects,
|
|
2545
|
+
decisionChildEffects,
|
|
2546
|
+
choiceClassAuthorities,
|
|
2547
|
+
choiceExecutionOrders,
|
|
2548
|
+
classifySpellingMaps,
|
|
2549
|
+
classifyProjectionPlans,
|
|
2550
|
+
decisionExpectedAuthorities,
|
|
2551
|
+
decisionCallbackAuthorities,
|
|
2552
|
+
decisionSourceAuthorities: [...sourceIds.entries()].map(([source, id]) => ({ id, source })).sort((a, b) => a.id - b.id),
|
|
2553
|
+
decisionAutoNotAuthorities: [...autoNotIds.entries()].map(([key, id]) => ({
|
|
2554
|
+
id,
|
|
2555
|
+
checks: JSON.parse(key)
|
|
2556
|
+
})).sort((a, b) => a.id - b.id)
|
|
2557
|
+
};
|
|
2558
|
+
}
|
|
2559
|
+
function lexicalCapabilityInventory(roots, resolve) {
|
|
2560
|
+
const inventory = lexicalCapabilityCandidates(roots, resolve);
|
|
2561
|
+
const occurrenceContexts = /* @__PURE__ */ new Map();
|
|
2562
|
+
for (const candidate of inventory.candidates) {
|
|
2563
|
+
let contexts = occurrenceContexts.get(candidate.parser);
|
|
2564
|
+
if (contexts === void 0) occurrenceContexts.set(candidate.parser, contexts = /* @__PURE__ */ new Set());
|
|
2565
|
+
contexts.add(candidate.contextKey);
|
|
2566
|
+
}
|
|
2567
|
+
const isSeparateOccurrence = (parser, contextKey) => occurrenceContexts.get(parser)?.has(contextKey) === true;
|
|
2568
|
+
const scanConsumersBySite = /* @__PURE__ */ new Map();
|
|
2569
|
+
for (let siteId = 0; siteId < inventory.candidates.length; siteId++) {
|
|
2570
|
+
const candidate = inventory.candidates[siteId];
|
|
2571
|
+
const consumers = ownedScanConsumers(
|
|
2572
|
+
candidate.parser,
|
|
2573
|
+
candidate.context,
|
|
2574
|
+
inventory.contextKeyOf,
|
|
2575
|
+
isSeparateOccurrence,
|
|
2576
|
+
resolve
|
|
2577
|
+
);
|
|
2578
|
+
if (consumers.length === 0) continue;
|
|
2579
|
+
scanConsumersBySite.set(siteId, consumers);
|
|
2580
|
+
for (const consumer of consumers) {
|
|
2581
|
+
if (!inventory.contexts.has(consumer.contextKey)) {
|
|
2582
|
+
inventory.contexts.set(consumer.contextKey, consumer.context);
|
|
2583
|
+
}
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
const contextSnapshots = [...inventory.contexts.entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0).map(([key, context], id) => ({
|
|
2587
|
+
id,
|
|
2588
|
+
key,
|
|
2589
|
+
hasTrivia: context.trivia !== void 0,
|
|
2590
|
+
hasScanSkip: context.scanSkip.length > 0,
|
|
2591
|
+
trackLines: context.trackLines,
|
|
2592
|
+
captureTrivia: context.captureTrivia,
|
|
2593
|
+
opaqueRootCapture: context.opaqueRootCapture,
|
|
2594
|
+
dynamicState: context.dynamicState
|
|
2595
|
+
}));
|
|
2596
|
+
const contextSnapshotIdByKey = new Map(contextSnapshots.map((snapshot) => [snapshot.key, snapshot.id]));
|
|
2597
|
+
const decisionInventory = lexicalDecisionInventory(
|
|
2598
|
+
inventory.candidates,
|
|
2599
|
+
contextSnapshotIdByKey,
|
|
2600
|
+
resolve
|
|
2601
|
+
);
|
|
2602
|
+
const transitionDiagnostics = [];
|
|
2603
|
+
const transitionDiagnosticIdByKey = /* @__PURE__ */ new Map();
|
|
2604
|
+
const internTransitionDiagnostics = (recognizerKey, session) => {
|
|
2605
|
+
const body = {
|
|
2606
|
+
stateCount: session.nextState,
|
|
2607
|
+
expected: session.expected,
|
|
2608
|
+
events: session.events
|
|
2609
|
+
};
|
|
2610
|
+
const key = `${recognizerKey}\0${JSON.stringify(body)}`;
|
|
2611
|
+
const prior = transitionDiagnosticIdByKey.get(key);
|
|
2612
|
+
if (prior !== void 0) return prior;
|
|
2613
|
+
const id = transitionDiagnostics.length;
|
|
2614
|
+
transitionDiagnosticIdByKey.set(key, id);
|
|
2615
|
+
transitionDiagnostics.push({ id, ...body });
|
|
2616
|
+
return id;
|
|
2617
|
+
};
|
|
2618
|
+
const controlPlans = [];
|
|
2619
|
+
const controlPlanIdByKey = /* @__PURE__ */ new Map();
|
|
2620
|
+
const internControlPlan = (session) => {
|
|
2621
|
+
const key = JSON.stringify(session.controls);
|
|
2622
|
+
const prior = controlPlanIdByKey.get(key);
|
|
2623
|
+
if (prior !== void 0) return prior;
|
|
2624
|
+
const id = controlPlans.length;
|
|
2625
|
+
controlPlanIdByKey.set(key, id);
|
|
2626
|
+
controlPlans.push({ id, controls: session.controls });
|
|
2627
|
+
return id;
|
|
2628
|
+
};
|
|
2629
|
+
const grammarWrapperSpecs = [];
|
|
2630
|
+
const grammarSpecIdByKey = /* @__PURE__ */ new Map();
|
|
2631
|
+
const grammarSourceOperationIds = /* @__PURE__ */ new Map();
|
|
2632
|
+
const triviaBindingIds = /* @__PURE__ */ new Map();
|
|
2633
|
+
const grammarCaptureTriviaKinds = [];
|
|
2634
|
+
const captureKindsIdByKey = /* @__PURE__ */ new Map();
|
|
2635
|
+
const boundaryTopologies = [];
|
|
2636
|
+
const topologyIdByKey = /* @__PURE__ */ new Map();
|
|
2637
|
+
const identityId = (map, parser) => {
|
|
2638
|
+
const prior = map.get(parser);
|
|
2639
|
+
if (prior !== void 0) return prior;
|
|
2640
|
+
const id = map.size;
|
|
2641
|
+
map.set(parser, id);
|
|
2642
|
+
return id;
|
|
2643
|
+
};
|
|
2644
|
+
const captureKindsId = (values) => {
|
|
2645
|
+
if (values === void 0) return void 0;
|
|
2646
|
+
const key = JSON.stringify(values);
|
|
2647
|
+
const prior = captureKindsIdByKey.get(key);
|
|
2648
|
+
if (prior !== void 0) return prior;
|
|
2649
|
+
const id = grammarCaptureTriviaKinds.length;
|
|
2650
|
+
captureKindsIdByKey.set(key, id);
|
|
2651
|
+
grammarCaptureTriviaKinds.push([...values]);
|
|
2652
|
+
return id;
|
|
2653
|
+
};
|
|
2654
|
+
const internGrammarWrapper = (parser, captureTriviaKinds) => {
|
|
2655
|
+
const def = parser._def;
|
|
2656
|
+
if (def.tag !== "grammar") return void 0;
|
|
2657
|
+
if (def.constructionTrackLines === void 0) return void 0;
|
|
2658
|
+
const sourceOperationId = identityId(grammarSourceOperationIds, parser);
|
|
2659
|
+
const triviaBindingId = def.triviaParser === void 0 ? void 0 : identityId(triviaBindingIds, def.triviaParser);
|
|
2660
|
+
const captureTriviaKindsId = captureKindsId(captureTriviaKinds);
|
|
2661
|
+
const body = {
|
|
2662
|
+
sourceOperationId,
|
|
2663
|
+
clearTrivia: def.clearTrivia === true,
|
|
2664
|
+
...triviaBindingId === void 0 ? {} : { triviaBindingId },
|
|
2665
|
+
trackLines: def.constructionTrackLines,
|
|
2666
|
+
captureTrivia: def.captureTrivia === true,
|
|
2667
|
+
...captureTriviaKindsId === void 0 ? {} : { captureTriviaKindsId },
|
|
2668
|
+
rootCapture: def.rootCapture === "opaque" ? "opaque" : "inherit",
|
|
2669
|
+
clonePolicy: "spread-existing-or-create-canonical",
|
|
2670
|
+
postChildPolicy: "line-propagate-then-annotate-or-return"
|
|
2671
|
+
};
|
|
2672
|
+
const key = JSON.stringify(body);
|
|
2673
|
+
const prior = grammarSpecIdByKey.get(key);
|
|
2674
|
+
if (prior !== void 0) return prior;
|
|
2675
|
+
const id = grammarWrapperSpecs.length;
|
|
2676
|
+
grammarSpecIdByKey.set(key, id);
|
|
2677
|
+
grammarWrapperSpecs.push({ id, ...body });
|
|
2678
|
+
return id;
|
|
2679
|
+
};
|
|
2680
|
+
const internBoundaryTopology = (session) => {
|
|
2681
|
+
const grammarCaptureKindsByFrame = /* @__PURE__ */ new Map();
|
|
2682
|
+
for (let frameIndex = 0; frameIndex < session.wrapperFrames.length; frameIndex++) {
|
|
2683
|
+
const pending2 = session.wrapperFrames[frameIndex];
|
|
2684
|
+
const control = session.controls[pending2.controlId];
|
|
2685
|
+
if (pending2.stateStart < 0 || pending2.stateEnd < pending2.stateStart || pending2.stateEnd > session.nextState || pending2.id !== frameIndex || control === void 0 || control.id !== pending2.controlId || control.kind !== pending2.kind || control.stateStart !== pending2.stateStart || control.stateEnd !== pending2.stateEnd) {
|
|
2686
|
+
return { gap: "token boundary overlay has an invalid state interval" };
|
|
2687
|
+
}
|
|
2688
|
+
if (pending2.parentFrameId !== void 0) {
|
|
2689
|
+
const parent = session.wrapperFrames[pending2.parentFrameId];
|
|
2690
|
+
if (parent === void 0 || pending2.parentFrameId >= pending2.id || pending2.stateStart < parent.stateStart || pending2.stateEnd > parent.stateEnd) {
|
|
2691
|
+
return { gap: "token boundary overlay is not well nested" };
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
if (pending2.kind === "grammar") {
|
|
2695
|
+
const def = pending2.parser._def;
|
|
2696
|
+
if (def.tag !== "grammar" || def.constructionTrackLines === void 0) {
|
|
2697
|
+
return { gap: "grammar wrapper lacks exact construction-time source-operation metadata" };
|
|
2698
|
+
}
|
|
2699
|
+
try {
|
|
2700
|
+
grammarCaptureKindsByFrame.set(
|
|
2701
|
+
pending2.id,
|
|
2702
|
+
def.constructionCaptureTriviaKinds === void 0 ? void 0 : [...def.constructionCaptureTriviaKinds]
|
|
2703
|
+
);
|
|
2704
|
+
} catch {
|
|
2705
|
+
return { gap: "grammar wrapper capture-trivia policy cannot be snapshotted safely" };
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
for (let i = 0; i < session.wrapperFrames.length; i++) {
|
|
2710
|
+
for (let j = i + 1; j < session.wrapperFrames.length; j++) {
|
|
2711
|
+
const a = session.wrapperFrames[i];
|
|
2712
|
+
const b = session.wrapperFrames[j];
|
|
2713
|
+
const overlap = a.stateStart < b.stateEnd && b.stateStart < a.stateEnd;
|
|
2714
|
+
const nested = a.stateStart <= b.stateStart && b.stateEnd <= a.stateEnd || b.stateStart <= a.stateStart && a.stateEnd <= b.stateEnd;
|
|
2715
|
+
if (overlap && !nested) return { gap: "token boundary overlay has crossed state intervals" };
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
const outer = session.wrapperFrames[0];
|
|
2719
|
+
if (outer?.kind !== "token" || outer.parentFrameId !== void 0 || outer.stateStart !== 0 || outer.stateEnd !== session.nextState) {
|
|
2720
|
+
return { gap: "token boundary overlay lost its outer authored token frame" };
|
|
2721
|
+
}
|
|
2722
|
+
const frames = [];
|
|
2723
|
+
for (const pending2 of session.wrapperFrames) {
|
|
2724
|
+
if (pending2.kind === "token") frames.push({
|
|
2725
|
+
id: pending2.id,
|
|
2726
|
+
...pending2.parentFrameId === void 0 ? {} : { parentFrameId: pending2.parentFrameId },
|
|
2727
|
+
controlId: pending2.controlId,
|
|
2728
|
+
stateStart: pending2.stateStart,
|
|
2729
|
+
stateEnd: pending2.stateEnd,
|
|
2730
|
+
kind: "token",
|
|
2731
|
+
boundaryPlanId: 0,
|
|
2732
|
+
materializationPlanId: 0
|
|
2733
|
+
});
|
|
2734
|
+
else {
|
|
2735
|
+
const wrapperSpecId = internGrammarWrapper(
|
|
2736
|
+
pending2.parser,
|
|
2737
|
+
grammarCaptureKindsByFrame.get(pending2.id)
|
|
2738
|
+
);
|
|
2739
|
+
if (wrapperSpecId === void 0) throw new Error("parseman: validated grammar policy disappeared");
|
|
2740
|
+
frames.push({
|
|
2741
|
+
id: pending2.id,
|
|
2742
|
+
...pending2.parentFrameId === void 0 ? {} : { parentFrameId: pending2.parentFrameId },
|
|
2743
|
+
controlId: pending2.controlId,
|
|
2744
|
+
stateStart: pending2.stateStart,
|
|
2745
|
+
stateEnd: pending2.stateEnd,
|
|
2746
|
+
kind: "grammar",
|
|
2747
|
+
wrapperSpecId
|
|
2748
|
+
});
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
const key = JSON.stringify(frames);
|
|
2752
|
+
const prior = topologyIdByKey.get(key);
|
|
2753
|
+
if (prior !== void 0) return { id: prior };
|
|
2754
|
+
const id = boundaryTopologies.length;
|
|
2755
|
+
topologyIdByKey.set(key, id);
|
|
2756
|
+
boundaryTopologies.push({ id, frames });
|
|
2757
|
+
return { id };
|
|
2758
|
+
};
|
|
2759
|
+
const ownSkipPlans = [];
|
|
2760
|
+
const ownSkipPlanIdByKey = /* @__PURE__ */ new Map();
|
|
2761
|
+
const internOwnSkipPlan = (entries) => {
|
|
2762
|
+
if (entries.length === 0) return void 0;
|
|
2763
|
+
const represented = entries.map((entry) => {
|
|
2764
|
+
const normalized = normalizeBalancedLexical(entry, resolve) ?? normalizeLexical(entry, resolve, /* @__PURE__ */ new Set());
|
|
2765
|
+
if ("refusal" in normalized) return {
|
|
2766
|
+
status: gap(`ownSkip normalization: ${normalized.refusal}`)
|
|
2767
|
+
};
|
|
2768
|
+
return {
|
|
2769
|
+
semanticKey: JSON.stringify(normalized.ir),
|
|
2770
|
+
ir: normalized.ir,
|
|
2771
|
+
status: COMPLETE_CAPABILITY
|
|
2772
|
+
};
|
|
2773
|
+
});
|
|
2774
|
+
const key = JSON.stringify(represented);
|
|
2775
|
+
const prior = ownSkipPlanIdByKey.get(key);
|
|
2776
|
+
if (prior !== void 0) return prior;
|
|
2777
|
+
const id = ownSkipPlans.length;
|
|
2778
|
+
ownSkipPlanIdByKey.set(key, id);
|
|
2779
|
+
ownSkipPlans.push({ id, entries: represented });
|
|
2780
|
+
return id;
|
|
2781
|
+
};
|
|
2782
|
+
const scanConsumerPolicies = [];
|
|
2783
|
+
const scanPolicyIdsBySite = /* @__PURE__ */ new Map();
|
|
2784
|
+
for (let siteId = 0; siteId < inventory.candidates.length; siteId++) {
|
|
2785
|
+
const candidate = inventory.candidates[siteId];
|
|
2786
|
+
for (const consumer of scanConsumersBySite.get(siteId) ?? []) {
|
|
2787
|
+
const contextSnapshotId = contextSnapshotIdByKey.get(consumer.contextKey);
|
|
2788
|
+
if (contextSnapshotId === void 0) throw new Error("parseman: scan consumer lost its context snapshot");
|
|
2789
|
+
const ownSkipPlanId = internOwnSkipPlan(consumer.ownSkip);
|
|
2790
|
+
const ownSkipPlan = ownSkipPlanId === void 0 ? void 0 : ownSkipPlans[ownSkipPlanId];
|
|
2791
|
+
const status = ownSkipPlan?.entries.find((entry) => entry.status.kind !== "complete")?.status ?? COMPLETE_CAPABILITY;
|
|
2792
|
+
const id = scanConsumerPolicies.length;
|
|
2793
|
+
const common = {
|
|
2794
|
+
id,
|
|
2795
|
+
siteId,
|
|
2796
|
+
path: `${candidate.path}${consumer.path}`,
|
|
2797
|
+
contextSnapshotId,
|
|
2798
|
+
raw: consumer.raw,
|
|
2799
|
+
...ownSkipPlanId === void 0 ? {} : { ownSkipPlanId },
|
|
2800
|
+
lookup: "dynamic-parse-property-every-skip-test",
|
|
2801
|
+
pendingReuse: "forbidden",
|
|
2802
|
+
status
|
|
2803
|
+
};
|
|
2804
|
+
scanConsumerPolicies.push(consumer.kind === "scanTo" ? {
|
|
2805
|
+
...common,
|
|
2806
|
+
kind: "scanTo",
|
|
2807
|
+
ambient: consumer.raw ? "none-raw" : "enumerate-trivia-then-scanSkip-per-parse-attempt",
|
|
2808
|
+
context: "detached-per-attempt-state-errors-only"
|
|
2809
|
+
} : {
|
|
2810
|
+
...common,
|
|
2811
|
+
kind: "balanced",
|
|
2812
|
+
ambient: consumer.raw ? "none-raw" : "array-identity-interior-cache",
|
|
2813
|
+
cache: "lookup-every-attempt-enumerate-on-miss",
|
|
2814
|
+
context: "token-cleared-original"
|
|
2815
|
+
});
|
|
2816
|
+
let ids = scanPolicyIdsBySite.get(siteId);
|
|
2817
|
+
if (ids === void 0) scanPolicyIdsBySite.set(siteId, ids = []);
|
|
2818
|
+
ids.push(id);
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
const pending = inventory.candidates.map((candidate, id) => {
|
|
2822
|
+
const contextSnapshotId = contextSnapshotIdByKey.get(candidate.contextKey);
|
|
2823
|
+
if (contextSnapshotId === void 0) throw new Error("parseman: capability occurrence lost its context snapshot");
|
|
2824
|
+
const scanConsumerPolicyIds = scanPolicyIdsBySite.get(id) ?? [];
|
|
2825
|
+
if (candidate.atom === "terminal") {
|
|
2826
|
+
const key = keyOf(candidate.parser._def);
|
|
2827
|
+
if (key === void 0) throw new Error("parseman: lexical terminal capability lost its semantic key");
|
|
2828
|
+
const obligations2 = terminalObligations();
|
|
2829
|
+
return {
|
|
2830
|
+
id,
|
|
2831
|
+
bodyId: candidate.bodyId,
|
|
2832
|
+
path: candidate.path,
|
|
2833
|
+
contextKey: candidate.contextKey,
|
|
2834
|
+
contextSnapshotId,
|
|
2835
|
+
recognitionContextKey: candidate.recognitionContextKey,
|
|
2836
|
+
context: candidate.context,
|
|
2837
|
+
recognitionContext: candidate.parser._def.tag === "token" ? { ...candidate.context, trivia: void 0, captureTrivia: false } : candidate.context,
|
|
2838
|
+
semanticKey: key,
|
|
2839
|
+
atom: candidate.atom,
|
|
2840
|
+
parser: candidate.parser,
|
|
2841
|
+
obligations: obligations2,
|
|
2842
|
+
scanConsumerPolicyIds,
|
|
2843
|
+
status: derivedCapabilityStatus(obligations2)
|
|
2844
|
+
};
|
|
2845
|
+
}
|
|
2846
|
+
const def = candidate.parser._def;
|
|
2847
|
+
if (candidate.atom === "choice") {
|
|
2848
|
+
if (def.tag !== "choice") throw new Error("parseman: lexical choice capability lost its boundary");
|
|
2849
|
+
const obligations2 = decisionObligations(decisionInventory.recognitionBySite.get(id) ?? gap("choice outcome recognition record is missing"));
|
|
2850
|
+
return {
|
|
2851
|
+
id,
|
|
2852
|
+
bodyId: candidate.bodyId,
|
|
2853
|
+
path: candidate.path,
|
|
2854
|
+
contextSnapshotId,
|
|
2855
|
+
contextKey: candidate.contextKey,
|
|
2856
|
+
recognitionContextKey: candidate.recognitionContextKey,
|
|
2857
|
+
context: candidate.context,
|
|
2858
|
+
recognitionContext: candidate.context,
|
|
2859
|
+
semanticKey: `C\0${def.parsers.length}\0${def.strategy.tag}`,
|
|
2860
|
+
atom: candidate.atom,
|
|
2861
|
+
parser: candidate.parser,
|
|
2862
|
+
obligations: obligations2,
|
|
2863
|
+
scanConsumerPolicyIds,
|
|
2864
|
+
status: derivedCapabilityStatus(obligations2)
|
|
2865
|
+
};
|
|
2866
|
+
}
|
|
2867
|
+
if (candidate.atom === "dispatch") {
|
|
2868
|
+
if (def.tag !== "dispatch") throw new Error("parseman: lexical dispatch capability lost its boundary");
|
|
2869
|
+
const obligations2 = decisionObligations(decisionInventory.recognitionBySite.get(id) ?? gap("dispatch outcome recognition record is missing"));
|
|
2870
|
+
return {
|
|
2871
|
+
id,
|
|
2872
|
+
bodyId: candidate.bodyId,
|
|
2873
|
+
path: candidate.path,
|
|
2874
|
+
contextSnapshotId,
|
|
2875
|
+
contextKey: candidate.contextKey,
|
|
2876
|
+
recognitionContextKey: candidate.recognitionContextKey,
|
|
2877
|
+
context: candidate.context,
|
|
2878
|
+
recognitionContext: candidate.context,
|
|
2879
|
+
semanticKey: `D\0${def.cases.length}\0${def.matchers?.length ?? 0}\0${def.otherwise === void 0 ? 0 : 1}`,
|
|
2880
|
+
atom: candidate.atom,
|
|
2881
|
+
parser: candidate.parser,
|
|
2882
|
+
obligations: obligations2,
|
|
2883
|
+
scanConsumerPolicyIds,
|
|
2884
|
+
status: derivedCapabilityStatus(obligations2)
|
|
2885
|
+
};
|
|
2886
|
+
}
|
|
2887
|
+
if (def.tag !== "token") throw new Error("parseman: lexical token capability lost its boundary");
|
|
2888
|
+
const session = newNormalizeSession();
|
|
2889
|
+
const normalized = normalizeBalancedLexical(
|
|
2890
|
+
candidate.parser,
|
|
2891
|
+
resolve,
|
|
2892
|
+
session
|
|
2893
|
+
) ?? normalizeLexical(candidate.parser, resolve, /* @__PURE__ */ new Set(), session);
|
|
2894
|
+
if ("refusal" in normalized) {
|
|
2895
|
+
const obligations2 = tokenObligations(gap(`token normalization: ${normalized.refusal}`));
|
|
2896
|
+
return {
|
|
2897
|
+
id,
|
|
2898
|
+
bodyId: candidate.bodyId,
|
|
2899
|
+
path: candidate.path,
|
|
2900
|
+
contextKey: candidate.contextKey,
|
|
2901
|
+
contextSnapshotId,
|
|
2902
|
+
recognitionContextKey: candidate.recognitionContextKey,
|
|
2903
|
+
context: candidate.context,
|
|
2904
|
+
recognitionContext: { ...candidate.context, trivia: void 0, captureTrivia: false },
|
|
2905
|
+
semanticKey: `T\0GAP\0${normalized.refusal}`,
|
|
2906
|
+
atom: candidate.atom,
|
|
2907
|
+
parser: candidate.parser,
|
|
2908
|
+
obligations: obligations2,
|
|
2909
|
+
scanConsumerPolicyIds,
|
|
2910
|
+
status: derivedCapabilityStatus(obligations2)
|
|
2911
|
+
};
|
|
2912
|
+
}
|
|
2913
|
+
const semanticKey = `T\0${JSON.stringify(normalized.ir)}`;
|
|
2914
|
+
if (matchesEmpty(def.parser)) {
|
|
2915
|
+
const obligations2 = tokenObligations({
|
|
2916
|
+
kind: "impossible",
|
|
2917
|
+
proof: "an atomic source token must consume positive width but this token body is nullable"
|
|
2918
|
+
});
|
|
2919
|
+
return {
|
|
2920
|
+
id,
|
|
2921
|
+
bodyId: candidate.bodyId,
|
|
2922
|
+
path: candidate.path,
|
|
2923
|
+
contextKey: candidate.contextKey,
|
|
2924
|
+
contextSnapshotId,
|
|
2925
|
+
recognitionContextKey: candidate.recognitionContextKey,
|
|
2926
|
+
context: candidate.context,
|
|
2927
|
+
recognitionContext: { ...candidate.context, trivia: void 0, captureTrivia: false },
|
|
2928
|
+
semanticKey,
|
|
2929
|
+
atom: candidate.atom,
|
|
2930
|
+
parser: candidate.parser,
|
|
2931
|
+
scanConsumerPolicyIds,
|
|
2932
|
+
obligations: obligations2,
|
|
2933
|
+
status: derivedCapabilityStatus(obligations2)
|
|
2934
|
+
};
|
|
2935
|
+
}
|
|
2936
|
+
const diagnosticPlanId = internTransitionDiagnostics(semanticKey, session);
|
|
2937
|
+
const controlPlanId = internControlPlan(session);
|
|
2938
|
+
const topology = internBoundaryTopology(session);
|
|
2939
|
+
const topologyRepresentation = "id" in topology ? COMPLETE_CAPABILITY : gap(topology.gap);
|
|
2940
|
+
const obligations = directExecutableTokenBody(candidate.parser, resolve) === void 0 ? tokenObligations(COMPLETE_CAPABILITY, {
|
|
2941
|
+
diagnostics: true,
|
|
2942
|
+
boundaryPlan: topologyRepresentation,
|
|
2943
|
+
materializationPlan: topologyRepresentation
|
|
2944
|
+
}) : executableLexBodyObligations();
|
|
2945
|
+
return {
|
|
2946
|
+
id,
|
|
2947
|
+
bodyId: candidate.bodyId,
|
|
2948
|
+
path: candidate.path,
|
|
2949
|
+
contextKey: candidate.contextKey,
|
|
2950
|
+
contextSnapshotId,
|
|
2951
|
+
recognitionContextKey: candidate.recognitionContextKey,
|
|
2952
|
+
context: candidate.context,
|
|
2953
|
+
recognitionContext: { ...candidate.context, trivia: void 0, captureTrivia: false },
|
|
2954
|
+
semanticKey,
|
|
2955
|
+
atom: candidate.atom,
|
|
2956
|
+
parser: candidate.parser,
|
|
2957
|
+
diagnosticPlanId,
|
|
2958
|
+
scanConsumerPolicyIds,
|
|
2959
|
+
controlPlanId,
|
|
2960
|
+
..."id" in topology ? { boundaryTopologyId: topology.id } : {},
|
|
2961
|
+
obligations,
|
|
2962
|
+
status: derivedCapabilityStatus(obligations)
|
|
2963
|
+
};
|
|
2964
|
+
});
|
|
2965
|
+
const languageKeys = [...new Set(pending.map((site) => `${site.atom}\0${site.semanticKey}`))].sort();
|
|
2966
|
+
const languageIdByKey = new Map(languageKeys.map((key, id) => [key, id]));
|
|
2967
|
+
const languages = languageKeys.map((key, id) => {
|
|
2968
|
+
const split = key.indexOf("\0");
|
|
2969
|
+
return {
|
|
2970
|
+
id,
|
|
2971
|
+
atom: key.slice(0, split),
|
|
2972
|
+
semanticKey: key.slice(split + 1)
|
|
2973
|
+
};
|
|
2974
|
+
});
|
|
2975
|
+
const preliminaryCapabilities = pending.map((site) => ({
|
|
2976
|
+
...site,
|
|
2977
|
+
languageId: languageIdByKey.get(`${site.atom}\0${site.semanticKey}`)
|
|
2978
|
+
}));
|
|
2979
|
+
const bindingProjections = [];
|
|
2980
|
+
const bindingEdges = inventory.bindingEdges.map((edge, id) => {
|
|
2981
|
+
const projection = fixedBindingProjection(edge, id, bindingProjections.length);
|
|
2982
|
+
bindingProjections.push(projection);
|
|
2983
|
+
const {
|
|
2984
|
+
parentBodyId: _parentBodyId,
|
|
2985
|
+
childBodyId: _childBodyId,
|
|
2986
|
+
childOrdinal: _childOrdinal,
|
|
2987
|
+
...publicEdge
|
|
2988
|
+
} = edge;
|
|
2989
|
+
const complete = projection.readerMask === ALL_BINDING_READERS && projection.variantMask === ALL_BINDING_VARIANTS;
|
|
2990
|
+
return {
|
|
2991
|
+
id,
|
|
2992
|
+
...publicEdge,
|
|
2993
|
+
projectionId: projection.id,
|
|
2994
|
+
contextSnapshotId: contextSnapshotIdByKey.get(edge.contextKey) ?? (() => {
|
|
2995
|
+
throw new Error("parseman: binding edge lost its context snapshot");
|
|
2996
|
+
})(),
|
|
2997
|
+
status: complete ? COMPLETE_CAPABILITY : gap(FIXED_TUPLE_BINDING_GAP)
|
|
2998
|
+
};
|
|
2999
|
+
});
|
|
3000
|
+
const terminalProjections = preliminaryCapabilities.filter((site) => site.atom === "terminal").map((site, id) => {
|
|
3001
|
+
const incomingBindingProjectionIds = [];
|
|
3002
|
+
let readerMask = ALL_BINDING_READERS;
|
|
3003
|
+
let variantMask = ALL_BINDING_VARIANTS;
|
|
3004
|
+
for (let edgeId = 0; edgeId < inventory.bindingEdges.length; edgeId++) {
|
|
3005
|
+
const edge = inventory.bindingEdges[edgeId];
|
|
3006
|
+
if (edge.childBodyId !== site.bodyId || edge.childContextKey !== site.contextKey) continue;
|
|
3007
|
+
const bindingEdge = bindingEdges[edgeId];
|
|
3008
|
+
const projection = bindingProjections[bindingEdge.projectionId];
|
|
3009
|
+
if (projection === void 0) throw new Error("parseman: terminal binding projection disappeared");
|
|
3010
|
+
incomingBindingProjectionIds.push(projection.id);
|
|
3011
|
+
readerMask &= projection.readerMask;
|
|
3012
|
+
variantMask &= projection.variantMask;
|
|
3013
|
+
}
|
|
3014
|
+
if (incomingBindingProjectionIds.length === 0) {
|
|
3015
|
+
readerMask = 0;
|
|
3016
|
+
variantMask = 0;
|
|
3017
|
+
}
|
|
3018
|
+
const complete = incomingBindingProjectionIds.length > 0 && readerMask === ALL_BINDING_READERS && variantMask === ALL_BINDING_VARIANTS && incomingBindingProjectionIds.every((projectionId) => bindingEdges[bindingProjections[projectionId].edgeId].status.kind === "complete");
|
|
3019
|
+
const digestWords = [
|
|
3020
|
+
site.bodyId,
|
|
3021
|
+
site.languageId,
|
|
3022
|
+
site.bodyId,
|
|
3023
|
+
TERMINAL_CAPTURED_TEMPLATE_ID,
|
|
3024
|
+
site.bodyId,
|
|
3025
|
+
readerMask,
|
|
3026
|
+
variantMask,
|
|
3027
|
+
incomingBindingProjectionIds.length,
|
|
3028
|
+
...incomingBindingProjectionIds.flatMap((projectionId) => {
|
|
3029
|
+
const projection = bindingProjections[projectionId];
|
|
3030
|
+
return [projection.id, projection.semanticDigest];
|
|
3031
|
+
})
|
|
3032
|
+
];
|
|
3033
|
+
return {
|
|
3034
|
+
id,
|
|
3035
|
+
siteId: site.id,
|
|
3036
|
+
bodyId: site.bodyId,
|
|
3037
|
+
languageId: site.languageId,
|
|
3038
|
+
referenceBodyId: site.bodyId,
|
|
3039
|
+
capturedTemplateId: TERMINAL_CAPTURED_TEMPLATE_ID,
|
|
3040
|
+
namedSymbolId: site.bodyId,
|
|
3041
|
+
incomingBindingProjectionIds,
|
|
3042
|
+
readerMask,
|
|
3043
|
+
variantMask,
|
|
3044
|
+
semanticDigest: bindingDigest(digestWords, "terminal", site.semanticKey),
|
|
3045
|
+
status: complete ? COMPLETE_CAPABILITY : gap(FIXED_TUPLE_BINDING_GAP)
|
|
3046
|
+
};
|
|
3047
|
+
});
|
|
3048
|
+
const terminalProjectionBySiteId = new Map(terminalProjections.map((projection) => [projection.siteId, projection]));
|
|
3049
|
+
const terminalCapabilities = preliminaryCapabilities.map((site) => {
|
|
3050
|
+
if (site.atom !== "terminal") return site;
|
|
3051
|
+
const projection = terminalProjectionBySiteId.get(site.id);
|
|
3052
|
+
if (projection === void 0) throw new Error("parseman: terminal capability lost its projection");
|
|
3053
|
+
const bindingAndReachability = projection.status.kind === "complete" ? COMPLETE_PHASE : phaseGap(projection.status, FIXED_TUPLE_BINDING_GAP);
|
|
3054
|
+
const obligations = { ...site.obligations, bindingAndReachability };
|
|
3055
|
+
return { ...site, obligations, status: derivedCapabilityStatus(obligations) };
|
|
3056
|
+
});
|
|
3057
|
+
const decisionEffects = decisionEffectInventory(
|
|
3058
|
+
inventory.candidates,
|
|
3059
|
+
decisionInventory.decisions,
|
|
3060
|
+
bindingEdges,
|
|
3061
|
+
bindingProjections,
|
|
3062
|
+
resolve
|
|
3063
|
+
);
|
|
3064
|
+
const decisionEffectBySite = new Map(decisionEffects.decisionEffects.map((effect) => [effect.decisionSiteId, effect]));
|
|
3065
|
+
const capabilities = terminalCapabilities.map((site) => {
|
|
3066
|
+
if (site.atom !== "choice" && site.atom !== "dispatch") return site;
|
|
3067
|
+
const effect = decisionEffectBySite.get(site.id);
|
|
3068
|
+
if (effect === void 0) throw new Error("parseman: decision capability lost its effect projection");
|
|
3069
|
+
const obligations = executableDecisionObligations(
|
|
3070
|
+
site.obligations.recognition.representation,
|
|
3071
|
+
effect.phase
|
|
3072
|
+
);
|
|
3073
|
+
return { ...site, obligations, status: derivedCapabilityStatus(obligations) };
|
|
3074
|
+
});
|
|
3075
|
+
return {
|
|
3076
|
+
capabilities,
|
|
3077
|
+
languages,
|
|
3078
|
+
bindingEdges,
|
|
3079
|
+
bindingProjections,
|
|
3080
|
+
terminalProjections,
|
|
3081
|
+
decisionFamilies: decisionInventory.families,
|
|
3082
|
+
decisionOutcomes: decisionInventory.outcomes,
|
|
3083
|
+
decisions: decisionInventory.decisions,
|
|
3084
|
+
decisionEffectPlan: decisionEffects,
|
|
3085
|
+
transitionDiagnostics,
|
|
3086
|
+
controlPlans,
|
|
3087
|
+
boundaryPlans: boundaryTopologies.length === 0 ? [] : [{ id: 0, kind: "token-context-transaction" }],
|
|
3088
|
+
materializationPlans: boundaryTopologies.length === 0 ? [] : [{ id: 0, kind: "token-source-range" }],
|
|
3089
|
+
grammarWrapperSpecs,
|
|
3090
|
+
grammarCaptureTriviaKinds,
|
|
3091
|
+
boundaryTopologies,
|
|
3092
|
+
contextSnapshots,
|
|
3093
|
+
ownSkipPlans,
|
|
3094
|
+
scanConsumerPolicies
|
|
3095
|
+
};
|
|
3096
|
+
}
|
|
3097
|
+
function assertLexicalCapabilityClosure(roots, alphabet, resolve) {
|
|
3098
|
+
const actual = lexicalCapabilityInventory(roots, resolve);
|
|
3099
|
+
const signature = (site) => `${site.id}\0${site.bodyId}\0${site.languageId}\0${site.path}\0${site.contextKey}\0${site.contextSnapshotId}\0${site.recognitionContextKey}\0${site.atom}\0${site.semanticKey}\0${site.diagnosticPlanId ?? -1}\0${site.controlPlanId ?? -1}\0${site.boundaryTopologyId ?? -1}\0${site.scanConsumerPolicyIds.join(",")}\0${JSON.stringify(site.obligations)}`;
|
|
3100
|
+
const expectedKeys = actual.capabilities.map(signature);
|
|
3101
|
+
const suppliedKeys = alphabet.capabilities.map(signature);
|
|
3102
|
+
const expectedLanguages = actual.languages.map((language) => `${language.id}\0${language.atom}\0${language.semanticKey}`);
|
|
3103
|
+
const suppliedLanguages = alphabet.capabilityLanguages.map((language) => `${language.id}\0${language.atom}\0${language.semanticKey}`);
|
|
3104
|
+
const edgeSignature = (edge) => `${edge.id}\0${edge.path}\0${edge.contextKey}\0${edge.childContextKey}\0${edge.contextSnapshotId}\0${edge.parentTag}\0${edge.childTag}\0${edge.projectionId ?? -1}\0${JSON.stringify(edge.status)}`;
|
|
3105
|
+
const expectedEdges = actual.bindingEdges.map(edgeSignature);
|
|
3106
|
+
const suppliedEdges = alphabet.bindingEdges.map(edgeSignature);
|
|
3107
|
+
const expectedBindingProjections = actual.bindingProjections.map((plan) => JSON.stringify(plan));
|
|
3108
|
+
const suppliedBindingProjections = (alphabet.bindingProjections ?? []).map((plan) => JSON.stringify(plan));
|
|
3109
|
+
const expectedTerminalProjections = actual.terminalProjections.map((plan) => JSON.stringify(plan));
|
|
3110
|
+
const suppliedTerminalProjections = (alphabet.terminalProjections ?? []).map((plan) => JSON.stringify(plan));
|
|
3111
|
+
const familySignature = (family) => `${family.id}\0${family.semanticKey}\0${JSON.stringify(family.ir)}`;
|
|
3112
|
+
const expectedFamilies = actual.decisionFamilies.map(familySignature);
|
|
3113
|
+
const suppliedFamilies = alphabet.decisionFamilies.map(familySignature);
|
|
3114
|
+
const outcomeSignature = (outcome) => `${outcome.id}\0${outcome.familyId}\0${outcome.semanticKey}\0${JSON.stringify(outcome.view)}`;
|
|
3115
|
+
const expectedOutcomes = actual.decisionOutcomes.map(outcomeSignature);
|
|
3116
|
+
const suppliedOutcomes = alphabet.decisionOutcomes.map(outcomeSignature);
|
|
3117
|
+
const decisionSignature = (decision) => JSON.stringify(decision);
|
|
3118
|
+
const expectedDecisions = actual.decisions.map(decisionSignature);
|
|
3119
|
+
const suppliedDecisions = alphabet.decisions.map(decisionSignature);
|
|
3120
|
+
const c2Signature = (value) => JSON.stringify(value, (_key, entry) => typeof entry === "function" ? String(entry) : entry);
|
|
3121
|
+
const expectedC2 = c2Signature(actual.decisionEffectPlan);
|
|
3122
|
+
const suppliedC2 = c2Signature(alphabet.decisionEffectPlan ?? {});
|
|
3123
|
+
const planSignature = (plan) => JSON.stringify(plan);
|
|
3124
|
+
const expectedPlans = actual.transitionDiagnostics.map(planSignature);
|
|
3125
|
+
const suppliedPlans = (alphabet.transitionDiagnostics ?? []).map(planSignature);
|
|
3126
|
+
const expectedControlPlans = actual.controlPlans.map((plan) => JSON.stringify(plan));
|
|
3127
|
+
const suppliedControlPlans = (alphabet.controlPlans ?? []).map((plan) => JSON.stringify(plan));
|
|
3128
|
+
const expectedBoundaryPlans = actual.boundaryPlans.map((plan) => JSON.stringify(plan));
|
|
3129
|
+
const suppliedBoundaryPlans = (alphabet.boundaryPlans ?? []).map((plan) => JSON.stringify(plan));
|
|
3130
|
+
const expectedMaterializationPlans = actual.materializationPlans.map((plan) => JSON.stringify(plan));
|
|
3131
|
+
const suppliedMaterializationPlans = (alphabet.materializationPlans ?? []).map((plan) => JSON.stringify(plan));
|
|
3132
|
+
const expectedGrammarSpecs = actual.grammarWrapperSpecs.map((plan) => JSON.stringify(plan));
|
|
3133
|
+
const suppliedGrammarSpecs = (alphabet.grammarWrapperSpecs ?? []).map((plan) => JSON.stringify(plan));
|
|
3134
|
+
const expectedCaptureKinds = actual.grammarCaptureTriviaKinds.map((plan) => JSON.stringify(plan));
|
|
3135
|
+
const suppliedCaptureKinds = (alphabet.grammarCaptureTriviaKinds ?? []).map((plan) => JSON.stringify(plan));
|
|
3136
|
+
const expectedTopologies = actual.boundaryTopologies.map((plan) => JSON.stringify(plan));
|
|
3137
|
+
const suppliedTopologies = (alphabet.boundaryTopologies ?? []).map((plan) => JSON.stringify(plan));
|
|
3138
|
+
const expectedContexts = actual.contextSnapshots.map((plan) => JSON.stringify(plan));
|
|
3139
|
+
const suppliedContexts = (alphabet.contextSnapshots ?? []).map((plan) => JSON.stringify(plan));
|
|
3140
|
+
const expectedOwnSkip = actual.ownSkipPlans.map((plan) => JSON.stringify(plan));
|
|
3141
|
+
const suppliedOwnSkip = (alphabet.ownSkipPlans ?? []).map((plan) => JSON.stringify(plan));
|
|
3142
|
+
const expectedScanPolicies = actual.scanConsumerPolicies.map((plan) => JSON.stringify(plan));
|
|
3143
|
+
const suppliedScanPolicies = (alphabet.scanConsumerPolicies ?? []).map((plan) => JSON.stringify(plan));
|
|
3144
|
+
if (expectedKeys.length !== suppliedKeys.length || expectedKeys.some((key, index) => key !== suppliedKeys[index]) || expectedLanguages.length !== suppliedLanguages.length || expectedLanguages.some((key, index) => key !== suppliedLanguages[index]) || expectedEdges.length !== suppliedEdges.length || expectedEdges.some((key, index) => key !== suppliedEdges[index]) || expectedBindingProjections.length !== suppliedBindingProjections.length || expectedBindingProjections.some((key, index) => key !== suppliedBindingProjections[index]) || expectedTerminalProjections.length !== suppliedTerminalProjections.length || expectedTerminalProjections.some((key, index) => key !== suppliedTerminalProjections[index]) || expectedFamilies.length !== suppliedFamilies.length || expectedFamilies.some((key, index) => key !== suppliedFamilies[index]) || expectedOutcomes.length !== suppliedOutcomes.length || expectedOutcomes.some((key, index) => key !== suppliedOutcomes[index]) || expectedDecisions.length !== suppliedDecisions.length || expectedDecisions.some((key, index) => key !== suppliedDecisions[index]) || expectedC2 !== suppliedC2 || actual.decisionEffectPlan.decisionCallbackAuthorities.length !== (alphabet.decisionEffectPlan?.decisionCallbackAuthorities.length ?? 0) || actual.decisionEffectPlan.decisionCallbackAuthorities.some((entry, index) => entry.callback !== alphabet.decisionEffectPlan?.decisionCallbackAuthorities[index]?.callback) || expectedPlans.length !== suppliedPlans.length || expectedPlans.some((key, index) => key !== suppliedPlans[index]) || expectedControlPlans.length !== suppliedControlPlans.length || expectedControlPlans.some((key, index) => key !== suppliedControlPlans[index]) || expectedBoundaryPlans.length !== suppliedBoundaryPlans.length || expectedBoundaryPlans.some((key, index) => key !== suppliedBoundaryPlans[index]) || expectedMaterializationPlans.length !== suppliedMaterializationPlans.length || expectedMaterializationPlans.some((key, index) => key !== suppliedMaterializationPlans[index]) || expectedGrammarSpecs.length !== suppliedGrammarSpecs.length || expectedGrammarSpecs.some((key, index) => key !== suppliedGrammarSpecs[index]) || expectedCaptureKinds.length !== suppliedCaptureKinds.length || expectedCaptureKinds.some((key, index) => key !== suppliedCaptureKinds[index]) || expectedTopologies.length !== suppliedTopologies.length || expectedTopologies.some((key, index) => key !== suppliedTopologies[index]) || expectedContexts.length !== suppliedContexts.length || expectedContexts.some((key, index) => key !== suppliedContexts[index]) || expectedOwnSkip.length !== suppliedOwnSkip.length || expectedOwnSkip.some((key, index) => key !== suppliedOwnSkip[index]) || expectedScanPolicies.length !== suppliedScanPolicies.length || expectedScanPolicies.some((key, index) => key !== suppliedScanPolicies[index])) {
|
|
3145
|
+
throw new Error("parseman: lexical capability census is incomplete after final grammar resolution");
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
function collectLexicalCapabilities(roots, resolve) {
|
|
3149
|
+
const inventory = lexicalCapabilityInventory(roots, resolve);
|
|
3150
|
+
const { languages: capabilityLanguages, ...fields } = inventory;
|
|
3151
|
+
return {
|
|
3152
|
+
...fields,
|
|
3153
|
+
capabilityLanguages,
|
|
3154
|
+
capabilityComplete: inventory.capabilities.every((site) => site.status.kind !== "gap") && inventory.bindingEdges.every((edge) => edge.status.kind !== "gap") && inventory.decisionEffectPlan.decisionEffects.every((effect) => effect.phase.executableLowering.kind !== "gap") && inventory.scanConsumerPolicies.every((policy) => policy.status.kind !== "gap")
|
|
3155
|
+
};
|
|
3156
|
+
}
|
|
3157
|
+
function foldAsciiCode(code) {
|
|
3158
|
+
return code >= 65 && code <= 90 ? code + 32 : code;
|
|
3159
|
+
}
|
|
3160
|
+
function rangeEquals(input, start, end, value, folded) {
|
|
3161
|
+
if (end - start !== value.length) return false;
|
|
3162
|
+
for (let i = 0; i < value.length; i++) {
|
|
3163
|
+
const actual = input.charCodeAt(start + i);
|
|
3164
|
+
const expected = value.charCodeAt(i);
|
|
3165
|
+
if ((folded ? foldAsciiCode(actual) : actual) !== (folded ? foldAsciiCode(expected) : expected)) return false;
|
|
3166
|
+
}
|
|
3167
|
+
return true;
|
|
3168
|
+
}
|
|
3169
|
+
function rangeStartsWith(input, start, end, value, folded) {
|
|
3170
|
+
return start + value.length <= end && rangeEquals(input, start, start + value.length, value, folded);
|
|
3171
|
+
}
|
|
3172
|
+
function rangeEndsWith(input, start, end, value, folded) {
|
|
3173
|
+
return end - value.length >= start && rangeEquals(input, end - value.length, end, value, folded);
|
|
3174
|
+
}
|
|
3175
|
+
function lexicalOutcomeMatches(match, input, start, end) {
|
|
3176
|
+
if (match.kind === "exact") {
|
|
3177
|
+
return match.values.some((value) => rangeEquals(input, start, end, value, match.caseInsensitive));
|
|
3178
|
+
}
|
|
3179
|
+
if (match.kind === "startsWith") return rangeStartsWith(input, start, end, match.value, match.caseInsensitive);
|
|
3180
|
+
if (match.kind === "endsWith") return rangeEndsWith(input, start, end, match.value, match.caseInsensitive);
|
|
3181
|
+
if ("flags" in match) {
|
|
3182
|
+
const flags = match.caseInsensitive && !match.flags.includes("i") ? `${match.flags}i` : match.flags;
|
|
3183
|
+
return new RegExp(match.value, flags).test(input.slice(start, end));
|
|
3184
|
+
}
|
|
3185
|
+
return false;
|
|
3186
|
+
}
|
|
3187
|
+
export {
|
|
3188
|
+
assertLexicalCapabilityClosure,
|
|
3189
|
+
collectLexicalCapabilities,
|
|
3190
|
+
winnerWrapsReference
|
|
3191
|
+
};
|
|
3192
|
+
//# sourceMappingURL=token-capability.js.map
|