parseman 0.52.0 → 0.53.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analysis/diagnostics.js +358 -8
- package/dist/analysis/diagnostics.js.map +3 -3
- package/dist/cli/index.js +5929 -6172
- package/dist/cli/index.js.map +3 -3
- package/dist/combinators/parser.d.ts +34 -0
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/combinators/ref.d.ts +0 -13
- package/dist/combinators/ref.d.ts.map +1 -1
- package/dist/compiler/borrowed-rules.d.ts +30 -0
- package/dist/compiler/borrowed-rules.d.ts.map +1 -0
- package/dist/compiler/compile-linkable-table.d.ts +1 -1
- package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts +10 -4
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +48 -91
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/coverage.d.ts +1 -1
- package/dist/coverage.d.ts.map +1 -1
- package/dist/cst/reflection.d.ts.map +1 -1
- package/dist/index.js +416 -704
- package/dist/index.js.map +3 -3
- package/dist/language-service/index.js.map +1 -1
- package/dist/plugin/evaluator.d.ts +38 -2
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +1073 -523
- package/dist/plugin/index.js.map +3 -3
- package/dist/plugin/ir-eval.d.ts +21 -0
- package/dist/plugin/ir-eval.d.ts.map +1 -0
- package/dist/plugin/reducer-resolver.d.ts +6 -0
- package/dist/plugin/reducer-resolver.d.ts.map +1 -1
- package/dist/spec/index.js +555 -6109
- package/dist/spec/index.js.map +3 -3
- package/dist/spec/railroad-lib.d.ts +7 -2
- package/dist/spec/railroad-lib.d.ts.map +1 -1
- package/dist/spec/railroad.d.ts.map +1 -1
- package/dist/table/compile-rule-map.d.ts +11 -4
- package/dist/table/compile-rule-map.d.ts.map +1 -1
- package/dist/table/compile.d.ts +16 -0
- package/dist/table/compile.d.ts.map +1 -1
- package/dist/table/index.js +235 -87
- package/dist/table/index.js.map +2 -2
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/combinators/parser.ts +133 -67
- package/src/combinators/ref.ts +10 -1
- package/src/compiler/borrowed-rules.ts +88 -0
- package/src/compiler/compile-linkable-table.ts +1 -1
- package/src/compiler/grammar-coverage-ids.ts +35 -6
- package/src/compiler/ir-serialize.ts +12 -118
- package/src/compiler/linker.ts +190 -666
- package/src/coverage.ts +6 -4
- package/src/cst/reflection.ts +6 -1
- package/src/plugin/evaluator.ts +113 -13
- package/src/plugin/index.ts +588 -110
- package/src/plugin/ir-eval.ts +165 -0
- package/src/plugin/reducer-resolver.ts +20 -3
- package/src/spec/railroad-lib.ts +18 -8
- package/src/spec/railroad.ts +3 -4
- package/src/table/compile-rule-map.ts +18 -8
- package/src/table/compile.ts +61 -0
- package/src/version.ts +1 -1
package/dist/table/index.js
CHANGED
|
@@ -3392,6 +3392,7 @@ function withRuleTrivia(trivia2, ctx, run) {
|
|
|
3392
3392
|
ctx.triviaKindLabels = savedLabels;
|
|
3393
3393
|
}
|
|
3394
3394
|
}
|
|
3395
|
+
var UNDEFINED_REF = new Error("ref<T>() used before .define() was called");
|
|
3395
3396
|
function ref() {
|
|
3396
3397
|
let resolved = null;
|
|
3397
3398
|
let resolvedScalar = null;
|
|
@@ -3407,7 +3408,7 @@ function ref() {
|
|
|
3407
3408
|
_def: {
|
|
3408
3409
|
tag: "lazy",
|
|
3409
3410
|
thunk: () => {
|
|
3410
|
-
if (!resolved) throw
|
|
3411
|
+
if (!resolved) throw UNDEFINED_REF;
|
|
3411
3412
|
return resolved;
|
|
3412
3413
|
}
|
|
3413
3414
|
},
|
|
@@ -13801,7 +13802,8 @@ function children(def, winners) {
|
|
|
13801
13802
|
return [];
|
|
13802
13803
|
}
|
|
13803
13804
|
const name = resolved._ruleName;
|
|
13804
|
-
|
|
13805
|
+
const winner = name ? winners?.[name] : void 0;
|
|
13806
|
+
return winner !== void 0 && winner._def !== def ? [winner] : [resolved];
|
|
13805
13807
|
}
|
|
13806
13808
|
default:
|
|
13807
13809
|
return [];
|
|
@@ -13826,16 +13828,39 @@ function buildGrammarPlan(entry, winners) {
|
|
|
13826
13828
|
}
|
|
13827
13829
|
}
|
|
13828
13830
|
}
|
|
13831
|
+
const selfWinnerBody = (parser) => {
|
|
13832
|
+
if (parser._def.tag !== "lazy" || winners === void 0) return void 0;
|
|
13833
|
+
const name = winnerNames.get(parser);
|
|
13834
|
+
if (name === void 0 || winners[name] !== parser) return void 0;
|
|
13835
|
+
try {
|
|
13836
|
+
return parser._def.thunk();
|
|
13837
|
+
} catch {
|
|
13838
|
+
return void 0;
|
|
13839
|
+
}
|
|
13840
|
+
};
|
|
13841
|
+
const slotsPerBody = /* @__PURE__ */ new Map();
|
|
13842
|
+
if (winners) {
|
|
13843
|
+
for (const winner of Object.values(winners)) {
|
|
13844
|
+
const body = selfWinnerBody(winner);
|
|
13845
|
+
if (body !== void 0) slotsPerBody.set(body, (slotsPerBody.get(body) ?? 0) + 1);
|
|
13846
|
+
}
|
|
13847
|
+
}
|
|
13848
|
+
const sharedBody = (parser) => (slotsPerBody.get(parser) ?? 0) > 1;
|
|
13849
|
+
const ownRule = (parser, rule) => {
|
|
13850
|
+
const id = `rule:${rule}`;
|
|
13851
|
+
definitions.set(id, { id, kind: "rule" });
|
|
13852
|
+
rules.set(parser, id);
|
|
13853
|
+
};
|
|
13829
13854
|
const seen = /* @__PURE__ */ new Set();
|
|
13830
13855
|
const visit = (parser, path) => {
|
|
13831
13856
|
if (seen.has(parser)) return;
|
|
13832
13857
|
seen.add(parser);
|
|
13833
13858
|
const rule = winnerNames.get(parser) ?? parser._ruleName;
|
|
13834
|
-
|
|
13835
|
-
|
|
13836
|
-
|
|
13837
|
-
rules.set(parser, id);
|
|
13859
|
+
const body = selfWinnerBody(parser);
|
|
13860
|
+
if (rule && body === void 0 && !sharedBody(parser) && (winnerNames.has(parser) || parser._def.tag !== "lazy")) {
|
|
13861
|
+
ownRule(parser, rule);
|
|
13838
13862
|
}
|
|
13863
|
+
if (rule && body !== void 0 && sharedBody(body)) ownRule(parser, rule);
|
|
13839
13864
|
if (parser._def.tag === "choice") {
|
|
13840
13865
|
const ids = parser._def.parsers.map((_, index) => `choice:${path}/arm:${index}`);
|
|
13841
13866
|
choices.set(parser, ids);
|
|
@@ -13856,7 +13881,13 @@ function buildGrammarPlan(entry, winners) {
|
|
|
13856
13881
|
};
|
|
13857
13882
|
const roots = Array.isArray(entry) ? entry : [entry];
|
|
13858
13883
|
for (const root of roots) {
|
|
13859
|
-
|
|
13884
|
+
const name = winnerNames.get(root) ?? root._ruleName ?? "entry";
|
|
13885
|
+
const body = selfWinnerBody(root);
|
|
13886
|
+
if (body !== void 0 && sharedBody(body) && !seen.has(root)) {
|
|
13887
|
+
seen.add(root);
|
|
13888
|
+
ownRule(root, name);
|
|
13889
|
+
}
|
|
13890
|
+
visit(body ?? root, name);
|
|
13860
13891
|
}
|
|
13861
13892
|
return { definitions: [...definitions.values()].sort((a, b) => a.id.localeCompare(b.id)), choices, dispatches, attempts, labels, rules };
|
|
13862
13893
|
}
|
|
@@ -15162,84 +15193,8 @@ function runDuplicationDiagnosticRules(ruleMap, opt) {
|
|
|
15162
15193
|
return reportDuplication(opt, (o) => analyzeDuplicationRules(ruleMap, o));
|
|
15163
15194
|
}
|
|
15164
15195
|
|
|
15165
|
-
// src/
|
|
15166
|
-
var
|
|
15167
|
-
function ownSource(fn) {
|
|
15168
|
-
if (typeof fn !== "function") return null;
|
|
15169
|
-
const text = Function.prototype.toString.call(fn);
|
|
15170
|
-
if (!text.includes("[native code]")) return text;
|
|
15171
|
-
const name = fn.name;
|
|
15172
|
-
return typeof name === "string" && name.length > 0 && globalThis[name] === fn ? name : null;
|
|
15173
|
-
}
|
|
15174
|
-
function compile(combinator, mapFnSources, opts = {}) {
|
|
15175
|
-
runDuplicationDiagnostic(combinator, opts.duplication);
|
|
15176
|
-
const drain = beginCompileDegradationDrain();
|
|
15177
|
-
let compiled = false;
|
|
15178
|
-
try {
|
|
15179
|
-
const out = compileImpl(combinator, mapFnSources, opts);
|
|
15180
|
-
compiled = true;
|
|
15181
|
-
return out;
|
|
15182
|
-
} finally {
|
|
15183
|
-
drain(compiled);
|
|
15184
|
-
}
|
|
15185
|
-
}
|
|
15186
|
-
function compileImpl(combinator, mapFnSources, opts = {}) {
|
|
15187
|
-
const plan = opts.coverage === true ? buildGrammarPlan(combinator) : void 0;
|
|
15188
|
-
const settings = {
|
|
15189
|
-
...opts.hostMode === void 0 ? {} : { hostMode: opts.hostMode },
|
|
15190
|
-
...opts.trackLines === void 0 ? {} : { trackLines: opts.trackLines },
|
|
15191
|
-
...plan === void 0 ? {} : { coverage: plan }
|
|
15192
|
-
};
|
|
15193
|
-
const { prog, fnSrcs } = encodeTableProgram({ [ENTRY]: combinator }, settings);
|
|
15194
|
-
const artifact = closureArtifact(prog);
|
|
15195
|
-
const entry = tableRules(prog)[ENTRY];
|
|
15196
|
-
const offered = opts.fnSources ?? mapFnSources;
|
|
15197
|
-
const supplied = offered !== void 0 && offered.length === fnSrcs.length ? offered : void 0;
|
|
15198
|
-
const sources = fnSrcs.map((s, i) => s ?? supplied?.[i] ?? ownSource(prog.fns[i]));
|
|
15199
|
-
const unsourced = sources.reduce((acc, s, i) => s === null ? [...acc, i] : acc, []);
|
|
15200
|
-
const runtimeOnly = [
|
|
15201
|
-
...prog.runtimeOnly ?? [],
|
|
15202
|
-
...unsourced.length === 0 ? [] : [`author reducer source missing for prog.fns[${unsourced.join(", ")}] \u2014 printing would emit \`() => {}\` and the parse would return no value`]
|
|
15203
|
-
];
|
|
15204
|
-
const printable = runtimeOnly.length === 0;
|
|
15205
|
-
const emitOpts = { fnSources: sources };
|
|
15206
|
-
const source = printable ? emitTableModule(artifact, { name: "grammar", ...emitOpts }) : "";
|
|
15207
|
-
const inlineExpression = printable ? emitTableExpression(artifact, { entry: ENTRY, runtimeRef: opts.runtimeRef ?? "tableRules", ...emitOpts }) : null;
|
|
15208
|
-
const runOnce = (input, pos, ctx) => entry(input, pos, ctx);
|
|
15209
|
-
return {
|
|
15210
|
-
source,
|
|
15211
|
-
inlineExpression,
|
|
15212
|
-
...printable ? {} : { runtimeOnly },
|
|
15213
|
-
// The DENOMINATOR, handed back rather than scraped out of the emitted text.
|
|
15214
|
-
// `plugin/index.ts` prefers a compiler-supplied `coverageDefinitions` and only
|
|
15215
|
-
// falls back to regex-scanning generated hooks; a table has no hooks to scan,
|
|
15216
|
-
// so this is the channel.
|
|
15217
|
-
...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
|
|
15218
|
-
parse(input, pos = 0) {
|
|
15219
|
-
return runOnce(input, pos, createParseContext());
|
|
15220
|
-
},
|
|
15221
|
-
parseWithContext(input, parseCtx, pos = 0) {
|
|
15222
|
-
return runOnce(input, pos, parseCtx);
|
|
15223
|
-
},
|
|
15224
|
-
/**
|
|
15225
|
-
* NO LONGER REFUSES. It used to throw unless the caller passed
|
|
15226
|
-
* `{ recovery: true }`, because setting `_tolerant` on a table with no
|
|
15227
|
-
* recovery rows would report a clean parse with an empty error list whatever
|
|
15228
|
-
* the input — refusing was the right answer to that, and OPTIONAL RECOVERY
|
|
15229
|
-
* was the wrong question. `compile()` requires no such flag, so the refusal
|
|
15230
|
-
* was a `CompiledParser` contract break; recovery is now always lowered and
|
|
15231
|
-
* there is nothing left to refuse.
|
|
15232
|
-
*/
|
|
15233
|
-
parseWithErrors(input, pos = 0) {
|
|
15234
|
-
const ctx = createParseContext();
|
|
15235
|
-
const errors = [];
|
|
15236
|
-
ctx._errors = errors;
|
|
15237
|
-
ctx._tolerant = true;
|
|
15238
|
-
const r = runOnce(input, pos, ctx);
|
|
15239
|
-
return { ...r, errors };
|
|
15240
|
-
}
|
|
15241
|
-
};
|
|
15242
|
-
}
|
|
15196
|
+
// src/cst/reflection-symbols.ts
|
|
15197
|
+
var GRAMMAR_REFLECTION = /* @__PURE__ */ Symbol.for("parseman.grammarReflection");
|
|
15243
15198
|
|
|
15244
15199
|
// src/cst/reflection.ts
|
|
15245
15200
|
function childrenOf2(def) {
|
|
@@ -15326,6 +15281,7 @@ function collectFromCombinator(parser, out, seen, followLazy = true) {
|
|
|
15326
15281
|
function collectGrammarReflection(ruleMap, opts) {
|
|
15327
15282
|
const byType = /* @__PURE__ */ new Map();
|
|
15328
15283
|
const followLazy = opts?.followLazy !== false;
|
|
15284
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15329
15285
|
for (const [, rule] of ruleMap) {
|
|
15330
15286
|
if (!followLazy && rule._def.tag === "lazy") {
|
|
15331
15287
|
try {
|
|
@@ -15335,7 +15291,7 @@ function collectGrammarReflection(ruleMap, opts) {
|
|
|
15335
15291
|
}
|
|
15336
15292
|
continue;
|
|
15337
15293
|
}
|
|
15338
|
-
collectFromCombinator(rule, byType,
|
|
15294
|
+
collectFromCombinator(rule, byType, seen, followLazy);
|
|
15339
15295
|
}
|
|
15340
15296
|
return { nodes: [...byType].map(([type, tags]) => ({ type, tags })) };
|
|
15341
15297
|
}
|
|
@@ -15371,6 +15327,24 @@ function withAmbient(ruleMap, opts) {
|
|
|
15371
15327
|
return [name, wrapped];
|
|
15372
15328
|
});
|
|
15373
15329
|
}
|
|
15330
|
+
function compileRuleMapRunnable(ruleMap, opts = {}) {
|
|
15331
|
+
const encoded = encodeForRun(ruleMap, opts);
|
|
15332
|
+
if (encoded === null) return null;
|
|
15333
|
+
const { prog, hostMode, plan } = encoded;
|
|
15334
|
+
const artifact = closureArtifact(prog);
|
|
15335
|
+
const reflection = collectGrammarReflection(ruleMap);
|
|
15336
|
+
return {
|
|
15337
|
+
keys: ruleMap.map(([key]) => key),
|
|
15338
|
+
hostMode,
|
|
15339
|
+
hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
|
|
15340
|
+
reflection,
|
|
15341
|
+
...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
|
|
15342
|
+
// Reflection rides on the map's metadata prototype from birth. Only `compile()`
|
|
15343
|
+
// asks to specialise; every other caller runs the closure artifact.
|
|
15344
|
+
rules: tableRules(opts.specialise === true ? prog : artifact, { [GRAMMAR_REFLECTION]: reflection }),
|
|
15345
|
+
prog: artifact
|
|
15346
|
+
};
|
|
15347
|
+
}
|
|
15374
15348
|
function encodeForRun(ruleMap, opts) {
|
|
15375
15349
|
runDuplicationDiagnosticRules(ruleMap, opts.duplication);
|
|
15376
15350
|
const encodeMap = withAmbient(ruleMap, opts);
|
|
@@ -15439,11 +15413,185 @@ function compileRuleMap(ruleMap, opts = {}) {
|
|
|
15439
15413
|
hostBranchElided: hostMode === "ast" && ruleMap.some(([, rule]) => hasDirectBuildDef(rule)),
|
|
15440
15414
|
reflection: collectGrammarReflection(ruleMap),
|
|
15441
15415
|
...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
|
|
15442
|
-
rules: tableRules(
|
|
15416
|
+
rules: tableRules(artifact),
|
|
15443
15417
|
prog: artifact
|
|
15444
15418
|
};
|
|
15445
15419
|
}
|
|
15446
15420
|
|
|
15421
|
+
// src/compiler/borrowed-rules.ts
|
|
15422
|
+
var nameOf = (c) => c._ruleName;
|
|
15423
|
+
function deref(c) {
|
|
15424
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15425
|
+
let current = c;
|
|
15426
|
+
while (current._def.tag === "lazy" && !seen.has(current)) {
|
|
15427
|
+
seen.add(current);
|
|
15428
|
+
try {
|
|
15429
|
+
current = current._def.thunk();
|
|
15430
|
+
} catch {
|
|
15431
|
+
return void 0;
|
|
15432
|
+
}
|
|
15433
|
+
}
|
|
15434
|
+
return current;
|
|
15435
|
+
}
|
|
15436
|
+
function borrowedRuleReference(map) {
|
|
15437
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15438
|
+
for (const [rule, self] of Object.entries(map)) {
|
|
15439
|
+
let found;
|
|
15440
|
+
const visit = (c) => {
|
|
15441
|
+
if (found !== void 0) return;
|
|
15442
|
+
if (c._def.tag === "lazy") {
|
|
15443
|
+
if (!winnerWrapsReference(self, c)) {
|
|
15444
|
+
const name = nameOf(c);
|
|
15445
|
+
const winner = name !== void 0 && Object.hasOwn(map, name) ? map[name] : void 0;
|
|
15446
|
+
if (winner !== void 0) {
|
|
15447
|
+
if (winnerWrapsReference(winner, c) || deref(c) === deref(winner)) return;
|
|
15448
|
+
found = name;
|
|
15449
|
+
return;
|
|
15450
|
+
}
|
|
15451
|
+
}
|
|
15452
|
+
if (seen.has(c)) return;
|
|
15453
|
+
seen.add(c);
|
|
15454
|
+
let body;
|
|
15455
|
+
try {
|
|
15456
|
+
body = c._def.thunk();
|
|
15457
|
+
} catch {
|
|
15458
|
+
return;
|
|
15459
|
+
}
|
|
15460
|
+
visit(body);
|
|
15461
|
+
return;
|
|
15462
|
+
}
|
|
15463
|
+
if (seen.has(c)) return;
|
|
15464
|
+
seen.add(c);
|
|
15465
|
+
for (const child of childrenOf(c._def)) visit(child);
|
|
15466
|
+
};
|
|
15467
|
+
visit(self);
|
|
15468
|
+
if (found !== void 0) return { rule, reference: found };
|
|
15469
|
+
}
|
|
15470
|
+
return void 0;
|
|
15471
|
+
}
|
|
15472
|
+
function borrowedRuleMessage(api, hit) {
|
|
15473
|
+
return `${api}: rule "${hit.rule}" is a rule object borrowed from another grammar, and its graph references "${hit.reference}", which this grammar also defines. The interpreter would keep the other grammar's "${hit.reference}" while a compiled table binds this grammar's, so the two would accept different input. Compose the grammar that defines "${hit.rule}" instead of borrowing its rule object, so its references resolve to this grammar's rules.`;
|
|
15474
|
+
}
|
|
15475
|
+
|
|
15476
|
+
// src/table/compile.ts
|
|
15477
|
+
var ENTRY = "Entry";
|
|
15478
|
+
function ownSource(fn) {
|
|
15479
|
+
if (typeof fn !== "function") return null;
|
|
15480
|
+
const text = Function.prototype.toString.call(fn);
|
|
15481
|
+
if (!text.includes("[native code]")) return text;
|
|
15482
|
+
const name = fn.name;
|
|
15483
|
+
return typeof name === "string" && name.length > 0 && globalThis[name] === fn ? name : null;
|
|
15484
|
+
}
|
|
15485
|
+
function compile(target, second, third) {
|
|
15486
|
+
if (!isCombinator(target)) return compileMap(target, second);
|
|
15487
|
+
return compileRoot(target, second, third);
|
|
15488
|
+
}
|
|
15489
|
+
function isCombinator(x) {
|
|
15490
|
+
return typeof x === "object" && x !== null && typeof x.parse === "function" && "_def" in x;
|
|
15491
|
+
}
|
|
15492
|
+
function compileMap(grammar, opts = {}) {
|
|
15493
|
+
const entries = [];
|
|
15494
|
+
for (const [key, value] of Object.entries(grammar)) {
|
|
15495
|
+
if (!isCombinator(value)) throw new TypeError(`compile: grammar entry "${key}" is not a parser`);
|
|
15496
|
+
if (value._def.tag === "lazy") {
|
|
15497
|
+
try {
|
|
15498
|
+
value._def.thunk();
|
|
15499
|
+
} catch {
|
|
15500
|
+
continue;
|
|
15501
|
+
}
|
|
15502
|
+
}
|
|
15503
|
+
entries.push([key, value]);
|
|
15504
|
+
}
|
|
15505
|
+
const borrowed = borrowedRuleReference(Object.fromEntries(entries));
|
|
15506
|
+
if (borrowed !== void 0) throw new Error(borrowedRuleMessage("compile", borrowed));
|
|
15507
|
+
const drain = beginCompileDegradationDrain();
|
|
15508
|
+
let done = false;
|
|
15509
|
+
try {
|
|
15510
|
+
const refusals = [];
|
|
15511
|
+
const compiled = compileRuleMapRunnable(entries, {
|
|
15512
|
+
...opts.hostMode ? { hostMode: opts.hostMode } : {},
|
|
15513
|
+
refusals,
|
|
15514
|
+
specialise: true
|
|
15515
|
+
});
|
|
15516
|
+
if (compiled === null) {
|
|
15517
|
+
throw new Error(`compile: this grammar could not be encoded to a table${refusals.length ? ` \u2014 ${refusals.join("; ")}` : ""}`);
|
|
15518
|
+
}
|
|
15519
|
+
done = true;
|
|
15520
|
+
return compiled.rules;
|
|
15521
|
+
} finally {
|
|
15522
|
+
drain(done);
|
|
15523
|
+
}
|
|
15524
|
+
}
|
|
15525
|
+
function compileRoot(combinator, mapFnSources, opts = {}) {
|
|
15526
|
+
runDuplicationDiagnostic(combinator, opts.duplication);
|
|
15527
|
+
const drain = beginCompileDegradationDrain();
|
|
15528
|
+
let compiled = false;
|
|
15529
|
+
try {
|
|
15530
|
+
const out = compileImpl(combinator, mapFnSources, opts);
|
|
15531
|
+
compiled = true;
|
|
15532
|
+
return out;
|
|
15533
|
+
} finally {
|
|
15534
|
+
drain(compiled);
|
|
15535
|
+
}
|
|
15536
|
+
}
|
|
15537
|
+
function compileImpl(combinator, mapFnSources, opts = {}) {
|
|
15538
|
+
const plan = opts.coverage === true ? buildGrammarPlan(combinator) : void 0;
|
|
15539
|
+
const settings = {
|
|
15540
|
+
...opts.hostMode === void 0 ? {} : { hostMode: opts.hostMode },
|
|
15541
|
+
...opts.trackLines === void 0 ? {} : { trackLines: opts.trackLines },
|
|
15542
|
+
...plan === void 0 ? {} : { coverage: plan }
|
|
15543
|
+
};
|
|
15544
|
+
const { prog, fnSrcs } = encodeTableProgram({ [ENTRY]: combinator }, settings);
|
|
15545
|
+
const artifact = closureArtifact(prog);
|
|
15546
|
+
const entry = tableRules(prog)[ENTRY];
|
|
15547
|
+
const offered = opts.fnSources ?? mapFnSources;
|
|
15548
|
+
const supplied = offered !== void 0 && offered.length === fnSrcs.length ? offered : void 0;
|
|
15549
|
+
const sources = fnSrcs.map((s, i) => s ?? supplied?.[i] ?? ownSource(prog.fns[i]));
|
|
15550
|
+
const unsourced = sources.reduce((acc, s, i) => s === null ? [...acc, i] : acc, []);
|
|
15551
|
+
const runtimeOnly = [
|
|
15552
|
+
...prog.runtimeOnly ?? [],
|
|
15553
|
+
...unsourced.length === 0 ? [] : [`author reducer source missing for prog.fns[${unsourced.join(", ")}] \u2014 printing would emit \`() => {}\` and the parse would return no value`]
|
|
15554
|
+
];
|
|
15555
|
+
const printable = runtimeOnly.length === 0;
|
|
15556
|
+
const emitOpts = { fnSources: sources };
|
|
15557
|
+
const source = printable ? emitTableModule(artifact, { name: "grammar", ...emitOpts }) : "";
|
|
15558
|
+
const inlineExpression = printable ? emitTableExpression(artifact, { entry: ENTRY, runtimeRef: opts.runtimeRef ?? "tableRules", ...emitOpts }) : null;
|
|
15559
|
+
const runOnce = (input, pos, ctx) => entry(input, pos, ctx);
|
|
15560
|
+
return {
|
|
15561
|
+
source,
|
|
15562
|
+
inlineExpression,
|
|
15563
|
+
...printable ? {} : { runtimeOnly },
|
|
15564
|
+
// The DENOMINATOR, handed back rather than scraped out of the emitted text.
|
|
15565
|
+
// `plugin/index.ts` prefers a compiler-supplied `coverageDefinitions` and only
|
|
15566
|
+
// falls back to regex-scanning generated hooks; a table has no hooks to scan,
|
|
15567
|
+
// so this is the channel.
|
|
15568
|
+
...plan === void 0 ? {} : { coverageDefinitions: plan.definitions },
|
|
15569
|
+
parse(input, pos = 0) {
|
|
15570
|
+
return runOnce(input, pos, createParseContext());
|
|
15571
|
+
},
|
|
15572
|
+
parseWithContext(input, parseCtx, pos = 0) {
|
|
15573
|
+
return runOnce(input, pos, parseCtx);
|
|
15574
|
+
},
|
|
15575
|
+
/**
|
|
15576
|
+
* NO LONGER REFUSES. It used to throw unless the caller passed
|
|
15577
|
+
* `{ recovery: true }`, because setting `_tolerant` on a table with no
|
|
15578
|
+
* recovery rows would report a clean parse with an empty error list whatever
|
|
15579
|
+
* the input — refusing was the right answer to that, and OPTIONAL RECOVERY
|
|
15580
|
+
* was the wrong question. `compile()` requires no such flag, so the refusal
|
|
15581
|
+
* was a `CompiledParser` contract break; recovery is now always lowered and
|
|
15582
|
+
* there is nothing left to refuse.
|
|
15583
|
+
*/
|
|
15584
|
+
parseWithErrors(input, pos = 0) {
|
|
15585
|
+
const ctx = createParseContext();
|
|
15586
|
+
const errors = [];
|
|
15587
|
+
ctx._errors = errors;
|
|
15588
|
+
ctx._tolerant = true;
|
|
15589
|
+
const r = runOnce(input, pos, ctx);
|
|
15590
|
+
return { ...r, errors };
|
|
15591
|
+
}
|
|
15592
|
+
};
|
|
15593
|
+
}
|
|
15594
|
+
|
|
15447
15595
|
// src/table/fold.ts
|
|
15448
15596
|
function tableVariants(source, name) {
|
|
15449
15597
|
const folded = "base" in source ? source : expandCompactFolded(source);
|