parseman 0.13.0 → 0.14.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/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +1 -1
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/combinators/regex-analyze.d.ts +6 -0
- package/dist/combinators/regex-analyze.d.ts.map +1 -0
- package/dist/combinators/regex.d.ts +16 -1
- package/dist/combinators/regex.d.ts.map +1 -1
- package/dist/compiler/build-arity.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts +45 -0
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/inline-build.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +44 -0
- package/dist/compiler/linker.d.ts.map +1 -0
- package/dist/compiler/scannable-run.d.ts.map +1 -1
- package/dist/cst/offset-model.d.ts +119 -0
- package/dist/cst/offset-model.d.ts.map +1 -0
- package/dist/cst/relative-spans.d.ts +56 -0
- package/dist/cst/relative-spans.d.ts.map +1 -0
- package/dist/functional/doc.d.ts +20 -0
- package/dist/functional/doc.d.ts.map +1 -1
- package/dist/functional/run.d.ts +63 -0
- package/dist/functional/run.d.ts.map +1 -0
- package/dist/index.cjs +902 -112
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +902 -112
- package/dist/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts +2 -28
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +710 -250
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +710 -250
- package/dist/plugin/index.js.map +4 -4
- package/dist/types.d.ts +12 -3
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -1
package/dist/plugin/index.cjs
CHANGED
|
@@ -323,6 +323,36 @@ function literal(value, opts = {}) {
|
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
// src/combinators/regex.ts
|
|
326
|
+
var firstSetAnalyzer = null;
|
|
327
|
+
function registerRegexAnalyzer(analyzer) {
|
|
328
|
+
firstSetAnalyzer = analyzer;
|
|
329
|
+
}
|
|
330
|
+
var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
|
|
331
|
+
function regex(pattern, flags = "") {
|
|
332
|
+
const source = typeof pattern === "string" ? pattern : pattern.source;
|
|
333
|
+
const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
|
|
334
|
+
const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
|
|
335
|
+
const { firstSet, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
|
|
336
|
+
const meta = { firstSet, canMatchNewline, isTrivia: false };
|
|
337
|
+
return {
|
|
338
|
+
_tag: "regex",
|
|
339
|
+
_meta: meta,
|
|
340
|
+
_def: { tag: "regex", source, flags: resolvedFlags },
|
|
341
|
+
parse(input, pos, ctx) {
|
|
342
|
+
anchored.lastIndex = pos;
|
|
343
|
+
const m = anchored.exec(input);
|
|
344
|
+
if (m === null) {
|
|
345
|
+
return failAt(ctx, [`/${source}/`], pos);
|
|
346
|
+
}
|
|
347
|
+
const span = { start: pos, end: pos + m[0].length };
|
|
348
|
+
const leaf = { _tag: "leaf", value: m[0], span };
|
|
349
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
|
|
350
|
+
return { ok: true, value: m[0], span };
|
|
351
|
+
}
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// src/combinators/regex-analyze.ts
|
|
326
356
|
var import_regexp_tree = __toESM(require("regexp-tree"), 1);
|
|
327
357
|
function firstSetFromRegex(pattern) {
|
|
328
358
|
try {
|
|
@@ -427,40 +457,6 @@ function extractFirstSet(node2) {
|
|
|
427
457
|
return { firstSet: any(), canMatchNewline: true };
|
|
428
458
|
}
|
|
429
459
|
}
|
|
430
|
-
function optimizeRegex(source, flags) {
|
|
431
|
-
try {
|
|
432
|
-
const result = import_regexp_tree.default.optimize(`/${source}/${flags}`);
|
|
433
|
-
const str = result.toString();
|
|
434
|
-
const lastSlash = str.lastIndexOf("/");
|
|
435
|
-
return str.slice(1, lastSlash);
|
|
436
|
-
} catch {
|
|
437
|
-
return source;
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
function regex(pattern, flags = "") {
|
|
441
|
-
const source = typeof pattern === "string" ? pattern : pattern.source;
|
|
442
|
-
const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
|
|
443
|
-
const optimizedSource = optimizeRegex(source, resolvedFlags);
|
|
444
|
-
const anchored = new RegExp(optimizedSource, "y" + resolvedFlags.replace(/[gy]/g, ""));
|
|
445
|
-
const { firstSet, canMatchNewline } = firstSetFromRegex(source);
|
|
446
|
-
const meta = { firstSet, canMatchNewline, isTrivia: false };
|
|
447
|
-
return {
|
|
448
|
-
_tag: "regex",
|
|
449
|
-
_meta: meta,
|
|
450
|
-
_def: { tag: "regex", source, flags: resolvedFlags, optimizedSource },
|
|
451
|
-
parse(input, pos, ctx) {
|
|
452
|
-
anchored.lastIndex = pos;
|
|
453
|
-
const m = anchored.exec(input);
|
|
454
|
-
if (m === null) {
|
|
455
|
-
return failAt(ctx, [`/${source}/`], pos);
|
|
456
|
-
}
|
|
457
|
-
const span = { start: pos, end: pos + m[0].length };
|
|
458
|
-
const leaf = { _tag: "leaf", value: m[0], span };
|
|
459
|
-
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
|
|
460
|
-
return { ok: true, value: m[0], span };
|
|
461
|
-
}
|
|
462
|
-
};
|
|
463
|
-
}
|
|
464
460
|
|
|
465
461
|
// src/combinators/keywords.ts
|
|
466
462
|
function word(str, boundary = "_0-9A-Za-z") {
|
|
@@ -1160,12 +1156,14 @@ function confirmedBuildArity(src) {
|
|
|
1160
1156
|
return parts.length;
|
|
1161
1157
|
}
|
|
1162
1158
|
function buildReadsTrivia(def) {
|
|
1159
|
+
if (!def.build) return true;
|
|
1163
1160
|
const src = def.buildSrc ?? def.build.toString();
|
|
1164
1161
|
const arity = confirmedBuildArity(src);
|
|
1165
1162
|
if (arity === null) return true;
|
|
1166
1163
|
return arity >= 4;
|
|
1167
1164
|
}
|
|
1168
1165
|
function buildReadsState(def) {
|
|
1166
|
+
if (!def.build) return true;
|
|
1169
1167
|
const src = def.buildSrc ?? def.build.toString();
|
|
1170
1168
|
const arity = confirmedBuildArity(src);
|
|
1171
1169
|
if (arity === null) return true;
|
|
@@ -1184,8 +1182,8 @@ function node(type, combinator, build, opts) {
|
|
|
1184
1182
|
};
|
|
1185
1183
|
const collapse = opts?.collapse === true;
|
|
1186
1184
|
const def = collapse ? { tag: "node", type, parser: combinator, build, collapse: true } : { tag: "node", type, parser: combinator, build };
|
|
1187
|
-
const capturesTrivia = buildReadsTrivia(def);
|
|
1188
|
-
const clonesState = buildReadsState(def);
|
|
1185
|
+
const capturesTrivia = build ? buildReadsTrivia(def) : true;
|
|
1186
|
+
const clonesState = build ? buildReadsState(def) : true;
|
|
1189
1187
|
return {
|
|
1190
1188
|
_tag: "node",
|
|
1191
1189
|
_meta: meta,
|
|
@@ -1196,13 +1194,8 @@ function node(type, combinator, build, opts) {
|
|
|
1196
1194
|
const r = combinator.parse(input, pos, ctx);
|
|
1197
1195
|
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
1198
1196
|
if (!r.ok) return r;
|
|
1199
|
-
const
|
|
1200
|
-
|
|
1201
|
-
rawChildren,
|
|
1202
|
-
r.span,
|
|
1203
|
-
triviaLog,
|
|
1204
|
-
clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0
|
|
1205
|
-
);
|
|
1197
|
+
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
1198
|
+
const built = collapse && children.length === 1 ? collapseChild(children[0]) : build ? build(children, rawChildren, r.span, triviaLog, st) : ctx.build ? ctx.build(type, children, rawChildren, r.span, triviaLog, st) : { _tag: "node", type, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children };
|
|
1206
1199
|
const isNodeLike = typeof built === "object" && built !== null && built._tag === "node";
|
|
1207
1200
|
const rawEntry = isNodeLike ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
|
|
1208
1201
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
@@ -1345,8 +1338,14 @@ function staticExpected(c) {
|
|
|
1345
1338
|
case "transform":
|
|
1346
1339
|
case "not":
|
|
1347
1340
|
return staticExpected(def.parser);
|
|
1348
|
-
case "lazy":
|
|
1349
|
-
|
|
1341
|
+
case "lazy": {
|
|
1342
|
+
const name = c._ruleName;
|
|
1343
|
+
try {
|
|
1344
|
+
return staticExpected(def.thunk());
|
|
1345
|
+
} catch {
|
|
1346
|
+
return name ? [name] : [];
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1350
1349
|
default:
|
|
1351
1350
|
return [];
|
|
1352
1351
|
}
|
|
@@ -1646,6 +1645,15 @@ function seqIsUnambiguous(parts) {
|
|
|
1646
1645
|
const p = parts[k];
|
|
1647
1646
|
const mandatory = p.part === "lit" ? !p.optional : p.min === 1;
|
|
1648
1647
|
if (mandatory) hasMandatory = true;
|
|
1648
|
+
if (p.part === "group") {
|
|
1649
|
+
const exposure = groupPartExposure(p);
|
|
1650
|
+
if (exposure === "unsupported") {
|
|
1651
|
+
const trailingOnce = k === parts.length - 1 && p.min === 1 && !p.unbounded;
|
|
1652
|
+
if (!trailingOnce) return false;
|
|
1653
|
+
} else if (exposure !== null) {
|
|
1654
|
+
if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1649
1657
|
const skippableSingle = p.part === "lit" && p.optional || p.part !== "lit" && !p.unbounded && p.min === 0;
|
|
1650
1658
|
const isUnboundedRepeat = p.part !== "lit" && p.unbounded;
|
|
1651
1659
|
if (skippableSingle || isUnboundedRepeat) {
|
|
@@ -1692,6 +1700,58 @@ function firstSetsDisjoint(a, b) {
|
|
|
1692
1700
|
if (a === "any" || b === "any") return false;
|
|
1693
1701
|
return classDisjoint(a, b);
|
|
1694
1702
|
}
|
|
1703
|
+
function fixedClassSeq(shape) {
|
|
1704
|
+
if (shape.kind !== "seq") return null;
|
|
1705
|
+
const out = [];
|
|
1706
|
+
for (const p of shape.parts) {
|
|
1707
|
+
if (p.part === "lit") {
|
|
1708
|
+
if (p.optional) return null;
|
|
1709
|
+
for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
|
|
1710
|
+
} else if (p.part === "run" && !p.unbounded && p.min === 1) {
|
|
1711
|
+
out.push({ ranges: p.ranges, negated: p.negated });
|
|
1712
|
+
} else {
|
|
1713
|
+
return null;
|
|
1714
|
+
}
|
|
1715
|
+
}
|
|
1716
|
+
return out.length ? out : null;
|
|
1717
|
+
}
|
|
1718
|
+
function altFixedMutuallyExclusive(shape) {
|
|
1719
|
+
if (shape.kind !== "alt" || shape.disjoint) return false;
|
|
1720
|
+
const lists = [];
|
|
1721
|
+
for (const arm of shape.arms) {
|
|
1722
|
+
const f = fixedClassSeq(arm);
|
|
1723
|
+
if (!f) return false;
|
|
1724
|
+
lists.push(f);
|
|
1725
|
+
}
|
|
1726
|
+
for (let i = 0; i < lists.length; i++) {
|
|
1727
|
+
for (let j = 0; j < lists.length; j++) {
|
|
1728
|
+
if (i === j) continue;
|
|
1729
|
+
const a = lists[i];
|
|
1730
|
+
const b = lists[j];
|
|
1731
|
+
if (a.length > b.length) continue;
|
|
1732
|
+
let disjointAt = false;
|
|
1733
|
+
for (let p = 0; p < a.length; p++) {
|
|
1734
|
+
if (classDisjoint(a[p], b[p])) {
|
|
1735
|
+
disjointAt = true;
|
|
1736
|
+
break;
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
if (!disjointAt) return false;
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
return true;
|
|
1743
|
+
}
|
|
1744
|
+
function groupPartExposure(part) {
|
|
1745
|
+
const innerWiggle = trailingBacktrackClass(part.inner);
|
|
1746
|
+
if (innerWiggle === "unsupported") return "unsupported";
|
|
1747
|
+
const requiredOnce = !part.unbounded && part.min === 1;
|
|
1748
|
+
if (requiredOnce) return innerWiggle;
|
|
1749
|
+
const dropExposed = shapeFirstAccept(part.inner);
|
|
1750
|
+
if (dropExposed === "any") return "unsupported";
|
|
1751
|
+
if (innerWiggle === null) return dropExposed;
|
|
1752
|
+
const unioned = unionCharSets([innerWiggle, dropExposed]);
|
|
1753
|
+
return unioned === "any" ? "unsupported" : unioned;
|
|
1754
|
+
}
|
|
1695
1755
|
function trailingBacktrackClass(shape) {
|
|
1696
1756
|
if (shape.kind === "chars") return { ranges: shape.ranges, negated: false };
|
|
1697
1757
|
if (shape.kind === "ident") return { ranges: shape.tail, negated: false };
|
|
@@ -1703,18 +1763,10 @@ function trailingBacktrackClass(shape) {
|
|
|
1703
1763
|
if (last.unbounded || last.min === 0) return { ranges: last.ranges, negated: last.negated };
|
|
1704
1764
|
return null;
|
|
1705
1765
|
}
|
|
1706
|
-
|
|
1707
|
-
if (innerWiggle === "unsupported") return "unsupported";
|
|
1708
|
-
const requiredOnce = !last.unbounded && last.min === 1;
|
|
1709
|
-
if (requiredOnce) return innerWiggle;
|
|
1710
|
-
const dropExposed = shapeFirstAccept(last.inner);
|
|
1711
|
-
if (dropExposed === "any") return "unsupported";
|
|
1712
|
-
if (innerWiggle === null) return dropExposed;
|
|
1713
|
-
const unioned = unionCharSets([innerWiggle, dropExposed]);
|
|
1714
|
-
return unioned === "any" ? "unsupported" : unioned;
|
|
1766
|
+
return groupPartExposure(last);
|
|
1715
1767
|
}
|
|
1716
1768
|
if (shape.kind === "alt") {
|
|
1717
|
-
if (!shape.disjoint) return "unsupported";
|
|
1769
|
+
if (!shape.disjoint) return altFixedMutuallyExclusive(shape) ? null : "unsupported";
|
|
1718
1770
|
const classes = shape.arms.map(trailingBacktrackClass);
|
|
1719
1771
|
if (classes.some((c) => c === "unsupported")) return "unsupported";
|
|
1720
1772
|
const concrete = classes.filter((c) => c !== null);
|
|
@@ -1854,7 +1906,7 @@ function seqFirstAccept(parts) {
|
|
|
1854
1906
|
function groupInnerSafe(shape) {
|
|
1855
1907
|
if (shape.kind === "chars" || shape.kind === "ident" || shape.kind === "seq" || shape.kind === "litFold") return true;
|
|
1856
1908
|
if (shape.kind === "lookahead") return groupInnerSafe(shape.inner);
|
|
1857
|
-
if (shape.kind === "alt") return
|
|
1909
|
+
if (shape.kind === "alt") return true;
|
|
1858
1910
|
return false;
|
|
1859
1911
|
}
|
|
1860
1912
|
function shapeFirstAccept(shape) {
|
|
@@ -1882,9 +1934,8 @@ function shapeFirstAccept(shape) {
|
|
|
1882
1934
|
return shapeFirstAccept(shape.inner);
|
|
1883
1935
|
// zero-width — doesn't change first-char acceptance
|
|
1884
1936
|
case "alt": {
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
return sets.length === shape.arms.length ? unionCharSets(sets) : "any";
|
|
1937
|
+
const sets = shape.firsts.map((f) => f === null ? "any" : f);
|
|
1938
|
+
return unionCharSets(sets);
|
|
1888
1939
|
}
|
|
1889
1940
|
}
|
|
1890
1941
|
}
|
|
@@ -1925,6 +1976,120 @@ function parseScanShape(source) {
|
|
|
1925
1976
|
}
|
|
1926
1977
|
return parseScanShapeCore(source);
|
|
1927
1978
|
}
|
|
1979
|
+
function splitDelimArms(body) {
|
|
1980
|
+
const arms = [];
|
|
1981
|
+
let depth = 0;
|
|
1982
|
+
let last = 0;
|
|
1983
|
+
let i = 0;
|
|
1984
|
+
while (i < body.length) {
|
|
1985
|
+
const ch = body[i];
|
|
1986
|
+
if (ch === "\\") {
|
|
1987
|
+
i += 2;
|
|
1988
|
+
continue;
|
|
1989
|
+
}
|
|
1990
|
+
if (ch === "[") {
|
|
1991
|
+
let j = i + 1;
|
|
1992
|
+
if (body[j] === "^") j++;
|
|
1993
|
+
while (j < body.length && body[j] !== "]") {
|
|
1994
|
+
if (body[j] === "\\") j += 2;
|
|
1995
|
+
else j++;
|
|
1996
|
+
}
|
|
1997
|
+
if (body[j] !== "]") return null;
|
|
1998
|
+
i = j + 1;
|
|
1999
|
+
continue;
|
|
2000
|
+
}
|
|
2001
|
+
if (ch === "(") {
|
|
2002
|
+
depth++;
|
|
2003
|
+
i++;
|
|
2004
|
+
continue;
|
|
2005
|
+
}
|
|
2006
|
+
if (ch === ")") {
|
|
2007
|
+
depth--;
|
|
2008
|
+
if (depth < 0) return null;
|
|
2009
|
+
i++;
|
|
2010
|
+
continue;
|
|
2011
|
+
}
|
|
2012
|
+
if (ch === "|" && depth === 0) {
|
|
2013
|
+
arms.push(body.slice(last, i));
|
|
2014
|
+
last = i + 1;
|
|
2015
|
+
}
|
|
2016
|
+
i++;
|
|
2017
|
+
}
|
|
2018
|
+
if (depth !== 0) return null;
|
|
2019
|
+
arms.push(body.slice(last));
|
|
2020
|
+
return arms;
|
|
2021
|
+
}
|
|
2022
|
+
function delimitedBodySound(body, close) {
|
|
2023
|
+
const l0 = close[0];
|
|
2024
|
+
if (close.length > 2) return false;
|
|
2025
|
+
const arms = splitDelimArms(body);
|
|
2026
|
+
if (!arms) return false;
|
|
2027
|
+
let bulkSeen = false;
|
|
2028
|
+
let guardSeen = false;
|
|
2029
|
+
for (const arm of arms) {
|
|
2030
|
+
const bulk = /^\[\^((?:\\.|[^\]])+)\]$/.exec(arm);
|
|
2031
|
+
if (bulk) {
|
|
2032
|
+
if (bulkSeen) return false;
|
|
2033
|
+
const ranges = parseClassRanges(bulk[1]);
|
|
2034
|
+
if (!ranges || ranges.length !== 1 || ranges[0][0] !== l0 || ranges[0][1] !== l0) return false;
|
|
2035
|
+
bulkSeen = true;
|
|
2036
|
+
continue;
|
|
2037
|
+
}
|
|
2038
|
+
if (close.length === 2 && arm.endsWith(")")) {
|
|
2039
|
+
const idx = arm.indexOf("(?!");
|
|
2040
|
+
if (idx === -1) return false;
|
|
2041
|
+
const prefix = literalCodePoints(arm.slice(0, idx));
|
|
2042
|
+
const op = parseClassOperand(arm.slice(idx + 3, -1));
|
|
2043
|
+
const prefixIsL0 = prefix?.length === 1 && prefix[0] === l0;
|
|
2044
|
+
const forbidsL1 = op && !op.negated && op.ranges.length === 1 && op.ranges[0][0] === close[1] && op.ranges[0][1] === close[1];
|
|
2045
|
+
if (!prefixIsL0 || !forbidsL1 || guardSeen) return false;
|
|
2046
|
+
guardSeen = true;
|
|
2047
|
+
continue;
|
|
2048
|
+
}
|
|
2049
|
+
return false;
|
|
2050
|
+
}
|
|
2051
|
+
return bulkSeen && guardSeen === (close.length === 2);
|
|
2052
|
+
}
|
|
2053
|
+
function parseDelimited(source) {
|
|
2054
|
+
if (source.includes("\\\\")) return null;
|
|
2055
|
+
let i = 0;
|
|
2056
|
+
while (i < source.length && source[i] !== "(") {
|
|
2057
|
+
i += source[i] === "\\" ? 2 : 1;
|
|
2058
|
+
}
|
|
2059
|
+
if (source[i] !== "(" || source[i + 1] !== "?" || source[i + 2] !== ":") return null;
|
|
2060
|
+
const openFrag = source.slice(0, i);
|
|
2061
|
+
let k = i + 3;
|
|
2062
|
+
let depth = 1;
|
|
2063
|
+
while (k < source.length && depth > 0) {
|
|
2064
|
+
const ch = source[k];
|
|
2065
|
+
if (ch === "\\") {
|
|
2066
|
+
k += 2;
|
|
2067
|
+
continue;
|
|
2068
|
+
}
|
|
2069
|
+
if (ch === "[") {
|
|
2070
|
+
let j = k + 1;
|
|
2071
|
+
if (source[j] === "^") j++;
|
|
2072
|
+
while (j < source.length && source[j] !== "]") {
|
|
2073
|
+
if (source[j] === "\\") j += 2;
|
|
2074
|
+
else j++;
|
|
2075
|
+
}
|
|
2076
|
+
if (source[j] !== "]") return null;
|
|
2077
|
+
k = j + 1;
|
|
2078
|
+
continue;
|
|
2079
|
+
}
|
|
2080
|
+
if (ch === "(") depth++;
|
|
2081
|
+
else if (ch === ")") depth--;
|
|
2082
|
+
k++;
|
|
2083
|
+
}
|
|
2084
|
+
if (depth !== 0) return null;
|
|
2085
|
+
const body = source.slice(i + 3, k - 1);
|
|
2086
|
+
if (source[k] !== "*") return null;
|
|
2087
|
+
const closeFrag = source.slice(k + 1);
|
|
2088
|
+
const open = literalCodePoints(openFrag);
|
|
2089
|
+
const close = literalCodePoints(closeFrag);
|
|
2090
|
+
if (!open || !close || !delimitedBodySound(body, close)) return null;
|
|
2091
|
+
return { kind: "delimited", open, close };
|
|
2092
|
+
}
|
|
1928
2093
|
function parseScanShapeCore(source) {
|
|
1929
2094
|
let m = /^\[((?:\\.|[^\]])+)\]([+*])$/.exec(source);
|
|
1930
2095
|
if (m && !m[1].startsWith("^")) {
|
|
@@ -1949,14 +2114,8 @@ function parseScanShapeCore(source) {
|
|
|
1949
2114
|
const stop = parseClassRanges(m[2]);
|
|
1950
2115
|
if (open && stop) return { kind: "until", open, stop };
|
|
1951
2116
|
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
if (m && m[1] && m[2]) {
|
|
1955
|
-
const open = literalCodePoints(m[1]);
|
|
1956
|
-
const close = literalCodePoints(m[2]);
|
|
1957
|
-
if (open && close) return { kind: "delimited", open, close };
|
|
1958
|
-
}
|
|
1959
|
-
}
|
|
2117
|
+
const delim = parseDelimited(source);
|
|
2118
|
+
if (delim) return delim;
|
|
1960
2119
|
const parts = parseSeqParts(source);
|
|
1961
2120
|
if (parts && seqIsUnambiguous(parts)) return { kind: "seq", parts };
|
|
1962
2121
|
return null;
|
|
@@ -2411,6 +2570,7 @@ function looseMkBuildRe(type) {
|
|
|
2411
2570
|
);
|
|
2412
2571
|
}
|
|
2413
2572
|
function analyzeMkInlineBuild(def) {
|
|
2573
|
+
if (!def.build) return null;
|
|
2414
2574
|
const src = (def.buildSrc ?? def.build.toString()).trim();
|
|
2415
2575
|
const strict = src.match(MK_BUILD_RE);
|
|
2416
2576
|
if (strict) {
|
|
@@ -2508,6 +2668,15 @@ function v(ctx, prefix = "_v") {
|
|
|
2508
2668
|
function ind(ctx) {
|
|
2509
2669
|
return " ".repeat(ctx.indent);
|
|
2510
2670
|
}
|
|
2671
|
+
function nsp(ctx) {
|
|
2672
|
+
return ctx.ns ?? "";
|
|
2673
|
+
}
|
|
2674
|
+
function mfRef(ctx) {
|
|
2675
|
+
return `${nsp(ctx)}_mf`;
|
|
2676
|
+
}
|
|
2677
|
+
function buildRef(ctx) {
|
|
2678
|
+
return `${nsp(ctx)}_build`;
|
|
2679
|
+
}
|
|
2511
2680
|
function reindentStmts(stmts, targetLevels) {
|
|
2512
2681
|
const nonEmpty = stmts.filter((s) => s.trim().length > 0);
|
|
2513
2682
|
if (nonEmpty.length === 0) return stmts;
|
|
@@ -2524,7 +2693,7 @@ function failReturnArr(expectedArr, posExpr) {
|
|
|
2524
2693
|
function hoistExpected(ctx, constArrSource) {
|
|
2525
2694
|
let name = ctx.expectedMap.get(constArrSource);
|
|
2526
2695
|
if (name === void 0) {
|
|
2527
|
-
name =
|
|
2696
|
+
name = `${nsp(ctx)}_fx${ctx.expectedDecls.length}`;
|
|
2528
2697
|
ctx.expectedDecls.push(`const ${name} = ${constArrSource}`);
|
|
2529
2698
|
ctx.expectedMap.set(constArrSource, name);
|
|
2530
2699
|
}
|
|
@@ -2623,13 +2792,13 @@ function emitLeafCapture(ctx, valExpr, startExpr, endExpr) {
|
|
|
2623
2792
|
`${i}}`
|
|
2624
2793
|
];
|
|
2625
2794
|
}
|
|
2626
|
-
function ensureRegexDecl(ctx,
|
|
2795
|
+
function ensureRegexDecl(ctx, source, flags) {
|
|
2627
2796
|
const f = "y" + flags.replace(/[gy]/g, "");
|
|
2628
|
-
const key = `${
|
|
2797
|
+
const key = `${source}/${f}`;
|
|
2629
2798
|
let rName = ctx.regexMap.get(key);
|
|
2630
2799
|
if (rName === void 0) {
|
|
2631
|
-
rName =
|
|
2632
|
-
ctx.regexDecls.push(`const ${rName} = /${
|
|
2800
|
+
rName = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
|
|
2801
|
+
ctx.regexDecls.push(`const ${rName} = /${source}/${f}`);
|
|
2633
2802
|
ctx.regexMap.set(key, rName);
|
|
2634
2803
|
}
|
|
2635
2804
|
return rName;
|
|
@@ -2638,7 +2807,7 @@ function ensureTriviaFn(ctx) {
|
|
|
2638
2807
|
const trivia2 = ctx.activeTrivia;
|
|
2639
2808
|
const existing = ctx.triviaFnNames.get(trivia2);
|
|
2640
2809
|
if (existing) return existing;
|
|
2641
|
-
const fnName =
|
|
2810
|
+
const fnName = `${nsp(ctx)}_tf${ctx.triviaFnNames.size}`;
|
|
2642
2811
|
ctx.triviaFnNames.set(trivia2, fnName);
|
|
2643
2812
|
ctx.triviaCaptureNames.set(trivia2, fnName);
|
|
2644
2813
|
const labeledSpec = analyzeLabeledTrivia(trivia2);
|
|
@@ -2660,7 +2829,7 @@ function ensureTriviaFn(ctx) {
|
|
|
2660
2829
|
for (const arm of regexSpec.arms) {
|
|
2661
2830
|
const def = arm.parser._def;
|
|
2662
2831
|
if (def.tag !== "regex") break;
|
|
2663
|
-
reNames.push(ensureRegexDecl(ctx, def.
|
|
2832
|
+
reNames.push(ensureRegexDecl(ctx, def.source, def.flags));
|
|
2664
2833
|
}
|
|
2665
2834
|
if (reNames.length === regexSpec.arms.length) {
|
|
2666
2835
|
ctx.namedFnDecls.push(buildLabeledRegexTriviaFnDecl(fnName, regexSpec, reNames));
|
|
@@ -2985,7 +3154,7 @@ function emitKeywords(def, ctx, pos) {
|
|
|
2985
3154
|
const key = `${source}/${flags}`;
|
|
2986
3155
|
let rName = ctx.regexMap.get(key);
|
|
2987
3156
|
if (rName === void 0) {
|
|
2988
|
-
rName =
|
|
3157
|
+
rName = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
|
|
2989
3158
|
ctx.regexDecls.push(`const ${rName} = /${source}/${flags}`);
|
|
2990
3159
|
ctx.regexMap.set(key, rName);
|
|
2991
3160
|
}
|
|
@@ -3019,11 +3188,11 @@ function emitRegex(def, ctx, pos) {
|
|
|
3019
3188
|
}
|
|
3020
3189
|
}
|
|
3021
3190
|
const flags = "y" + def.flags.replace(/[gy]/g, "");
|
|
3022
|
-
const key = `${def.
|
|
3191
|
+
const key = `${def.source}/${flags}`;
|
|
3023
3192
|
let rName = ctx.regexMap.get(key);
|
|
3024
3193
|
if (rName === void 0) {
|
|
3025
|
-
rName =
|
|
3026
|
-
ctx.regexDecls.push(`const ${rName} = /${def.
|
|
3194
|
+
rName = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
|
|
3195
|
+
ctx.regexDecls.push(`const ${rName} = /${def.source}/${flags}`);
|
|
3027
3196
|
ctx.regexMap.set(key, rName);
|
|
3028
3197
|
}
|
|
3029
3198
|
const mv = v(ctx, "_m");
|
|
@@ -3200,7 +3369,7 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
3200
3369
|
const reKey = `${regexDef.source}/${cleanFlags}`;
|
|
3201
3370
|
let reVar = ctx.regexMap.get(reKey);
|
|
3202
3371
|
if (reVar === void 0) {
|
|
3203
|
-
reVar =
|
|
3372
|
+
reVar = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
|
|
3204
3373
|
ctx.regexDecls.push(`const ${reVar} = /${regexDef.source}/${cleanFlags}`);
|
|
3205
3374
|
ctx.regexMap.set(reKey, reVar);
|
|
3206
3375
|
}
|
|
@@ -3293,7 +3462,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
3293
3462
|
if (gate) {
|
|
3294
3463
|
const gateIdx = ctx.mapFns.length;
|
|
3295
3464
|
ctx.mapFns.push(gate);
|
|
3296
|
-
gateCond =
|
|
3465
|
+
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
3297
3466
|
}
|
|
3298
3467
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
3299
3468
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
@@ -3360,7 +3529,7 @@ function emitTransformChain(p, baseValue, endV, startPos, ctx) {
|
|
|
3360
3529
|
ctx.mapFnSrcs.push(def.fnSrc ?? null);
|
|
3361
3530
|
const vv = v(ctx);
|
|
3362
3531
|
return {
|
|
3363
|
-
stmts: [...innerR.stmts, `${ind(ctx)}const ${vv} =
|
|
3532
|
+
stmts: [...innerR.stmts, `${ind(ctx)}const ${vv} = ${mfRef(ctx)}[${fnIdx}](${innerR.valueVar}, { start: ${startPos}, end: ${endV} })`],
|
|
3364
3533
|
valueVar: vv,
|
|
3365
3534
|
endVar: endV
|
|
3366
3535
|
};
|
|
@@ -3588,16 +3757,17 @@ function emitNot(def, ctx, pos) {
|
|
|
3588
3757
|
};
|
|
3589
3758
|
}
|
|
3590
3759
|
function emitNode(def, ctx, pos) {
|
|
3591
|
-
const
|
|
3760
|
+
const structural = def.build === void 0;
|
|
3761
|
+
const mkType = structural ? null : analyzeMkInlineBuild(def);
|
|
3592
3762
|
let buildIdx = null;
|
|
3593
|
-
if (!mkType) {
|
|
3763
|
+
if (!mkType && !structural) {
|
|
3594
3764
|
buildIdx = ctx.buildFns.length;
|
|
3595
3765
|
ctx.buildFns.push(def.build);
|
|
3596
3766
|
ctx.buildSrcs.push(def.buildSrc ?? null);
|
|
3597
3767
|
}
|
|
3598
3768
|
const i = ind(ctx);
|
|
3599
|
-
const capturesTrivia = mkType !== null || buildReadsTrivia(def);
|
|
3600
|
-
const clonesState = buildReadsState(def);
|
|
3769
|
+
const capturesTrivia = mkType !== null || structural || buildReadsTrivia(def);
|
|
3770
|
+
const clonesState = structural || buildReadsState(def);
|
|
3601
3771
|
const chV = v(ctx, "_ch");
|
|
3602
3772
|
const rawV = v(ctx, "_raw");
|
|
3603
3773
|
const tlV = capturesTrivia ? v(ctx, "_tl") : "_EMPTY_TL";
|
|
@@ -3620,7 +3790,8 @@ function emitNode(def, ctx, pos) {
|
|
|
3620
3790
|
stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
|
|
3621
3791
|
}
|
|
3622
3792
|
const ndV = v(ctx, "_nd");
|
|
3623
|
-
const
|
|
3793
|
+
const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${rawV}, { start: ${pos}, end: ${endVar} }, ${tlV}, ${stV})`;
|
|
3794
|
+
const ndExpr = ctx.ns || structural ? `_ctx.build !== undefined ? _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${rawV}, { start: ${pos}, end: ${endVar} }, ${tlV}, ${stV}) : (${buildExpr})` : buildExpr;
|
|
3624
3795
|
const finalExpr = def.collapse ? `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})` : ndExpr;
|
|
3625
3796
|
stmts.push(
|
|
3626
3797
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
@@ -3645,8 +3816,9 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
3645
3816
|
return { stmts, valueVar: vv, endVar: ev };
|
|
3646
3817
|
}
|
|
3647
3818
|
function emitLazy(p, def, ctx, pos) {
|
|
3819
|
+
const canonical = ctx.ruleNames?.get(p);
|
|
3648
3820
|
const usage = ctx.lazyUsage;
|
|
3649
|
-
if (usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
|
|
3821
|
+
if (!canonical && usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
|
|
3650
3822
|
let resolved;
|
|
3651
3823
|
try {
|
|
3652
3824
|
resolved = def.thunk();
|
|
@@ -3656,7 +3828,7 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
3656
3828
|
return emit(resolved, ctx, pos);
|
|
3657
3829
|
}
|
|
3658
3830
|
if (!ctx.namedParsers.has(p)) {
|
|
3659
|
-
const fnName2 =
|
|
3831
|
+
const fnName2 = canonical ?? `${nsp(ctx)}_pf${ctx.namedParsers.size}`;
|
|
3660
3832
|
ctx.namedParsers.set(p, fnName2);
|
|
3661
3833
|
let resolved;
|
|
3662
3834
|
try {
|
|
@@ -3774,7 +3946,7 @@ function emit(p, ctx, pos) {
|
|
|
3774
3946
|
return {
|
|
3775
3947
|
stmts: [
|
|
3776
3948
|
...inner.stmts,
|
|
3777
|
-
`${ind(ctx)}const ${mv} =
|
|
3949
|
+
`${ind(ctx)}const ${mv} = ${mfRef(ctx)}[${fnIdx}](${inner.valueVar}, { start: ${pos}, end: ${inner.endVar} })`
|
|
3778
3950
|
],
|
|
3779
3951
|
valueVar: mv,
|
|
3780
3952
|
endVar: inner.endVar
|
|
@@ -3837,7 +4009,7 @@ function emit(p, ctx, pos) {
|
|
|
3837
4009
|
const vv = v(ctx);
|
|
3838
4010
|
return {
|
|
3839
4011
|
stmts: [
|
|
3840
|
-
...emitIfFail(ctx,
|
|
4012
|
+
...emitIfFail(ctx, `!${mfRef(ctx)}[${fnIdx}](_ctx.state)`, failBody(ctx, '"gate"', pos)),
|
|
3841
4013
|
`${ind(ctx)}const ${vv} = null`
|
|
3842
4014
|
],
|
|
3843
4015
|
valueVar: vv,
|
|
@@ -3870,7 +4042,7 @@ function emit(p, ctx, pos) {
|
|
|
3870
4042
|
const ev = v(ctx, "_wce");
|
|
3871
4043
|
return {
|
|
3872
4044
|
stmts: [
|
|
3873
|
-
`${ind(ctx)}const ${rv} = { ..._ctx, state:
|
|
4045
|
+
`${ind(ctx)}const ${rv} = { ..._ctx, state: ${mfRef(ctx)}[${evIdx}]() }`,
|
|
3874
4046
|
`${ind(ctx)}const ${vv} = ${fn}(input, ${pos}, ${rv})`,
|
|
3875
4047
|
// withCtx runs on a spread child ctx — copy its recorded failure back
|
|
3876
4048
|
// and propagate the inner failure verbatim (interpreter parity).
|
|
@@ -4001,6 +4173,39 @@ function analyzeLazyUsageMulti(roots) {
|
|
|
4001
4173
|
for (const root of roots) walk2(root);
|
|
4002
4174
|
return { counts, recursive };
|
|
4003
4175
|
}
|
|
4176
|
+
function ruleDependencies(ruleMap) {
|
|
4177
|
+
const nameOf = /* @__PURE__ */ new Map();
|
|
4178
|
+
for (const [name, comb] of ruleMap) nameOf.set(comb, name);
|
|
4179
|
+
const deps = /* @__PURE__ */ new Map();
|
|
4180
|
+
for (const [name, comb] of ruleMap) {
|
|
4181
|
+
const found = /* @__PURE__ */ new Set();
|
|
4182
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4183
|
+
const walk2 = (p, isRoot) => {
|
|
4184
|
+
const def = p._def;
|
|
4185
|
+
const boundary = def.tag === "lazy" ? p._ruleName ?? nameOf.get(p) : nameOf.get(p);
|
|
4186
|
+
if (!isRoot && boundary !== void 0) {
|
|
4187
|
+
found.add(boundary);
|
|
4188
|
+
return;
|
|
4189
|
+
}
|
|
4190
|
+
if (seen.has(p)) return;
|
|
4191
|
+
seen.add(p);
|
|
4192
|
+
if (def.tag === "lazy") {
|
|
4193
|
+
let resolved;
|
|
4194
|
+
try {
|
|
4195
|
+
resolved = def.thunk();
|
|
4196
|
+
} catch {
|
|
4197
|
+
return;
|
|
4198
|
+
}
|
|
4199
|
+
walk2(resolved, false);
|
|
4200
|
+
return;
|
|
4201
|
+
}
|
|
4202
|
+
for (const child of childrenOf(def)) walk2(child, false);
|
|
4203
|
+
};
|
|
4204
|
+
walk2(comb, true);
|
|
4205
|
+
deps.set(name, [...found]);
|
|
4206
|
+
}
|
|
4207
|
+
return deps;
|
|
4208
|
+
}
|
|
4004
4209
|
function compile(combinator, mapFnSources) {
|
|
4005
4210
|
const ctx = {
|
|
4006
4211
|
vars: 0,
|
|
@@ -4106,6 +4311,15 @@ function compileRuleMap(ruleMap) {
|
|
|
4106
4311
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
4107
4312
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule))
|
|
4108
4313
|
};
|
|
4314
|
+
const seenNames = /* @__PURE__ */ new Map();
|
|
4315
|
+
const ruleNames = /* @__PURE__ */ new Map();
|
|
4316
|
+
for (const [key, rule] of ruleMap) {
|
|
4317
|
+
const base = `_r_${key.replace(/[^A-Za-z0-9_$]/g, "_")}`;
|
|
4318
|
+
const n = seenNames.get(base) ?? 0;
|
|
4319
|
+
seenNames.set(base, n + 1);
|
|
4320
|
+
ruleNames.set(rule, n === 0 ? base : `${base}$${n}`);
|
|
4321
|
+
}
|
|
4322
|
+
ctx.ruleNames = ruleNames;
|
|
4109
4323
|
const perEntry = ruleMap.map(([key, rule]) => ({ key, r: emit(rule, ctx, "_pos") }));
|
|
4110
4324
|
const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
|
|
4111
4325
|
` : "";
|
|
@@ -4115,8 +4329,8 @@ function compileRuleMap(ruleMap) {
|
|
|
4115
4329
|
const mfCovered = ctx.mapFns.length === 0 || derivedSrcs !== void 0;
|
|
4116
4330
|
const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
|
|
4117
4331
|
if (!canInline) return null;
|
|
4118
|
-
const mfDecl = derivedSrcs?.length ? ` const
|
|
4119
|
-
const buildDecl = buildSources?.length ? ` const
|
|
4332
|
+
const mfDecl = derivedSrcs?.length ? ` const ${mfRef(ctx)} = [${derivedSrcs.join(", ")}]` : "";
|
|
4333
|
+
const buildDecl = buildSources?.length ? ` const ${buildRef(ctx)} = [${buildSources.join(", ")}]` : "";
|
|
4120
4334
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
|
|
4121
4335
|
const hoistedDecls = [
|
|
4122
4336
|
ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "",
|
|
@@ -4149,6 +4363,150 @@ function compileRuleMap(ruleMap) {
|
|
|
4149
4363
|
].join("\n");
|
|
4150
4364
|
return { keys: perEntry.map((e) => e.key), replacement };
|
|
4151
4365
|
}
|
|
4366
|
+
function compileLinkable(ruleMapArg, ns) {
|
|
4367
|
+
if (!ns) throw new Error("compileLinkable: ns must be a non-empty namespace");
|
|
4368
|
+
const ruleMap = ruleMapArg.filter(([, val]) => {
|
|
4369
|
+
const d = val._def;
|
|
4370
|
+
if (d.tag !== "lazy") return true;
|
|
4371
|
+
try {
|
|
4372
|
+
d.thunk();
|
|
4373
|
+
return true;
|
|
4374
|
+
} catch {
|
|
4375
|
+
return false;
|
|
4376
|
+
}
|
|
4377
|
+
});
|
|
4378
|
+
const ctx = {
|
|
4379
|
+
vars: 0,
|
|
4380
|
+
indent: 1,
|
|
4381
|
+
regexDecls: [],
|
|
4382
|
+
regexMap: /* @__PURE__ */ new Map(),
|
|
4383
|
+
expectedDecls: [],
|
|
4384
|
+
expectedMap: /* @__PURE__ */ new Map(),
|
|
4385
|
+
recordFail: true,
|
|
4386
|
+
mapFns: [],
|
|
4387
|
+
mapFnSrcs: [],
|
|
4388
|
+
buildFns: [],
|
|
4389
|
+
buildSrcs: [],
|
|
4390
|
+
runtimeParsers: [],
|
|
4391
|
+
needsCollator: false,
|
|
4392
|
+
namedParsers: /* @__PURE__ */ new Map(),
|
|
4393
|
+
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
4394
|
+
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
4395
|
+
namedFnDecls: [],
|
|
4396
|
+
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
4397
|
+
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
4398
|
+
ns
|
|
4399
|
+
};
|
|
4400
|
+
const seen = /* @__PURE__ */ new Map();
|
|
4401
|
+
const ruleNames = /* @__PURE__ */ new Map();
|
|
4402
|
+
const fnNameToKey = /* @__PURE__ */ new Map();
|
|
4403
|
+
for (const [key, rule] of ruleMap) {
|
|
4404
|
+
const base = `_r_${key.replace(/[^A-Za-z0-9_$]/g, "_")}`;
|
|
4405
|
+
const n = seen.get(base) ?? 0;
|
|
4406
|
+
seen.set(base, n + 1);
|
|
4407
|
+
const fn = n === 0 ? base : `${base}$${n}`;
|
|
4408
|
+
ruleNames.set(rule, fn);
|
|
4409
|
+
fnNameToKey.set(fn, key);
|
|
4410
|
+
}
|
|
4411
|
+
ctx.ruleNames = ruleNames;
|
|
4412
|
+
{
|
|
4413
|
+
const scanned = /* @__PURE__ */ new Set();
|
|
4414
|
+
const scanExternal = (p) => {
|
|
4415
|
+
if (scanned.has(p)) return;
|
|
4416
|
+
scanned.add(p);
|
|
4417
|
+
const def = p._def;
|
|
4418
|
+
if (def.tag === "lazy") {
|
|
4419
|
+
let resolved;
|
|
4420
|
+
try {
|
|
4421
|
+
resolved = def.thunk();
|
|
4422
|
+
} catch {
|
|
4423
|
+
resolved = void 0;
|
|
4424
|
+
}
|
|
4425
|
+
if (resolved === void 0) {
|
|
4426
|
+
const name = p._ruleName;
|
|
4427
|
+
if (name && !ctx.namedParsers.has(p)) {
|
|
4428
|
+
const fn = `_r_${name.replace(/[^A-Za-z0-9_$]/g, "_")}`;
|
|
4429
|
+
ruleNames.set(p, fn);
|
|
4430
|
+
ctx.namedParsers.set(p, fn);
|
|
4431
|
+
}
|
|
4432
|
+
return;
|
|
4433
|
+
}
|
|
4434
|
+
scanExternal(resolved);
|
|
4435
|
+
return;
|
|
4436
|
+
}
|
|
4437
|
+
for (const child of childrenOf(def)) scanExternal(child);
|
|
4438
|
+
};
|
|
4439
|
+
for (const [, rule] of ruleMap) scanExternal(rule);
|
|
4440
|
+
}
|
|
4441
|
+
const perEntry = [];
|
|
4442
|
+
for (const [key, rule] of ruleMap) {
|
|
4443
|
+
const fn = ruleNames.get(rule);
|
|
4444
|
+
if (!ctx.namedParsers.has(rule)) {
|
|
4445
|
+
ctx.namedParsers.set(rule, fn);
|
|
4446
|
+
let resolved = rule;
|
|
4447
|
+
const def = rule._def;
|
|
4448
|
+
if (def.tag === "lazy") {
|
|
4449
|
+
try {
|
|
4450
|
+
resolved = def.thunk();
|
|
4451
|
+
} catch {
|
|
4452
|
+
return null;
|
|
4453
|
+
}
|
|
4454
|
+
}
|
|
4455
|
+
const savedIndent = ctx.indent, savedFail = ctx.failLabel, savedRec = ctx.recordFail;
|
|
4456
|
+
ctx.indent = 1;
|
|
4457
|
+
ctx.failLabel = "_pfail";
|
|
4458
|
+
ctx.recordFail = true;
|
|
4459
|
+
const body = emit(resolved, ctx, "_pos");
|
|
4460
|
+
ctx.indent = savedIndent;
|
|
4461
|
+
ctx.failLabel = savedFail;
|
|
4462
|
+
ctx.recordFail = savedRec;
|
|
4463
|
+
pushNamedFnDecl(ctx, fn, body.stmts, body.valueVar, body.endVar);
|
|
4464
|
+
}
|
|
4465
|
+
perEntry.push({ key, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
4466
|
+
}
|
|
4467
|
+
if (ctx.runtimeParsers.length !== 0) return null;
|
|
4468
|
+
const mfSrcs = ctx.mapFns.length > 0 && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : null;
|
|
4469
|
+
const buildSrcs = ctx.buildFns.length > 0 && ctx.buildSrcs.every((s) => s !== null) ? ctx.buildSrcs : null;
|
|
4470
|
+
const ruleFns = /* @__PURE__ */ new Map();
|
|
4471
|
+
const privateFns = [];
|
|
4472
|
+
for (const decl of ctx.namedFnDecls) {
|
|
4473
|
+
const fnName = decl.match(/^function (\S+?)\(/)?.[1];
|
|
4474
|
+
const key = fnName ? fnNameToKey.get(fnName) : void 0;
|
|
4475
|
+
if (key !== void 0) ruleFns.set(key, decl);
|
|
4476
|
+
else privateFns.push(decl);
|
|
4477
|
+
}
|
|
4478
|
+
const mfDecl = ctx.mapFns.length === 0 ? "" : mfSrcs ? `const ${mfRef(ctx)} = [${mfSrcs.join(", ")}]` : `const ${mfRef(ctx)} = _env[${JSON.stringify(nsp(ctx) + "mf")}]`;
|
|
4479
|
+
const buildDecl = ctx.buildFns.length === 0 ? "" : buildSrcs ? `const ${buildRef(ctx)} = [${buildSrcs.join(", ")}]` : `const ${buildRef(ctx)} = _env[${JSON.stringify(nsp(ctx) + "build")}]`;
|
|
4480
|
+
const prelude = [
|
|
4481
|
+
...ctx.regexDecls,
|
|
4482
|
+
...ctx.expectedDecls,
|
|
4483
|
+
mfDecl,
|
|
4484
|
+
buildDecl,
|
|
4485
|
+
...privateFns
|
|
4486
|
+
].filter(Boolean);
|
|
4487
|
+
const wrappers = /* @__PURE__ */ new Map();
|
|
4488
|
+
for (const { key, r } of perEntry) {
|
|
4489
|
+
wrappers.set(key, [
|
|
4490
|
+
`function(input, _pos, _ctx) {`,
|
|
4491
|
+
` let pos = _pos`,
|
|
4492
|
+
...r.stmts,
|
|
4493
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
4494
|
+
`}`
|
|
4495
|
+
].join("\n"));
|
|
4496
|
+
}
|
|
4497
|
+
return {
|
|
4498
|
+
ns,
|
|
4499
|
+
keys: perEntry.map((e) => e.key),
|
|
4500
|
+
prelude,
|
|
4501
|
+
ruleFns,
|
|
4502
|
+
wrappers,
|
|
4503
|
+
deps: ruleDependencies(ruleMap),
|
|
4504
|
+
needsEmptyTl: !!ctx.needsEmptyTl,
|
|
4505
|
+
needsCollator: ctx.needsCollator,
|
|
4506
|
+
mfFns: mfSrcs ? [] : ctx.mapFns,
|
|
4507
|
+
buildFns: buildSrcs ? [] : ctx.buildFns
|
|
4508
|
+
};
|
|
4509
|
+
}
|
|
4152
4510
|
function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources) {
|
|
4153
4511
|
const bodyLines = [
|
|
4154
4512
|
` let pos = _pos`,
|
|
@@ -4187,6 +4545,48 @@ function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources)
|
|
|
4187
4545
|
].join("\n");
|
|
4188
4546
|
}
|
|
4189
4547
|
|
|
4548
|
+
// src/compiler/linker.ts
|
|
4549
|
+
function fusedBody(pieces) {
|
|
4550
|
+
const winner = /* @__PURE__ */ new Map();
|
|
4551
|
+
for (const p of pieces) for (const k of p.keys) winner.set(k, p);
|
|
4552
|
+
for (const [k, p] of winner) {
|
|
4553
|
+
for (const d of p.deps.get(k) ?? []) {
|
|
4554
|
+
if (!winner.has(d)) throw new Error(`compose: rule "${k}" references missing rule "${d}"`);
|
|
4555
|
+
}
|
|
4556
|
+
}
|
|
4557
|
+
const contributing = new Set(winner.values());
|
|
4558
|
+
const needsEmptyTl = [...contributing].some((p) => p.needsEmptyTl);
|
|
4559
|
+
const needsCollator = [...contributing].some((p) => p.needsCollator);
|
|
4560
|
+
const lines = [
|
|
4561
|
+
// Shared sentinel protocol (must match NAMED_FN_FAIL / NAMED_FN_END in codegen).
|
|
4562
|
+
"const _pfFail = {}",
|
|
4563
|
+
"let _pfEnd",
|
|
4564
|
+
...needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [],
|
|
4565
|
+
...needsCollator ? ["const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })"] : [],
|
|
4566
|
+
// Each contributing artifact's namespaced private prelude (regexes, _pf, …).
|
|
4567
|
+
...[...contributing].flatMap((p) => p.prelude),
|
|
4568
|
+
// The winning `_r_<Name>` function for each rule (one per name → no redeclare).
|
|
4569
|
+
...[...winner].map(([k, p]) => p.ruleFns.get(k))
|
|
4570
|
+
];
|
|
4571
|
+
const wrapperEntries = [...winner].map(([k, p]) => `${JSON.stringify(k)}: ${p.wrappers.get(k)}`);
|
|
4572
|
+
const body = [...lines, "return {", wrapperEntries.join(",\n"), "}"].join("\n");
|
|
4573
|
+
const env = {};
|
|
4574
|
+
for (const p of contributing) {
|
|
4575
|
+
if (p.mfFns.length) env[`${p.ns}mf`] = p.mfFns;
|
|
4576
|
+
if (p.buildFns.length) env[`${p.ns}build`] = p.buildFns;
|
|
4577
|
+
}
|
|
4578
|
+
return { body, env };
|
|
4579
|
+
}
|
|
4580
|
+
function emitFusedSource(pieces) {
|
|
4581
|
+
const { body, env } = fusedBody(pieces);
|
|
4582
|
+
if (Object.keys(env).length > 0) {
|
|
4583
|
+
throw new Error("emitFusedSource: artifact carries non-static callbacks (runtime-only); cannot emit static source");
|
|
4584
|
+
}
|
|
4585
|
+
return `/* @__PURE__ */ (() => {
|
|
4586
|
+
${body}
|
|
4587
|
+
})()`;
|
|
4588
|
+
}
|
|
4589
|
+
|
|
4190
4590
|
// src/combinators/scanTo.ts
|
|
4191
4591
|
function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
4192
4592
|
const meta = {
|
|
@@ -4281,6 +4681,12 @@ function escapeClassChar(ch) {
|
|
|
4281
4681
|
return ch.replace(/[\\\]^-]/g, "\\$&");
|
|
4282
4682
|
}
|
|
4283
4683
|
|
|
4684
|
+
// src/cst/offset-model.ts
|
|
4685
|
+
var { isFinite } = Number;
|
|
4686
|
+
|
|
4687
|
+
// src/index.ts
|
|
4688
|
+
registerRegexAnalyzer(firstSetFromRegex);
|
|
4689
|
+
|
|
4284
4690
|
// src/plugin/evaluator.ts
|
|
4285
4691
|
function isWordFactory(v2) {
|
|
4286
4692
|
return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
|
|
@@ -4380,16 +4786,18 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
4380
4786
|
}
|
|
4381
4787
|
if (callee.name === "node" && code !== void 0) {
|
|
4382
4788
|
const [typeArg, parserArg, buildArg, optsArg] = node2.arguments;
|
|
4383
|
-
if (!typeArg || !parserArg ||
|
|
4789
|
+
if (!typeArg || !parserArg || typeArg.type === "SpreadElement" || parserArg.type === "SpreadElement") return null;
|
|
4384
4790
|
const typeVal = anyValue(typeArg, scope, code);
|
|
4385
4791
|
if (typeof typeVal !== "string") return null;
|
|
4386
4792
|
const inner = anyValue(parserArg, scope, code, mfs);
|
|
4387
4793
|
if (!isCombinator(inner)) return null;
|
|
4388
|
-
const
|
|
4794
|
+
const be = buildArg;
|
|
4795
|
+
const hasBuild = be !== void 0 && be.type !== "SpreadElement" && !(be.type === "Identifier" && be.name === "undefined");
|
|
4796
|
+
const buildSrc = hasBuild ? code.slice(be.start, be.end) : void 0;
|
|
4389
4797
|
const collapse = optsArg !== void 0 && optsArg.type !== "SpreadElement" ? staticCollapseOption(optsArg) : false;
|
|
4390
4798
|
try {
|
|
4391
|
-
const combi = node(typeVal, inner, () => null, collapse ? { collapse: true } : void 0);
|
|
4392
|
-
if (combi._def.tag === "node") combi._def.buildSrc = buildSrc;
|
|
4799
|
+
const combi = node(typeVal, inner, hasBuild ? () => null : void 0, collapse ? { collapse: true } : void 0);
|
|
4800
|
+
if (combi._def.tag === "node" && buildSrc !== void 0) combi._def.buildSrc = buildSrc;
|
|
4393
4801
|
return combi;
|
|
4394
4802
|
} catch {
|
|
4395
4803
|
return null;
|
|
@@ -4575,91 +4983,24 @@ function evaluateCombinatorArray(node2, scope, code) {
|
|
|
4575
4983
|
if (!val.every(isCombinator)) return null;
|
|
4576
4984
|
return val;
|
|
4577
4985
|
}
|
|
4578
|
-
function asFragmentFactory(expr) {
|
|
4579
|
-
if (expr.type !== "ArrowFunctionExpression" && expr.type !== "FunctionExpression" && expr.type !== "FunctionDeclaration") return null;
|
|
4580
|
-
const fn = expr;
|
|
4581
|
-
return factoryBodyAndReturn(fn) ? fn : null;
|
|
4582
|
-
}
|
|
4583
|
-
var unwrapParen = (e) => e && e.type === "ParenthesizedExpression" ? e.expression : e;
|
|
4584
|
-
function factoryBodyAndReturn(fn) {
|
|
4585
|
-
const body = fn.body;
|
|
4586
|
-
if (!body) return null;
|
|
4587
|
-
const b = unwrapParen(body);
|
|
4588
|
-
if (b.type === "ObjectExpression") return { statements: [], retObj: b };
|
|
4589
|
-
if (b.type === "BlockStatement") {
|
|
4590
|
-
const statements = [];
|
|
4591
|
-
for (const stmt of b.body) {
|
|
4592
|
-
if (stmt.type === "ReturnStatement") {
|
|
4593
|
-
const a = unwrapParen(stmt.argument);
|
|
4594
|
-
if (!a || a.type !== "ObjectExpression") return null;
|
|
4595
|
-
return { statements, retObj: a };
|
|
4596
|
-
}
|
|
4597
|
-
if (stmt.type === "VariableDeclaration") statements.push(stmt);
|
|
4598
|
-
else return null;
|
|
4599
|
-
}
|
|
4600
|
-
}
|
|
4601
|
-
return null;
|
|
4602
|
-
}
|
|
4603
|
-
function spreadFactoryCall(spread, resolve) {
|
|
4604
|
-
const call = spread.argument;
|
|
4605
|
-
if (!call || call.type !== "CallExpression") return null;
|
|
4606
|
-
if (!call.callee || call.callee.type !== "Identifier" || !call.callee.name) return null;
|
|
4607
|
-
const resolved = resolve(call.callee.name);
|
|
4608
|
-
return resolved ? { fn: resolved.fn, args: call.arguments ?? [], code: resolved.code } : null;
|
|
4609
|
-
}
|
|
4610
|
-
function factoryCallScope(fn, args, outer) {
|
|
4611
|
-
const s = new Map(outer);
|
|
4612
|
-
const params = fn.params ?? [];
|
|
4613
|
-
for (let i = 0; i < params.length; i++) {
|
|
4614
|
-
const pn = params[i];
|
|
4615
|
-
if (!pn || pn.type !== "Identifier" || !pn.name) continue;
|
|
4616
|
-
const arg = args[i];
|
|
4617
|
-
if (arg && arg.type === "Identifier" && arg.name && outer.has(arg.name)) {
|
|
4618
|
-
s.set(pn.name, outer.get(arg.name));
|
|
4619
|
-
}
|
|
4620
|
-
}
|
|
4621
|
-
return s;
|
|
4622
|
-
}
|
|
4623
4986
|
function propKey(prop) {
|
|
4624
4987
|
if (prop.type !== "Property" || prop.computed || !prop.key) return null;
|
|
4625
4988
|
if (prop.key.type === "Identifier") return prop.key.name ?? null;
|
|
4626
4989
|
if (prop.key.type === "Literal") return String(prop.key.value);
|
|
4627
4990
|
return null;
|
|
4628
4991
|
}
|
|
4629
|
-
function collectRuleKeys(retObj
|
|
4992
|
+
function collectRuleKeys(retObj) {
|
|
4630
4993
|
const out = [];
|
|
4631
4994
|
for (const prop of retObj.properties) {
|
|
4632
|
-
if (prop.type === "SpreadElement") {
|
|
4633
|
-
const sf = spreadFactoryCall(prop, resolve);
|
|
4634
|
-
if (!sf || seen.has(sf.fn)) return null;
|
|
4635
|
-
const br = factoryBodyAndReturn(sf.fn);
|
|
4636
|
-
if (!br) return null;
|
|
4637
|
-
const nested = collectRuleKeys(br.retObj, resolve, new Set(seen).add(sf.fn));
|
|
4638
|
-
if (!nested) return null;
|
|
4639
|
-
out.push(...nested);
|
|
4640
|
-
continue;
|
|
4641
|
-
}
|
|
4642
4995
|
const key = propKey(prop);
|
|
4643
4996
|
if (!key) return null;
|
|
4644
4997
|
out.push(key);
|
|
4645
4998
|
}
|
|
4646
4999
|
return out;
|
|
4647
5000
|
}
|
|
4648
|
-
function flattenRuleEntries(retObj, scope, code
|
|
5001
|
+
function flattenRuleEntries(retObj, scope, code) {
|
|
4649
5002
|
const out = [];
|
|
4650
5003
|
for (const prop of retObj.properties) {
|
|
4651
|
-
if (prop.type === "SpreadElement") {
|
|
4652
|
-
const sf = spreadFactoryCall(prop, resolve);
|
|
4653
|
-
if (!sf || seen.has(sf.fn)) return null;
|
|
4654
|
-
const br = factoryBodyAndReturn(sf.fn);
|
|
4655
|
-
if (!br) return null;
|
|
4656
|
-
const fragScope = factoryCallScope(sf.fn, sf.args, scope);
|
|
4657
|
-
if (!evalBodyStatements(br.statements, fragScope, sf.code)) return null;
|
|
4658
|
-
const nested = flattenRuleEntries(br.retObj, fragScope, sf.code, resolve, new Set(seen).add(sf.fn));
|
|
4659
|
-
if (!nested) return null;
|
|
4660
|
-
out.push(...nested);
|
|
4661
|
-
continue;
|
|
4662
|
-
}
|
|
4663
5004
|
const key = propKey(prop);
|
|
4664
5005
|
if (!key) return null;
|
|
4665
5006
|
out.push({ key, value: prop.value, scope, code });
|
|
@@ -4685,7 +5026,7 @@ function evalBodyStatements(statements, scope, code) {
|
|
|
4685
5026
|
}
|
|
4686
5027
|
return true;
|
|
4687
5028
|
}
|
|
4688
|
-
function evaluateParserFactory(factoryNode, scope, code, mapFnSources
|
|
5029
|
+
function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
4689
5030
|
if (factoryNode.type !== "ArrowFunctionExpression" && factoryNode.type !== "FunctionDeclaration" && factoryNode.type !== "FunctionExpression") return null;
|
|
4690
5031
|
const factory = factoryNode;
|
|
4691
5032
|
const params = factory.params;
|
|
@@ -4717,16 +5058,36 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources, resolveFa
|
|
|
4717
5058
|
if (!returnExpr) return null;
|
|
4718
5059
|
const retObj = returnExpr.type === "ParenthesizedExpression" ? returnExpr.expression : returnExpr;
|
|
4719
5060
|
if (retObj.type !== "ObjectExpression") return null;
|
|
4720
|
-
const keys = collectRuleKeys(retObj
|
|
5061
|
+
const keys = collectRuleKeys(retObj);
|
|
4721
5062
|
if (!keys) return null;
|
|
4722
5063
|
const ruleRefs = /* @__PURE__ */ new Map();
|
|
5064
|
+
const tagRef = (r, name) => {
|
|
5065
|
+
r._ruleName = name;
|
|
5066
|
+
};
|
|
4723
5067
|
for (const key of keys) {
|
|
4724
|
-
if (!ruleRefs.has(key))
|
|
4725
|
-
|
|
5068
|
+
if (!ruleRefs.has(key)) {
|
|
5069
|
+
const r = ref();
|
|
5070
|
+
tagRef(r, key);
|
|
5071
|
+
ruleRefs.set(key, r);
|
|
5072
|
+
}
|
|
5073
|
+
}
|
|
5074
|
+
const externalRefs = /* @__PURE__ */ new Map();
|
|
5075
|
+
const gProxy = new Proxy(Object.fromEntries(ruleRefs), {
|
|
5076
|
+
get(target, prop) {
|
|
5077
|
+
if (typeof prop !== "string" || prop in target) return target[prop];
|
|
5078
|
+
let ext = externalRefs.get(prop);
|
|
5079
|
+
if (!ext) {
|
|
5080
|
+
ext = ref();
|
|
5081
|
+
tagRef(ext, prop);
|
|
5082
|
+
externalRefs.set(prop, ext);
|
|
5083
|
+
}
|
|
5084
|
+
return ext;
|
|
5085
|
+
}
|
|
5086
|
+
});
|
|
4726
5087
|
const localScope = new Map(scope);
|
|
4727
|
-
localScope.set(proxyName,
|
|
5088
|
+
localScope.set(proxyName, gProxy);
|
|
4728
5089
|
if (!evalBodyStatements(statements, localScope, code)) return null;
|
|
4729
|
-
const entries = flattenRuleEntries(retObj, localScope, code
|
|
5090
|
+
const entries = flattenRuleEntries(retObj, localScope, code);
|
|
4730
5091
|
if (!entries) return null;
|
|
4731
5092
|
const finalByKey = /* @__PURE__ */ new Map();
|
|
4732
5093
|
for (const e of entries) finalByKey.set(e.key, e);
|
|
@@ -4788,19 +5149,14 @@ function referencesAny(node2, names, scope) {
|
|
|
4788
5149
|
}
|
|
4789
5150
|
|
|
4790
5151
|
// src/plugin/index.ts
|
|
5152
|
+
var import_node_crypto = require("node:crypto");
|
|
4791
5153
|
var PARSEMAN_MODULE = "parseman";
|
|
4792
|
-
var
|
|
4793
|
-
function
|
|
4794
|
-
return
|
|
4795
|
-
extensions: [".
|
|
4796
|
-
|
|
4797
|
-
|
|
4798
|
-
".js": [".ts", ".tsx", ".js", ".jsx"],
|
|
4799
|
-
".mjs": [".mts", ".mjs"],
|
|
4800
|
-
".cjs": [".cts", ".cjs"]
|
|
4801
|
-
},
|
|
4802
|
-
conditionNames: ["source", "development", "import", "require", "default"],
|
|
4803
|
-
mainFields: ["source", "module", "main"]
|
|
5154
|
+
var _compiledResolver = null;
|
|
5155
|
+
function getCompiledResolver() {
|
|
5156
|
+
return _compiledResolver ??= new import_oxc_resolver.ResolverFactory({
|
|
5157
|
+
extensions: [".js", ".mjs", ".cjs"],
|
|
5158
|
+
conditionNames: ["import", "require", "default"],
|
|
5159
|
+
mainFields: ["module", "main"]
|
|
4804
5160
|
});
|
|
4805
5161
|
}
|
|
4806
5162
|
var _moduleParseCache = /* @__PURE__ */ new Map();
|
|
@@ -4847,6 +5203,77 @@ var plugin_default = (0, import_unplugin.createUnplugin)((opts = {}) => ({
|
|
|
4847
5203
|
return { code: result.code, map: result.map };
|
|
4848
5204
|
}
|
|
4849
5205
|
}));
|
|
5206
|
+
function exportLocalName(body, exported) {
|
|
5207
|
+
for (const st of body) {
|
|
5208
|
+
if (st.type !== "ExportNamedDeclaration") continue;
|
|
5209
|
+
const decl = st.declaration;
|
|
5210
|
+
if (decl?.type === "VariableDeclaration") {
|
|
5211
|
+
for (const d of decl.declarations ?? []) {
|
|
5212
|
+
const idn = d.id;
|
|
5213
|
+
if (idn?.type === "Identifier" && idn.name === exported) return exported;
|
|
5214
|
+
}
|
|
5215
|
+
}
|
|
5216
|
+
for (const sp of st.specifiers ?? []) {
|
|
5217
|
+
const exp = sp.exported?.name;
|
|
5218
|
+
const loc = sp.local?.name;
|
|
5219
|
+
if (exp === exported && loc) return loc;
|
|
5220
|
+
}
|
|
5221
|
+
}
|
|
5222
|
+
return null;
|
|
5223
|
+
}
|
|
5224
|
+
function topLevelInit(body, name) {
|
|
5225
|
+
for (const st of body) {
|
|
5226
|
+
const vd = st.type === "VariableDeclaration" ? st : st.type === "ExportNamedDeclaration" && st.declaration?.type === "VariableDeclaration" ? st.declaration : null;
|
|
5227
|
+
if (!vd) continue;
|
|
5228
|
+
for (const d of vd.declarations ?? []) {
|
|
5229
|
+
const idn = d.id;
|
|
5230
|
+
if (idn?.type === "Identifier" && idn.name === name && d.init) return d.init;
|
|
5231
|
+
}
|
|
5232
|
+
}
|
|
5233
|
+
return null;
|
|
5234
|
+
}
|
|
5235
|
+
function isComposedPiecesSymbol(n) {
|
|
5236
|
+
if (!n || n.type !== "CallExpression") return false;
|
|
5237
|
+
const callee = n.callee;
|
|
5238
|
+
const obj = callee?.object?.name;
|
|
5239
|
+
const prop = callee?.property?.name;
|
|
5240
|
+
const arg0 = n.arguments?.[0];
|
|
5241
|
+
return obj === "Symbol" && prop === "for" && arg0?.value === "parseman.composedPieces";
|
|
5242
|
+
}
|
|
5243
|
+
function findCarriedPiecesLiteral(root) {
|
|
5244
|
+
let found = null;
|
|
5245
|
+
const visit = (n) => {
|
|
5246
|
+
if (found || !n || typeof n !== "object") return;
|
|
5247
|
+
if (Array.isArray(n)) {
|
|
5248
|
+
for (const c of n) visit(c);
|
|
5249
|
+
return;
|
|
5250
|
+
}
|
|
5251
|
+
const node2 = n;
|
|
5252
|
+
if (node2.type === "CallExpression") {
|
|
5253
|
+
const callee = node2.callee;
|
|
5254
|
+
const obj = callee?.object?.name;
|
|
5255
|
+
const prop = callee?.property?.name;
|
|
5256
|
+
const args = node2.arguments;
|
|
5257
|
+
if (obj === "Object" && prop === "defineProperty" && args && isComposedPiecesSymbol(args[1])) {
|
|
5258
|
+
const descriptor = args[2];
|
|
5259
|
+
for (const p of descriptor?.properties ?? []) {
|
|
5260
|
+
const key = p.key;
|
|
5261
|
+
if ((key?.name === "value" || key?.value === "value") && p.value) {
|
|
5262
|
+
found = { start: p.value.start, end: p.value.end };
|
|
5263
|
+
return;
|
|
5264
|
+
}
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
5267
|
+
}
|
|
5268
|
+
for (const k in node2) {
|
|
5269
|
+
if (k === "type" || k === "start" || k === "end") continue;
|
|
5270
|
+
const v2 = node2[k];
|
|
5271
|
+
if (v2 && typeof v2 === "object") visit(v2);
|
|
5272
|
+
}
|
|
5273
|
+
};
|
|
5274
|
+
visit(root);
|
|
5275
|
+
return found;
|
|
5276
|
+
}
|
|
4850
5277
|
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE])) {
|
|
4851
5278
|
let result;
|
|
4852
5279
|
try {
|
|
@@ -4884,63 +5311,6 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
4884
5311
|
}
|
|
4885
5312
|
if (macroImports.length === 0) return null;
|
|
4886
5313
|
const scope = /* @__PURE__ */ new Map();
|
|
4887
|
-
const factories = /* @__PURE__ */ new Map();
|
|
4888
|
-
const resolver = getFragmentResolver();
|
|
4889
|
-
const importedFactoryCache = /* @__PURE__ */ new Map();
|
|
4890
|
-
const OUTPUT_DIR = /([\\/])(dist|lib|build|out|output|compiled|cjs|esm|es)([\\/])/;
|
|
4891
|
-
const resolveSourcePath = (spec) => {
|
|
4892
|
-
let resolved = null;
|
|
4893
|
-
try {
|
|
4894
|
-
resolved = resolver.resolveFileSync(id, spec).path ?? null;
|
|
4895
|
-
} catch {
|
|
4896
|
-
}
|
|
4897
|
-
if (!resolved) return null;
|
|
4898
|
-
if (OUTPUT_DIR.test(resolved)) {
|
|
4899
|
-
const srcCandidate = resolved.replace(OUTPUT_DIR, "$1src$3").replace(/\.(c|m)?js$/, ".ts");
|
|
4900
|
-
try {
|
|
4901
|
-
if (fs.statSync(srcCandidate).isFile()) return srcCandidate;
|
|
4902
|
-
} catch {
|
|
4903
|
-
}
|
|
4904
|
-
}
|
|
4905
|
-
return resolved;
|
|
4906
|
-
};
|
|
4907
|
-
const resolveImportedFactory = (name) => {
|
|
4908
|
-
if (importedFactoryCache.has(name)) return importedFactoryCache.get(name);
|
|
4909
|
-
let result2 = null;
|
|
4910
|
-
const binding = importBindings.get(name);
|
|
4911
|
-
if (binding) {
|
|
4912
|
-
const filePath = resolveSourcePath(binding.source);
|
|
4913
|
-
const mod = filePath ? parseModuleCached(filePath) : null;
|
|
4914
|
-
if (mod) {
|
|
4915
|
-
for (const st of mod.body) {
|
|
4916
|
-
if (st.type !== "ExportNamedDeclaration" || !st.declaration) continue;
|
|
4917
|
-
const decl = st.declaration;
|
|
4918
|
-
if (decl.type === "VariableDeclaration") {
|
|
4919
|
-
for (const d of decl.declarations ?? []) {
|
|
4920
|
-
if (d.id?.type === "Identifier" && d.id.name === binding.imported && d.init) {
|
|
4921
|
-
const fac = asFragmentFactory(d.init);
|
|
4922
|
-
if (fac) {
|
|
4923
|
-
result2 = { fn: fac, code: mod.src };
|
|
4924
|
-
break;
|
|
4925
|
-
}
|
|
4926
|
-
}
|
|
4927
|
-
}
|
|
4928
|
-
} else if (decl.type === "FunctionDeclaration" && decl.id?.type === "Identifier" && decl.id.name === binding.imported) {
|
|
4929
|
-
const fac = asFragmentFactory(decl);
|
|
4930
|
-
if (fac) result2 = { fn: fac, code: mod.src };
|
|
4931
|
-
}
|
|
4932
|
-
if (result2) break;
|
|
4933
|
-
}
|
|
4934
|
-
}
|
|
4935
|
-
}
|
|
4936
|
-
importedFactoryCache.set(name, result2);
|
|
4937
|
-
return result2;
|
|
4938
|
-
};
|
|
4939
|
-
const resolveFactory = (n) => {
|
|
4940
|
-
const local = factories.get(n);
|
|
4941
|
-
if (local) return { fn: local, code };
|
|
4942
|
-
return resolveImportedFactory(n);
|
|
4943
|
-
};
|
|
4944
5314
|
const replacements = [];
|
|
4945
5315
|
const warnings = [];
|
|
4946
5316
|
let anyUnresolved = false;
|
|
@@ -4961,7 +5331,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
4961
5331
|
warn(init.start, `${label2}: rules() needs a factory argument`);
|
|
4962
5332
|
return null;
|
|
4963
5333
|
}
|
|
4964
|
-
const ruleMap = evaluateParserFactory(factoryArg, scope, code, []
|
|
5334
|
+
const ruleMap = evaluateParserFactory(factoryArg, scope, code, []);
|
|
4965
5335
|
if (!ruleMap) {
|
|
4966
5336
|
warn(init.start, `${label2}: rules(...) factory isn't statically evaluable`);
|
|
4967
5337
|
return null;
|
|
@@ -4974,6 +5344,89 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
4974
5344
|
return { replacement: compiled.replacement, ruleMap };
|
|
4975
5345
|
};
|
|
4976
5346
|
const isRulesCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "rules";
|
|
5347
|
+
const isComposeCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "compose";
|
|
5348
|
+
const localRuleMaps = /* @__PURE__ */ new Map();
|
|
5349
|
+
const nsFor = (label2) => `_${(0, import_node_crypto.createHash)("sha1").update(`${id}#${label2}`).digest("hex").slice(0, 8)}_`;
|
|
5350
|
+
const serializePieces = (p) => {
|
|
5351
|
+
const mapLit = (m) => `new Map([${[...m].map(([k, v2]) => `[${JSON.stringify(k)}, ${JSON.stringify(v2)}]`).join(", ")}])`;
|
|
5352
|
+
return `{ ns: ${JSON.stringify(p.ns)}, keys: ${JSON.stringify(p.keys)}, prelude: ${JSON.stringify(p.prelude)}, ruleFns: ${mapLit(p.ruleFns)}, wrappers: ${mapLit(p.wrappers)}, deps: ${mapLit(p.deps)}, needsEmptyTl: ${p.needsEmptyTl}, needsCollator: ${p.needsCollator}, mfFns: [], buildFns: [] }`;
|
|
5353
|
+
};
|
|
5354
|
+
const serializeList = (list) => `[${list.map(serializePieces).join(", ")}]`;
|
|
5355
|
+
const withCarriedPieces = (grammarExpr, list) => `/* @__PURE__ */ (() => { const _g = ${grammarExpr}; Object.defineProperty(_g, Symbol.for('parseman.composedPieces'), { value: ${serializeList(list)} }); return _g })()`;
|
|
5356
|
+
const localComposedPieces = /* @__PURE__ */ new Map();
|
|
5357
|
+
const importedPiecesCache = /* @__PURE__ */ new Map();
|
|
5358
|
+
const importedPieces = (localName) => {
|
|
5359
|
+
if (importedPiecesCache.has(localName)) return importedPiecesCache.get(localName);
|
|
5360
|
+
let result2 = null;
|
|
5361
|
+
const binding = importBindings.get(localName);
|
|
5362
|
+
if (binding) {
|
|
5363
|
+
let file = null;
|
|
5364
|
+
try {
|
|
5365
|
+
file = getCompiledResolver().resolveFileSync(id, binding.source).path ?? null;
|
|
5366
|
+
} catch {
|
|
5367
|
+
}
|
|
5368
|
+
const mod = file ? parseModuleCached(file) : null;
|
|
5369
|
+
if (mod) {
|
|
5370
|
+
const localFor = exportLocalName(mod.body, binding.imported);
|
|
5371
|
+
const initNode = localFor ? topLevelInit(mod.body, localFor) : null;
|
|
5372
|
+
const literalRange = initNode ? findCarriedPiecesLiteral(initNode) : null;
|
|
5373
|
+
if (literalRange) {
|
|
5374
|
+
const literal2 = mod.src.slice(literalRange.start, literalRange.end);
|
|
5375
|
+
try {
|
|
5376
|
+
result2 = new Function(`return (${literal2})`)();
|
|
5377
|
+
} catch {
|
|
5378
|
+
result2 = null;
|
|
5379
|
+
}
|
|
5380
|
+
}
|
|
5381
|
+
}
|
|
5382
|
+
}
|
|
5383
|
+
importedPiecesCache.set(localName, result2);
|
|
5384
|
+
return result2;
|
|
5385
|
+
};
|
|
5386
|
+
const argPieces = (arg, label2) => {
|
|
5387
|
+
if (isRulesCall(arg)) {
|
|
5388
|
+
const factory = arg.arguments[0];
|
|
5389
|
+
const rm = factory ? evaluateParserFactory(factory, scope, code, []) : null;
|
|
5390
|
+
const p = rm ? compileLinkable([...rm], nsFor(label2)) : null;
|
|
5391
|
+
return p ? [p] : null;
|
|
5392
|
+
}
|
|
5393
|
+
if (arg.type === "Identifier") {
|
|
5394
|
+
const name = arg.name;
|
|
5395
|
+
const rm = localRuleMaps.get(name);
|
|
5396
|
+
if (rm) {
|
|
5397
|
+
const p = compileLinkable([...rm], nsFor(label2));
|
|
5398
|
+
return p ? [p] : null;
|
|
5399
|
+
}
|
|
5400
|
+
const composed = localComposedPieces.get(name);
|
|
5401
|
+
if (composed) return composed;
|
|
5402
|
+
return importedPieces(name);
|
|
5403
|
+
}
|
|
5404
|
+
return null;
|
|
5405
|
+
};
|
|
5406
|
+
const compileComposeCall = (init) => {
|
|
5407
|
+
const args = init.arguments;
|
|
5408
|
+
const arr = args[0];
|
|
5409
|
+
if (!arr || arr.type !== "ArrayExpression") {
|
|
5410
|
+
warn(init.start, "compose(): expected a static array of grammars/artifacts");
|
|
5411
|
+
return null;
|
|
5412
|
+
}
|
|
5413
|
+
const elements = arr.elements;
|
|
5414
|
+
const pieces = [];
|
|
5415
|
+
for (let i = 0; i < elements.length; i++) {
|
|
5416
|
+
const list = argPieces(elements[i], `compose${init.start}_${i}`);
|
|
5417
|
+
if (!list) {
|
|
5418
|
+
warn(init.start, `compose(): argument ${i} isn't a build-resolvable grammar; falling back to runtime`);
|
|
5419
|
+
return null;
|
|
5420
|
+
}
|
|
5421
|
+
pieces.push(...list);
|
|
5422
|
+
}
|
|
5423
|
+
try {
|
|
5424
|
+
return { replacement: emitFusedSource(pieces), pieces };
|
|
5425
|
+
} catch (e) {
|
|
5426
|
+
warn(init.start, `compose(): ${e.message}; falling back to runtime`);
|
|
5427
|
+
return null;
|
|
5428
|
+
}
|
|
5429
|
+
};
|
|
4977
5430
|
const unwrapVd = (stmt) => stmt.type === "VariableDeclaration" ? stmt : stmt.type === "ExportNamedDeclaration" && stmt.declaration?.type === "VariableDeclaration" ? stmt.declaration : null;
|
|
4978
5431
|
const refNames = /* @__PURE__ */ new Set();
|
|
4979
5432
|
for (const stmt of body) {
|
|
@@ -5052,16 +5505,23 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
5052
5505
|
if (isRulesCall(init)) {
|
|
5053
5506
|
const compiledRules = compileRulesFactory(init, varName);
|
|
5054
5507
|
if (!compiledRules) continue;
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5508
|
+
localRuleMaps.set(varName, compiledRules.ruleMap);
|
|
5509
|
+
let replacement = compiledRules.replacement;
|
|
5510
|
+
if (exportPrefix) {
|
|
5511
|
+
const pieces = compileLinkable([...compiledRules.ruleMap], nsFor(varName));
|
|
5512
|
+
if (pieces && !pieces.mfFns.length && !pieces.buildFns.length) {
|
|
5513
|
+
replacement = withCarriedPieces(replacement, [pieces]);
|
|
5514
|
+
}
|
|
5515
|
+
}
|
|
5516
|
+
replacements.push({ start: init.start, end: init.end, replacement });
|
|
5060
5517
|
continue;
|
|
5061
5518
|
}
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5519
|
+
if (isComposeCall(init)) {
|
|
5520
|
+
const fused = compileComposeCall(init);
|
|
5521
|
+
if (!fused) continue;
|
|
5522
|
+
localComposedPieces.set(varName, fused.pieces);
|
|
5523
|
+
const replacement = exportPrefix ? withCarriedPieces(fused.replacement, fused.pieces) : fused.replacement;
|
|
5524
|
+
replacements.push({ start: init.start, end: init.end, replacement });
|
|
5065
5525
|
continue;
|
|
5066
5526
|
}
|
|
5067
5527
|
const mapFnSources = [];
|