parseman 0.13.0 → 0.14.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/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 +907 -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 +907 -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.js
CHANGED
|
@@ -288,6 +288,36 @@ function literal(value, opts = {}) {
|
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
// src/combinators/regex.ts
|
|
291
|
+
var firstSetAnalyzer = null;
|
|
292
|
+
function registerRegexAnalyzer(analyzer) {
|
|
293
|
+
firstSetAnalyzer = analyzer;
|
|
294
|
+
}
|
|
295
|
+
var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
|
|
296
|
+
function regex(pattern, flags = "") {
|
|
297
|
+
const source = typeof pattern === "string" ? pattern : pattern.source;
|
|
298
|
+
const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
|
|
299
|
+
const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
|
|
300
|
+
const { firstSet, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
|
|
301
|
+
const meta = { firstSet, canMatchNewline, isTrivia: false };
|
|
302
|
+
return {
|
|
303
|
+
_tag: "regex",
|
|
304
|
+
_meta: meta,
|
|
305
|
+
_def: { tag: "regex", source, flags: resolvedFlags },
|
|
306
|
+
parse(input, pos, ctx) {
|
|
307
|
+
anchored.lastIndex = pos;
|
|
308
|
+
const m = anchored.exec(input);
|
|
309
|
+
if (m === null) {
|
|
310
|
+
return failAt(ctx, [`/${source}/`], pos);
|
|
311
|
+
}
|
|
312
|
+
const span = { start: pos, end: pos + m[0].length };
|
|
313
|
+
const leaf = { _tag: "leaf", value: m[0], span };
|
|
314
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
|
|
315
|
+
return { ok: true, value: m[0], span };
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// src/combinators/regex-analyze.ts
|
|
291
321
|
import regexpTree from "regexp-tree";
|
|
292
322
|
function firstSetFromRegex(pattern) {
|
|
293
323
|
try {
|
|
@@ -392,40 +422,6 @@ function extractFirstSet(node2) {
|
|
|
392
422
|
return { firstSet: any(), canMatchNewline: true };
|
|
393
423
|
}
|
|
394
424
|
}
|
|
395
|
-
function optimizeRegex(source, flags) {
|
|
396
|
-
try {
|
|
397
|
-
const result = regexpTree.optimize(`/${source}/${flags}`);
|
|
398
|
-
const str = result.toString();
|
|
399
|
-
const lastSlash = str.lastIndexOf("/");
|
|
400
|
-
return str.slice(1, lastSlash);
|
|
401
|
-
} catch {
|
|
402
|
-
return source;
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
function regex(pattern, flags = "") {
|
|
406
|
-
const source = typeof pattern === "string" ? pattern : pattern.source;
|
|
407
|
-
const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
|
|
408
|
-
const optimizedSource = optimizeRegex(source, resolvedFlags);
|
|
409
|
-
const anchored = new RegExp(optimizedSource, "y" + resolvedFlags.replace(/[gy]/g, ""));
|
|
410
|
-
const { firstSet, canMatchNewline } = firstSetFromRegex(source);
|
|
411
|
-
const meta = { firstSet, canMatchNewline, isTrivia: false };
|
|
412
|
-
return {
|
|
413
|
-
_tag: "regex",
|
|
414
|
-
_meta: meta,
|
|
415
|
-
_def: { tag: "regex", source, flags: resolvedFlags, optimizedSource },
|
|
416
|
-
parse(input, pos, ctx) {
|
|
417
|
-
anchored.lastIndex = pos;
|
|
418
|
-
const m = anchored.exec(input);
|
|
419
|
-
if (m === null) {
|
|
420
|
-
return failAt(ctx, [`/${source}/`], pos);
|
|
421
|
-
}
|
|
422
|
-
const span = { start: pos, end: pos + m[0].length };
|
|
423
|
-
const leaf = { _tag: "leaf", value: m[0], span };
|
|
424
|
-
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
|
|
425
|
-
return { ok: true, value: m[0], span };
|
|
426
|
-
}
|
|
427
|
-
};
|
|
428
|
-
}
|
|
429
425
|
|
|
430
426
|
// src/combinators/keywords.ts
|
|
431
427
|
function word(str, boundary = "_0-9A-Za-z") {
|
|
@@ -1125,12 +1121,14 @@ function confirmedBuildArity(src) {
|
|
|
1125
1121
|
return parts.length;
|
|
1126
1122
|
}
|
|
1127
1123
|
function buildReadsTrivia(def) {
|
|
1124
|
+
if (!def.build) return true;
|
|
1128
1125
|
const src = def.buildSrc ?? def.build.toString();
|
|
1129
1126
|
const arity = confirmedBuildArity(src);
|
|
1130
1127
|
if (arity === null) return true;
|
|
1131
1128
|
return arity >= 4;
|
|
1132
1129
|
}
|
|
1133
1130
|
function buildReadsState(def) {
|
|
1131
|
+
if (!def.build) return true;
|
|
1134
1132
|
const src = def.buildSrc ?? def.build.toString();
|
|
1135
1133
|
const arity = confirmedBuildArity(src);
|
|
1136
1134
|
if (arity === null) return true;
|
|
@@ -1149,8 +1147,8 @@ function node(type, combinator, build, opts) {
|
|
|
1149
1147
|
};
|
|
1150
1148
|
const collapse = opts?.collapse === true;
|
|
1151
1149
|
const def = collapse ? { tag: "node", type, parser: combinator, build, collapse: true } : { tag: "node", type, parser: combinator, build };
|
|
1152
|
-
const capturesTrivia = buildReadsTrivia(def);
|
|
1153
|
-
const clonesState = buildReadsState(def);
|
|
1150
|
+
const capturesTrivia = build ? buildReadsTrivia(def) : true;
|
|
1151
|
+
const clonesState = build ? buildReadsState(def) : true;
|
|
1154
1152
|
return {
|
|
1155
1153
|
_tag: "node",
|
|
1156
1154
|
_meta: meta,
|
|
@@ -1161,13 +1159,8 @@ function node(type, combinator, build, opts) {
|
|
|
1161
1159
|
const r = combinator.parse(input, pos, ctx);
|
|
1162
1160
|
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
1163
1161
|
if (!r.ok) return r;
|
|
1164
|
-
const
|
|
1165
|
-
|
|
1166
|
-
rawChildren,
|
|
1167
|
-
r.span,
|
|
1168
|
-
triviaLog,
|
|
1169
|
-
clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0
|
|
1170
|
-
);
|
|
1162
|
+
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
1163
|
+
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 };
|
|
1171
1164
|
const isNodeLike = typeof built === "object" && built !== null && built._tag === "node";
|
|
1172
1165
|
const rawEntry = isNodeLike ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
|
|
1173
1166
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
@@ -1310,8 +1303,14 @@ function staticExpected(c) {
|
|
|
1310
1303
|
case "transform":
|
|
1311
1304
|
case "not":
|
|
1312
1305
|
return staticExpected(def.parser);
|
|
1313
|
-
case "lazy":
|
|
1314
|
-
|
|
1306
|
+
case "lazy": {
|
|
1307
|
+
const name = c._ruleName;
|
|
1308
|
+
try {
|
|
1309
|
+
return staticExpected(def.thunk());
|
|
1310
|
+
} catch {
|
|
1311
|
+
return name ? [name] : [];
|
|
1312
|
+
}
|
|
1313
|
+
}
|
|
1315
1314
|
default:
|
|
1316
1315
|
return [];
|
|
1317
1316
|
}
|
|
@@ -1611,6 +1610,15 @@ function seqIsUnambiguous(parts) {
|
|
|
1611
1610
|
const p = parts[k];
|
|
1612
1611
|
const mandatory = p.part === "lit" ? !p.optional : p.min === 1;
|
|
1613
1612
|
if (mandatory) hasMandatory = true;
|
|
1613
|
+
if (p.part === "group") {
|
|
1614
|
+
const exposure = groupPartExposure(p);
|
|
1615
|
+
if (exposure === "unsupported") {
|
|
1616
|
+
const trailingOnce = k === parts.length - 1 && p.min === 1 && !p.unbounded;
|
|
1617
|
+
if (!trailingOnce) return false;
|
|
1618
|
+
} else if (exposure !== null) {
|
|
1619
|
+
if (!firstSetsDisjoint(exposure, seqFirstAccept(parts.slice(k + 1)))) return false;
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1614
1622
|
const skippableSingle = p.part === "lit" && p.optional || p.part !== "lit" && !p.unbounded && p.min === 0;
|
|
1615
1623
|
const isUnboundedRepeat = p.part !== "lit" && p.unbounded;
|
|
1616
1624
|
if (skippableSingle || isUnboundedRepeat) {
|
|
@@ -1657,6 +1665,58 @@ function firstSetsDisjoint(a, b) {
|
|
|
1657
1665
|
if (a === "any" || b === "any") return false;
|
|
1658
1666
|
return classDisjoint(a, b);
|
|
1659
1667
|
}
|
|
1668
|
+
function fixedClassSeq(shape) {
|
|
1669
|
+
if (shape.kind !== "seq") return null;
|
|
1670
|
+
const out = [];
|
|
1671
|
+
for (const p of shape.parts) {
|
|
1672
|
+
if (p.part === "lit") {
|
|
1673
|
+
if (p.optional) return null;
|
|
1674
|
+
for (const cp of p.cps) out.push({ ranges: [[cp, cp]], negated: false });
|
|
1675
|
+
} else if (p.part === "run" && !p.unbounded && p.min === 1) {
|
|
1676
|
+
out.push({ ranges: p.ranges, negated: p.negated });
|
|
1677
|
+
} else {
|
|
1678
|
+
return null;
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
return out.length ? out : null;
|
|
1682
|
+
}
|
|
1683
|
+
function altFixedMutuallyExclusive(shape) {
|
|
1684
|
+
if (shape.kind !== "alt" || shape.disjoint) return false;
|
|
1685
|
+
const lists = [];
|
|
1686
|
+
for (const arm of shape.arms) {
|
|
1687
|
+
const f = fixedClassSeq(arm);
|
|
1688
|
+
if (!f) return false;
|
|
1689
|
+
lists.push(f);
|
|
1690
|
+
}
|
|
1691
|
+
for (let i = 0; i < lists.length; i++) {
|
|
1692
|
+
for (let j = 0; j < lists.length; j++) {
|
|
1693
|
+
if (i === j) continue;
|
|
1694
|
+
const a = lists[i];
|
|
1695
|
+
const b = lists[j];
|
|
1696
|
+
if (a.length > b.length) continue;
|
|
1697
|
+
let disjointAt = false;
|
|
1698
|
+
for (let p = 0; p < a.length; p++) {
|
|
1699
|
+
if (classDisjoint(a[p], b[p])) {
|
|
1700
|
+
disjointAt = true;
|
|
1701
|
+
break;
|
|
1702
|
+
}
|
|
1703
|
+
}
|
|
1704
|
+
if (!disjointAt) return false;
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
return true;
|
|
1708
|
+
}
|
|
1709
|
+
function groupPartExposure(part) {
|
|
1710
|
+
const innerWiggle = trailingBacktrackClass(part.inner);
|
|
1711
|
+
if (innerWiggle === "unsupported") return "unsupported";
|
|
1712
|
+
const requiredOnce = !part.unbounded && part.min === 1;
|
|
1713
|
+
if (requiredOnce) return innerWiggle;
|
|
1714
|
+
const dropExposed = shapeFirstAccept(part.inner);
|
|
1715
|
+
if (dropExposed === "any") return "unsupported";
|
|
1716
|
+
if (innerWiggle === null) return dropExposed;
|
|
1717
|
+
const unioned = unionCharSets([innerWiggle, dropExposed]);
|
|
1718
|
+
return unioned === "any" ? "unsupported" : unioned;
|
|
1719
|
+
}
|
|
1660
1720
|
function trailingBacktrackClass(shape) {
|
|
1661
1721
|
if (shape.kind === "chars") return { ranges: shape.ranges, negated: false };
|
|
1662
1722
|
if (shape.kind === "ident") return { ranges: shape.tail, negated: false };
|
|
@@ -1668,18 +1728,10 @@ function trailingBacktrackClass(shape) {
|
|
|
1668
1728
|
if (last.unbounded || last.min === 0) return { ranges: last.ranges, negated: last.negated };
|
|
1669
1729
|
return null;
|
|
1670
1730
|
}
|
|
1671
|
-
|
|
1672
|
-
if (innerWiggle === "unsupported") return "unsupported";
|
|
1673
|
-
const requiredOnce = !last.unbounded && last.min === 1;
|
|
1674
|
-
if (requiredOnce) return innerWiggle;
|
|
1675
|
-
const dropExposed = shapeFirstAccept(last.inner);
|
|
1676
|
-
if (dropExposed === "any") return "unsupported";
|
|
1677
|
-
if (innerWiggle === null) return dropExposed;
|
|
1678
|
-
const unioned = unionCharSets([innerWiggle, dropExposed]);
|
|
1679
|
-
return unioned === "any" ? "unsupported" : unioned;
|
|
1731
|
+
return groupPartExposure(last);
|
|
1680
1732
|
}
|
|
1681
1733
|
if (shape.kind === "alt") {
|
|
1682
|
-
if (!shape.disjoint) return "unsupported";
|
|
1734
|
+
if (!shape.disjoint) return altFixedMutuallyExclusive(shape) ? null : "unsupported";
|
|
1683
1735
|
const classes = shape.arms.map(trailingBacktrackClass);
|
|
1684
1736
|
if (classes.some((c) => c === "unsupported")) return "unsupported";
|
|
1685
1737
|
const concrete = classes.filter((c) => c !== null);
|
|
@@ -1819,7 +1871,7 @@ function seqFirstAccept(parts) {
|
|
|
1819
1871
|
function groupInnerSafe(shape) {
|
|
1820
1872
|
if (shape.kind === "chars" || shape.kind === "ident" || shape.kind === "seq" || shape.kind === "litFold") return true;
|
|
1821
1873
|
if (shape.kind === "lookahead") return groupInnerSafe(shape.inner);
|
|
1822
|
-
if (shape.kind === "alt") return
|
|
1874
|
+
if (shape.kind === "alt") return true;
|
|
1823
1875
|
return false;
|
|
1824
1876
|
}
|
|
1825
1877
|
function shapeFirstAccept(shape) {
|
|
@@ -1847,9 +1899,8 @@ function shapeFirstAccept(shape) {
|
|
|
1847
1899
|
return shapeFirstAccept(shape.inner);
|
|
1848
1900
|
// zero-width — doesn't change first-char acceptance
|
|
1849
1901
|
case "alt": {
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
return sets.length === shape.arms.length ? unionCharSets(sets) : "any";
|
|
1902
|
+
const sets = shape.firsts.map((f) => f === null ? "any" : f);
|
|
1903
|
+
return unionCharSets(sets);
|
|
1853
1904
|
}
|
|
1854
1905
|
}
|
|
1855
1906
|
}
|
|
@@ -1890,6 +1941,120 @@ function parseScanShape(source) {
|
|
|
1890
1941
|
}
|
|
1891
1942
|
return parseScanShapeCore(source);
|
|
1892
1943
|
}
|
|
1944
|
+
function splitDelimArms(body) {
|
|
1945
|
+
const arms = [];
|
|
1946
|
+
let depth = 0;
|
|
1947
|
+
let last = 0;
|
|
1948
|
+
let i = 0;
|
|
1949
|
+
while (i < body.length) {
|
|
1950
|
+
const ch = body[i];
|
|
1951
|
+
if (ch === "\\") {
|
|
1952
|
+
i += 2;
|
|
1953
|
+
continue;
|
|
1954
|
+
}
|
|
1955
|
+
if (ch === "[") {
|
|
1956
|
+
let j = i + 1;
|
|
1957
|
+
if (body[j] === "^") j++;
|
|
1958
|
+
while (j < body.length && body[j] !== "]") {
|
|
1959
|
+
if (body[j] === "\\") j += 2;
|
|
1960
|
+
else j++;
|
|
1961
|
+
}
|
|
1962
|
+
if (body[j] !== "]") return null;
|
|
1963
|
+
i = j + 1;
|
|
1964
|
+
continue;
|
|
1965
|
+
}
|
|
1966
|
+
if (ch === "(") {
|
|
1967
|
+
depth++;
|
|
1968
|
+
i++;
|
|
1969
|
+
continue;
|
|
1970
|
+
}
|
|
1971
|
+
if (ch === ")") {
|
|
1972
|
+
depth--;
|
|
1973
|
+
if (depth < 0) return null;
|
|
1974
|
+
i++;
|
|
1975
|
+
continue;
|
|
1976
|
+
}
|
|
1977
|
+
if (ch === "|" && depth === 0) {
|
|
1978
|
+
arms.push(body.slice(last, i));
|
|
1979
|
+
last = i + 1;
|
|
1980
|
+
}
|
|
1981
|
+
i++;
|
|
1982
|
+
}
|
|
1983
|
+
if (depth !== 0) return null;
|
|
1984
|
+
arms.push(body.slice(last));
|
|
1985
|
+
return arms;
|
|
1986
|
+
}
|
|
1987
|
+
function delimitedBodySound(body, close) {
|
|
1988
|
+
const l0 = close[0];
|
|
1989
|
+
if (close.length > 2) return false;
|
|
1990
|
+
const arms = splitDelimArms(body);
|
|
1991
|
+
if (!arms) return false;
|
|
1992
|
+
let bulkSeen = false;
|
|
1993
|
+
let guardSeen = false;
|
|
1994
|
+
for (const arm of arms) {
|
|
1995
|
+
const bulk = /^\[\^((?:\\.|[^\]])+)\]$/.exec(arm);
|
|
1996
|
+
if (bulk) {
|
|
1997
|
+
if (bulkSeen) return false;
|
|
1998
|
+
const ranges = parseClassRanges(bulk[1]);
|
|
1999
|
+
if (!ranges || ranges.length !== 1 || ranges[0][0] !== l0 || ranges[0][1] !== l0) return false;
|
|
2000
|
+
bulkSeen = true;
|
|
2001
|
+
continue;
|
|
2002
|
+
}
|
|
2003
|
+
if (close.length === 2 && arm.endsWith(")")) {
|
|
2004
|
+
const idx = arm.indexOf("(?!");
|
|
2005
|
+
if (idx === -1) return false;
|
|
2006
|
+
const prefix = literalCodePoints(arm.slice(0, idx));
|
|
2007
|
+
const op = parseClassOperand(arm.slice(idx + 3, -1));
|
|
2008
|
+
const prefixIsL0 = prefix?.length === 1 && prefix[0] === l0;
|
|
2009
|
+
const forbidsL1 = op && !op.negated && op.ranges.length === 1 && op.ranges[0][0] === close[1] && op.ranges[0][1] === close[1];
|
|
2010
|
+
if (!prefixIsL0 || !forbidsL1 || guardSeen) return false;
|
|
2011
|
+
guardSeen = true;
|
|
2012
|
+
continue;
|
|
2013
|
+
}
|
|
2014
|
+
return false;
|
|
2015
|
+
}
|
|
2016
|
+
return bulkSeen && guardSeen === (close.length === 2);
|
|
2017
|
+
}
|
|
2018
|
+
function parseDelimited(source) {
|
|
2019
|
+
if (source.includes("\\\\")) return null;
|
|
2020
|
+
let i = 0;
|
|
2021
|
+
while (i < source.length && source[i] !== "(") {
|
|
2022
|
+
i += source[i] === "\\" ? 2 : 1;
|
|
2023
|
+
}
|
|
2024
|
+
if (source[i] !== "(" || source[i + 1] !== "?" || source[i + 2] !== ":") return null;
|
|
2025
|
+
const openFrag = source.slice(0, i);
|
|
2026
|
+
let k = i + 3;
|
|
2027
|
+
let depth = 1;
|
|
2028
|
+
while (k < source.length && depth > 0) {
|
|
2029
|
+
const ch = source[k];
|
|
2030
|
+
if (ch === "\\") {
|
|
2031
|
+
k += 2;
|
|
2032
|
+
continue;
|
|
2033
|
+
}
|
|
2034
|
+
if (ch === "[") {
|
|
2035
|
+
let j = k + 1;
|
|
2036
|
+
if (source[j] === "^") j++;
|
|
2037
|
+
while (j < source.length && source[j] !== "]") {
|
|
2038
|
+
if (source[j] === "\\") j += 2;
|
|
2039
|
+
else j++;
|
|
2040
|
+
}
|
|
2041
|
+
if (source[j] !== "]") return null;
|
|
2042
|
+
k = j + 1;
|
|
2043
|
+
continue;
|
|
2044
|
+
}
|
|
2045
|
+
if (ch === "(") depth++;
|
|
2046
|
+
else if (ch === ")") depth--;
|
|
2047
|
+
k++;
|
|
2048
|
+
}
|
|
2049
|
+
if (depth !== 0) return null;
|
|
2050
|
+
const body = source.slice(i + 3, k - 1);
|
|
2051
|
+
if (source[k] !== "*") return null;
|
|
2052
|
+
const closeFrag = source.slice(k + 1);
|
|
2053
|
+
const open = literalCodePoints(openFrag);
|
|
2054
|
+
const close = literalCodePoints(closeFrag);
|
|
2055
|
+
if (!open || !close || !delimitedBodySound(body, close)) return null;
|
|
2056
|
+
return { kind: "delimited", open, close };
|
|
2057
|
+
}
|
|
1893
2058
|
function parseScanShapeCore(source) {
|
|
1894
2059
|
let m = /^\[((?:\\.|[^\]])+)\]([+*])$/.exec(source);
|
|
1895
2060
|
if (m && !m[1].startsWith("^")) {
|
|
@@ -1914,14 +2079,8 @@ function parseScanShapeCore(source) {
|
|
|
1914
2079
|
const stop = parseClassRanges(m[2]);
|
|
1915
2080
|
if (open && stop) return { kind: "until", open, stop };
|
|
1916
2081
|
}
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
if (m && m[1] && m[2]) {
|
|
1920
|
-
const open = literalCodePoints(m[1]);
|
|
1921
|
-
const close = literalCodePoints(m[2]);
|
|
1922
|
-
if (open && close) return { kind: "delimited", open, close };
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
2082
|
+
const delim = parseDelimited(source);
|
|
2083
|
+
if (delim) return delim;
|
|
1925
2084
|
const parts = parseSeqParts(source);
|
|
1926
2085
|
if (parts && seqIsUnambiguous(parts)) return { kind: "seq", parts };
|
|
1927
2086
|
return null;
|
|
@@ -2376,6 +2535,7 @@ function looseMkBuildRe(type) {
|
|
|
2376
2535
|
);
|
|
2377
2536
|
}
|
|
2378
2537
|
function analyzeMkInlineBuild(def) {
|
|
2538
|
+
if (!def.build) return null;
|
|
2379
2539
|
const src = (def.buildSrc ?? def.build.toString()).trim();
|
|
2380
2540
|
const strict = src.match(MK_BUILD_RE);
|
|
2381
2541
|
if (strict) {
|
|
@@ -2473,6 +2633,15 @@ function v(ctx, prefix = "_v") {
|
|
|
2473
2633
|
function ind(ctx) {
|
|
2474
2634
|
return " ".repeat(ctx.indent);
|
|
2475
2635
|
}
|
|
2636
|
+
function nsp(ctx) {
|
|
2637
|
+
return ctx.ns ?? "";
|
|
2638
|
+
}
|
|
2639
|
+
function mfRef(ctx) {
|
|
2640
|
+
return `${nsp(ctx)}_mf`;
|
|
2641
|
+
}
|
|
2642
|
+
function buildRef(ctx) {
|
|
2643
|
+
return `${nsp(ctx)}_build`;
|
|
2644
|
+
}
|
|
2476
2645
|
function reindentStmts(stmts, targetLevels) {
|
|
2477
2646
|
const nonEmpty = stmts.filter((s) => s.trim().length > 0);
|
|
2478
2647
|
if (nonEmpty.length === 0) return stmts;
|
|
@@ -2489,7 +2658,7 @@ function failReturnArr(expectedArr, posExpr) {
|
|
|
2489
2658
|
function hoistExpected(ctx, constArrSource) {
|
|
2490
2659
|
let name = ctx.expectedMap.get(constArrSource);
|
|
2491
2660
|
if (name === void 0) {
|
|
2492
|
-
name =
|
|
2661
|
+
name = `${nsp(ctx)}_fx${ctx.expectedDecls.length}`;
|
|
2493
2662
|
ctx.expectedDecls.push(`const ${name} = ${constArrSource}`);
|
|
2494
2663
|
ctx.expectedMap.set(constArrSource, name);
|
|
2495
2664
|
}
|
|
@@ -2588,13 +2757,13 @@ function emitLeafCapture(ctx, valExpr, startExpr, endExpr) {
|
|
|
2588
2757
|
`${i}}`
|
|
2589
2758
|
];
|
|
2590
2759
|
}
|
|
2591
|
-
function ensureRegexDecl(ctx,
|
|
2760
|
+
function ensureRegexDecl(ctx, source, flags) {
|
|
2592
2761
|
const f = "y" + flags.replace(/[gy]/g, "");
|
|
2593
|
-
const key = `${
|
|
2762
|
+
const key = `${source}/${f}`;
|
|
2594
2763
|
let rName = ctx.regexMap.get(key);
|
|
2595
2764
|
if (rName === void 0) {
|
|
2596
|
-
rName =
|
|
2597
|
-
ctx.regexDecls.push(`const ${rName} = /${
|
|
2765
|
+
rName = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
|
|
2766
|
+
ctx.regexDecls.push(`const ${rName} = /${source}/${f}`);
|
|
2598
2767
|
ctx.regexMap.set(key, rName);
|
|
2599
2768
|
}
|
|
2600
2769
|
return rName;
|
|
@@ -2603,7 +2772,7 @@ function ensureTriviaFn(ctx) {
|
|
|
2603
2772
|
const trivia2 = ctx.activeTrivia;
|
|
2604
2773
|
const existing = ctx.triviaFnNames.get(trivia2);
|
|
2605
2774
|
if (existing) return existing;
|
|
2606
|
-
const fnName =
|
|
2775
|
+
const fnName = `${nsp(ctx)}_tf${ctx.triviaFnNames.size}`;
|
|
2607
2776
|
ctx.triviaFnNames.set(trivia2, fnName);
|
|
2608
2777
|
ctx.triviaCaptureNames.set(trivia2, fnName);
|
|
2609
2778
|
const labeledSpec = analyzeLabeledTrivia(trivia2);
|
|
@@ -2625,7 +2794,7 @@ function ensureTriviaFn(ctx) {
|
|
|
2625
2794
|
for (const arm of regexSpec.arms) {
|
|
2626
2795
|
const def = arm.parser._def;
|
|
2627
2796
|
if (def.tag !== "regex") break;
|
|
2628
|
-
reNames.push(ensureRegexDecl(ctx, def.
|
|
2797
|
+
reNames.push(ensureRegexDecl(ctx, def.source, def.flags));
|
|
2629
2798
|
}
|
|
2630
2799
|
if (reNames.length === regexSpec.arms.length) {
|
|
2631
2800
|
ctx.namedFnDecls.push(buildLabeledRegexTriviaFnDecl(fnName, regexSpec, reNames));
|
|
@@ -2950,7 +3119,7 @@ function emitKeywords(def, ctx, pos) {
|
|
|
2950
3119
|
const key = `${source}/${flags}`;
|
|
2951
3120
|
let rName = ctx.regexMap.get(key);
|
|
2952
3121
|
if (rName === void 0) {
|
|
2953
|
-
rName =
|
|
3122
|
+
rName = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
|
|
2954
3123
|
ctx.regexDecls.push(`const ${rName} = /${source}/${flags}`);
|
|
2955
3124
|
ctx.regexMap.set(key, rName);
|
|
2956
3125
|
}
|
|
@@ -2984,11 +3153,11 @@ function emitRegex(def, ctx, pos) {
|
|
|
2984
3153
|
}
|
|
2985
3154
|
}
|
|
2986
3155
|
const flags = "y" + def.flags.replace(/[gy]/g, "");
|
|
2987
|
-
const key = `${def.
|
|
3156
|
+
const key = `${def.source}/${flags}`;
|
|
2988
3157
|
let rName = ctx.regexMap.get(key);
|
|
2989
3158
|
if (rName === void 0) {
|
|
2990
|
-
rName =
|
|
2991
|
-
ctx.regexDecls.push(`const ${rName} = /${def.
|
|
3159
|
+
rName = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
|
|
3160
|
+
ctx.regexDecls.push(`const ${rName} = /${def.source}/${flags}`);
|
|
2992
3161
|
ctx.regexMap.set(key, rName);
|
|
2993
3162
|
}
|
|
2994
3163
|
const mv = v(ctx, "_m");
|
|
@@ -3165,7 +3334,7 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
3165
3334
|
const reKey = `${regexDef.source}/${cleanFlags}`;
|
|
3166
3335
|
let reVar = ctx.regexMap.get(reKey);
|
|
3167
3336
|
if (reVar === void 0) {
|
|
3168
|
-
reVar =
|
|
3337
|
+
reVar = `${nsp(ctx)}_re${ctx.regexDecls.length}`;
|
|
3169
3338
|
ctx.regexDecls.push(`const ${reVar} = /${regexDef.source}/${cleanFlags}`);
|
|
3170
3339
|
ctx.regexMap.set(reKey, reVar);
|
|
3171
3340
|
}
|
|
@@ -3258,7 +3427,7 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
3258
3427
|
if (gate) {
|
|
3259
3428
|
const gateIdx = ctx.mapFns.length;
|
|
3260
3429
|
ctx.mapFns.push(gate);
|
|
3261
|
-
gateCond =
|
|
3430
|
+
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
3262
3431
|
}
|
|
3263
3432
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
3264
3433
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
@@ -3325,7 +3494,7 @@ function emitTransformChain(p, baseValue, endV, startPos, ctx) {
|
|
|
3325
3494
|
ctx.mapFnSrcs.push(def.fnSrc ?? null);
|
|
3326
3495
|
const vv = v(ctx);
|
|
3327
3496
|
return {
|
|
3328
|
-
stmts: [...innerR.stmts, `${ind(ctx)}const ${vv} =
|
|
3497
|
+
stmts: [...innerR.stmts, `${ind(ctx)}const ${vv} = ${mfRef(ctx)}[${fnIdx}](${innerR.valueVar}, { start: ${startPos}, end: ${endV} })`],
|
|
3329
3498
|
valueVar: vv,
|
|
3330
3499
|
endVar: endV
|
|
3331
3500
|
};
|
|
@@ -3553,16 +3722,17 @@ function emitNot(def, ctx, pos) {
|
|
|
3553
3722
|
};
|
|
3554
3723
|
}
|
|
3555
3724
|
function emitNode(def, ctx, pos) {
|
|
3556
|
-
const
|
|
3725
|
+
const structural = def.build === void 0;
|
|
3726
|
+
const mkType = structural ? null : analyzeMkInlineBuild(def);
|
|
3557
3727
|
let buildIdx = null;
|
|
3558
|
-
if (!mkType) {
|
|
3728
|
+
if (!mkType && !structural) {
|
|
3559
3729
|
buildIdx = ctx.buildFns.length;
|
|
3560
3730
|
ctx.buildFns.push(def.build);
|
|
3561
3731
|
ctx.buildSrcs.push(def.buildSrc ?? null);
|
|
3562
3732
|
}
|
|
3563
3733
|
const i = ind(ctx);
|
|
3564
|
-
const capturesTrivia = mkType !== null || buildReadsTrivia(def);
|
|
3565
|
-
const clonesState = buildReadsState(def);
|
|
3734
|
+
const capturesTrivia = mkType !== null || structural || buildReadsTrivia(def);
|
|
3735
|
+
const clonesState = structural || buildReadsState(def);
|
|
3566
3736
|
const chV = v(ctx, "_ch");
|
|
3567
3737
|
const rawV = v(ctx, "_raw");
|
|
3568
3738
|
const tlV = capturesTrivia ? v(ctx, "_tl") : "_EMPTY_TL";
|
|
@@ -3585,7 +3755,8 @@ function emitNode(def, ctx, pos) {
|
|
|
3585
3755
|
stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
|
|
3586
3756
|
}
|
|
3587
3757
|
const ndV = v(ctx, "_nd");
|
|
3588
|
-
const
|
|
3758
|
+
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})`;
|
|
3759
|
+
const ndExpr = ctx.ns || structural ? `_ctx.build !== undefined ? _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${rawV}, { start: ${pos}, end: ${endVar} }, ${tlV}, ${stV}) : (${buildExpr})` : buildExpr;
|
|
3589
3760
|
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;
|
|
3590
3761
|
stmts.push(
|
|
3591
3762
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
@@ -3610,8 +3781,9 @@ function emitRuntimeFallback(parser2, ctx, pos) {
|
|
|
3610
3781
|
return { stmts, valueVar: vv, endVar: ev };
|
|
3611
3782
|
}
|
|
3612
3783
|
function emitLazy(p, def, ctx, pos) {
|
|
3784
|
+
const canonical = ctx.ruleNames?.get(p);
|
|
3613
3785
|
const usage = ctx.lazyUsage;
|
|
3614
|
-
if (usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
|
|
3786
|
+
if (!canonical && usage && (usage.counts.get(p) ?? 0) <= 1 && !usage.recursive.has(p)) {
|
|
3615
3787
|
let resolved;
|
|
3616
3788
|
try {
|
|
3617
3789
|
resolved = def.thunk();
|
|
@@ -3621,7 +3793,7 @@ function emitLazy(p, def, ctx, pos) {
|
|
|
3621
3793
|
return emit(resolved, ctx, pos);
|
|
3622
3794
|
}
|
|
3623
3795
|
if (!ctx.namedParsers.has(p)) {
|
|
3624
|
-
const fnName2 =
|
|
3796
|
+
const fnName2 = canonical ?? `${nsp(ctx)}_pf${ctx.namedParsers.size}`;
|
|
3625
3797
|
ctx.namedParsers.set(p, fnName2);
|
|
3626
3798
|
let resolved;
|
|
3627
3799
|
try {
|
|
@@ -3739,7 +3911,7 @@ function emit(p, ctx, pos) {
|
|
|
3739
3911
|
return {
|
|
3740
3912
|
stmts: [
|
|
3741
3913
|
...inner.stmts,
|
|
3742
|
-
`${ind(ctx)}const ${mv} =
|
|
3914
|
+
`${ind(ctx)}const ${mv} = ${mfRef(ctx)}[${fnIdx}](${inner.valueVar}, { start: ${pos}, end: ${inner.endVar} })`
|
|
3743
3915
|
],
|
|
3744
3916
|
valueVar: mv,
|
|
3745
3917
|
endVar: inner.endVar
|
|
@@ -3802,7 +3974,7 @@ function emit(p, ctx, pos) {
|
|
|
3802
3974
|
const vv = v(ctx);
|
|
3803
3975
|
return {
|
|
3804
3976
|
stmts: [
|
|
3805
|
-
...emitIfFail(ctx,
|
|
3977
|
+
...emitIfFail(ctx, `!${mfRef(ctx)}[${fnIdx}](_ctx.state)`, failBody(ctx, '"gate"', pos)),
|
|
3806
3978
|
`${ind(ctx)}const ${vv} = null`
|
|
3807
3979
|
],
|
|
3808
3980
|
valueVar: vv,
|
|
@@ -3835,7 +4007,7 @@ function emit(p, ctx, pos) {
|
|
|
3835
4007
|
const ev = v(ctx, "_wce");
|
|
3836
4008
|
return {
|
|
3837
4009
|
stmts: [
|
|
3838
|
-
`${ind(ctx)}const ${rv} = { ..._ctx, state:
|
|
4010
|
+
`${ind(ctx)}const ${rv} = { ..._ctx, state: ${mfRef(ctx)}[${evIdx}]() }`,
|
|
3839
4011
|
`${ind(ctx)}const ${vv} = ${fn}(input, ${pos}, ${rv})`,
|
|
3840
4012
|
// withCtx runs on a spread child ctx — copy its recorded failure back
|
|
3841
4013
|
// and propagate the inner failure verbatim (interpreter parity).
|
|
@@ -3966,6 +4138,39 @@ function analyzeLazyUsageMulti(roots) {
|
|
|
3966
4138
|
for (const root of roots) walk2(root);
|
|
3967
4139
|
return { counts, recursive };
|
|
3968
4140
|
}
|
|
4141
|
+
function ruleDependencies(ruleMap) {
|
|
4142
|
+
const nameOf = /* @__PURE__ */ new Map();
|
|
4143
|
+
for (const [name, comb] of ruleMap) nameOf.set(comb, name);
|
|
4144
|
+
const deps = /* @__PURE__ */ new Map();
|
|
4145
|
+
for (const [name, comb] of ruleMap) {
|
|
4146
|
+
const found = /* @__PURE__ */ new Set();
|
|
4147
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4148
|
+
const walk2 = (p, isRoot) => {
|
|
4149
|
+
const def = p._def;
|
|
4150
|
+
const boundary = def.tag === "lazy" ? p._ruleName ?? nameOf.get(p) : nameOf.get(p);
|
|
4151
|
+
if (!isRoot && boundary !== void 0) {
|
|
4152
|
+
found.add(boundary);
|
|
4153
|
+
return;
|
|
4154
|
+
}
|
|
4155
|
+
if (seen.has(p)) return;
|
|
4156
|
+
seen.add(p);
|
|
4157
|
+
if (def.tag === "lazy") {
|
|
4158
|
+
let resolved;
|
|
4159
|
+
try {
|
|
4160
|
+
resolved = def.thunk();
|
|
4161
|
+
} catch {
|
|
4162
|
+
return;
|
|
4163
|
+
}
|
|
4164
|
+
walk2(resolved, false);
|
|
4165
|
+
return;
|
|
4166
|
+
}
|
|
4167
|
+
for (const child of childrenOf(def)) walk2(child, false);
|
|
4168
|
+
};
|
|
4169
|
+
walk2(comb, true);
|
|
4170
|
+
deps.set(name, [...found]);
|
|
4171
|
+
}
|
|
4172
|
+
return deps;
|
|
4173
|
+
}
|
|
3969
4174
|
function compile(combinator, mapFnSources) {
|
|
3970
4175
|
const ctx = {
|
|
3971
4176
|
vars: 0,
|
|
@@ -4071,6 +4276,15 @@ function compileRuleMap(ruleMap) {
|
|
|
4071
4276
|
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
4072
4277
|
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule))
|
|
4073
4278
|
};
|
|
4279
|
+
const seenNames = /* @__PURE__ */ new Map();
|
|
4280
|
+
const ruleNames = /* @__PURE__ */ new Map();
|
|
4281
|
+
for (const [key, rule] of ruleMap) {
|
|
4282
|
+
const base = `_r_${key.replace(/[^A-Za-z0-9_$]/g, "_")}`;
|
|
4283
|
+
const n = seenNames.get(base) ?? 0;
|
|
4284
|
+
seenNames.set(base, n + 1);
|
|
4285
|
+
ruleNames.set(rule, n === 0 ? base : `${base}$${n}`);
|
|
4286
|
+
}
|
|
4287
|
+
ctx.ruleNames = ruleNames;
|
|
4074
4288
|
const perEntry = ruleMap.map(([key, rule]) => ({ key, r: emit(rule, ctx, "_pos") }));
|
|
4075
4289
|
const collatorDecl = ctx.needsCollator ? `const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })
|
|
4076
4290
|
` : "";
|
|
@@ -4080,8 +4294,8 @@ function compileRuleMap(ruleMap) {
|
|
|
4080
4294
|
const mfCovered = ctx.mapFns.length === 0 || derivedSrcs !== void 0;
|
|
4081
4295
|
const canInline = ctx.runtimeParsers.length === 0 && mfCovered && buildCovered;
|
|
4082
4296
|
if (!canInline) return null;
|
|
4083
|
-
const mfDecl = derivedSrcs?.length ? ` const
|
|
4084
|
-
const buildDecl = buildSources?.length ? ` const
|
|
4297
|
+
const mfDecl = derivedSrcs?.length ? ` const ${mfRef(ctx)} = [${derivedSrcs.join(", ")}]` : "";
|
|
4298
|
+
const buildDecl = buildSources?.length ? ` const ${buildRef(ctx)} = [${buildSources.join(", ")}]` : "";
|
|
4085
4299
|
const namedPrelude = ctx.namedFnDecls.length > 0 ? namedFnPrelude() : [];
|
|
4086
4300
|
const hoistedDecls = [
|
|
4087
4301
|
ctx.needsEmptyTl ? ` const _EMPTY_TL = Object.freeze([])` : "",
|
|
@@ -4114,6 +4328,150 @@ function compileRuleMap(ruleMap) {
|
|
|
4114
4328
|
].join("\n");
|
|
4115
4329
|
return { keys: perEntry.map((e) => e.key), replacement };
|
|
4116
4330
|
}
|
|
4331
|
+
function compileLinkable(ruleMapArg, ns) {
|
|
4332
|
+
if (!ns) throw new Error("compileLinkable: ns must be a non-empty namespace");
|
|
4333
|
+
const ruleMap = ruleMapArg.filter(([, val]) => {
|
|
4334
|
+
const d = val._def;
|
|
4335
|
+
if (d.tag !== "lazy") return true;
|
|
4336
|
+
try {
|
|
4337
|
+
d.thunk();
|
|
4338
|
+
return true;
|
|
4339
|
+
} catch {
|
|
4340
|
+
return false;
|
|
4341
|
+
}
|
|
4342
|
+
});
|
|
4343
|
+
const ctx = {
|
|
4344
|
+
vars: 0,
|
|
4345
|
+
indent: 1,
|
|
4346
|
+
regexDecls: [],
|
|
4347
|
+
regexMap: /* @__PURE__ */ new Map(),
|
|
4348
|
+
expectedDecls: [],
|
|
4349
|
+
expectedMap: /* @__PURE__ */ new Map(),
|
|
4350
|
+
recordFail: true,
|
|
4351
|
+
mapFns: [],
|
|
4352
|
+
mapFnSrcs: [],
|
|
4353
|
+
buildFns: [],
|
|
4354
|
+
buildSrcs: [],
|
|
4355
|
+
runtimeParsers: [],
|
|
4356
|
+
needsCollator: false,
|
|
4357
|
+
namedParsers: /* @__PURE__ */ new Map(),
|
|
4358
|
+
triviaCaptureNames: /* @__PURE__ */ new Map(),
|
|
4359
|
+
triviaFnNames: /* @__PURE__ */ new Map(),
|
|
4360
|
+
namedFnDecls: [],
|
|
4361
|
+
capturing: ruleMap.some(([, rule]) => hasNodeDef(rule)),
|
|
4362
|
+
lazyUsage: analyzeLazyUsageMulti(ruleMap.map(([, rule]) => rule)),
|
|
4363
|
+
ns
|
|
4364
|
+
};
|
|
4365
|
+
const seen = /* @__PURE__ */ new Map();
|
|
4366
|
+
const ruleNames = /* @__PURE__ */ new Map();
|
|
4367
|
+
const fnNameToKey = /* @__PURE__ */ new Map();
|
|
4368
|
+
for (const [key, rule] of ruleMap) {
|
|
4369
|
+
const base = `_r_${key.replace(/[^A-Za-z0-9_$]/g, "_")}`;
|
|
4370
|
+
const n = seen.get(base) ?? 0;
|
|
4371
|
+
seen.set(base, n + 1);
|
|
4372
|
+
const fn = n === 0 ? base : `${base}$${n}`;
|
|
4373
|
+
ruleNames.set(rule, fn);
|
|
4374
|
+
fnNameToKey.set(fn, key);
|
|
4375
|
+
}
|
|
4376
|
+
ctx.ruleNames = ruleNames;
|
|
4377
|
+
{
|
|
4378
|
+
const scanned = /* @__PURE__ */ new Set();
|
|
4379
|
+
const scanExternal = (p) => {
|
|
4380
|
+
if (scanned.has(p)) return;
|
|
4381
|
+
scanned.add(p);
|
|
4382
|
+
const def = p._def;
|
|
4383
|
+
if (def.tag === "lazy") {
|
|
4384
|
+
let resolved;
|
|
4385
|
+
try {
|
|
4386
|
+
resolved = def.thunk();
|
|
4387
|
+
} catch {
|
|
4388
|
+
resolved = void 0;
|
|
4389
|
+
}
|
|
4390
|
+
if (resolved === void 0) {
|
|
4391
|
+
const name = p._ruleName;
|
|
4392
|
+
if (name && !ctx.namedParsers.has(p)) {
|
|
4393
|
+
const fn = `_r_${name.replace(/[^A-Za-z0-9_$]/g, "_")}`;
|
|
4394
|
+
ruleNames.set(p, fn);
|
|
4395
|
+
ctx.namedParsers.set(p, fn);
|
|
4396
|
+
}
|
|
4397
|
+
return;
|
|
4398
|
+
}
|
|
4399
|
+
scanExternal(resolved);
|
|
4400
|
+
return;
|
|
4401
|
+
}
|
|
4402
|
+
for (const child of childrenOf(def)) scanExternal(child);
|
|
4403
|
+
};
|
|
4404
|
+
for (const [, rule] of ruleMap) scanExternal(rule);
|
|
4405
|
+
}
|
|
4406
|
+
const perEntry = [];
|
|
4407
|
+
for (const [key, rule] of ruleMap) {
|
|
4408
|
+
const fn = ruleNames.get(rule);
|
|
4409
|
+
if (!ctx.namedParsers.has(rule)) {
|
|
4410
|
+
ctx.namedParsers.set(rule, fn);
|
|
4411
|
+
let resolved = rule;
|
|
4412
|
+
const def = rule._def;
|
|
4413
|
+
if (def.tag === "lazy") {
|
|
4414
|
+
try {
|
|
4415
|
+
resolved = def.thunk();
|
|
4416
|
+
} catch {
|
|
4417
|
+
return null;
|
|
4418
|
+
}
|
|
4419
|
+
}
|
|
4420
|
+
const savedIndent = ctx.indent, savedFail = ctx.failLabel, savedRec = ctx.recordFail;
|
|
4421
|
+
ctx.indent = 1;
|
|
4422
|
+
ctx.failLabel = "_pfail";
|
|
4423
|
+
ctx.recordFail = true;
|
|
4424
|
+
const body = emit(resolved, ctx, "_pos");
|
|
4425
|
+
ctx.indent = savedIndent;
|
|
4426
|
+
ctx.failLabel = savedFail;
|
|
4427
|
+
ctx.recordFail = savedRec;
|
|
4428
|
+
pushNamedFnDecl(ctx, fn, body.stmts, body.valueVar, body.endVar);
|
|
4429
|
+
}
|
|
4430
|
+
perEntry.push({ key, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
4431
|
+
}
|
|
4432
|
+
if (ctx.runtimeParsers.length !== 0) return null;
|
|
4433
|
+
const mfSrcs = ctx.mapFns.length > 0 && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : null;
|
|
4434
|
+
const buildSrcs = ctx.buildFns.length > 0 && ctx.buildSrcs.every((s) => s !== null) ? ctx.buildSrcs : null;
|
|
4435
|
+
const ruleFns = /* @__PURE__ */ new Map();
|
|
4436
|
+
const privateFns = [];
|
|
4437
|
+
for (const decl of ctx.namedFnDecls) {
|
|
4438
|
+
const fnName = decl.match(/^function (\S+?)\(/)?.[1];
|
|
4439
|
+
const key = fnName ? fnNameToKey.get(fnName) : void 0;
|
|
4440
|
+
if (key !== void 0) ruleFns.set(key, decl);
|
|
4441
|
+
else privateFns.push(decl);
|
|
4442
|
+
}
|
|
4443
|
+
const mfDecl = ctx.mapFns.length === 0 ? "" : mfSrcs ? `const ${mfRef(ctx)} = [${mfSrcs.join(", ")}]` : `const ${mfRef(ctx)} = _env[${JSON.stringify(nsp(ctx) + "mf")}]`;
|
|
4444
|
+
const buildDecl = ctx.buildFns.length === 0 ? "" : buildSrcs ? `const ${buildRef(ctx)} = [${buildSrcs.join(", ")}]` : `const ${buildRef(ctx)} = _env[${JSON.stringify(nsp(ctx) + "build")}]`;
|
|
4445
|
+
const prelude = [
|
|
4446
|
+
...ctx.regexDecls,
|
|
4447
|
+
...ctx.expectedDecls,
|
|
4448
|
+
mfDecl,
|
|
4449
|
+
buildDecl,
|
|
4450
|
+
...privateFns
|
|
4451
|
+
].filter(Boolean);
|
|
4452
|
+
const wrappers = /* @__PURE__ */ new Map();
|
|
4453
|
+
for (const { key, r } of perEntry) {
|
|
4454
|
+
wrappers.set(key, [
|
|
4455
|
+
`function(input, _pos, _ctx) {`,
|
|
4456
|
+
` let pos = _pos`,
|
|
4457
|
+
...r.stmts,
|
|
4458
|
+
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
4459
|
+
`}`
|
|
4460
|
+
].join("\n"));
|
|
4461
|
+
}
|
|
4462
|
+
return {
|
|
4463
|
+
ns,
|
|
4464
|
+
keys: perEntry.map((e) => e.key),
|
|
4465
|
+
prelude,
|
|
4466
|
+
ruleFns,
|
|
4467
|
+
wrappers,
|
|
4468
|
+
deps: ruleDependencies(ruleMap),
|
|
4469
|
+
needsEmptyTl: !!ctx.needsEmptyTl,
|
|
4470
|
+
needsCollator: ctx.needsCollator,
|
|
4471
|
+
mfFns: mfSrcs ? [] : ctx.mapFns,
|
|
4472
|
+
buildFns: buildSrcs ? [] : ctx.buildFns
|
|
4473
|
+
};
|
|
4474
|
+
}
|
|
4117
4475
|
function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources) {
|
|
4118
4476
|
const bodyLines = [
|
|
4119
4477
|
` let pos = _pos`,
|
|
@@ -4152,6 +4510,48 @@ function buildInlineExpression(ctx, r, collatorDecl, mapFnSources, buildSources)
|
|
|
4152
4510
|
].join("\n");
|
|
4153
4511
|
}
|
|
4154
4512
|
|
|
4513
|
+
// src/compiler/linker.ts
|
|
4514
|
+
function fusedBody(pieces) {
|
|
4515
|
+
const winner = /* @__PURE__ */ new Map();
|
|
4516
|
+
for (const p of pieces) for (const k of p.keys) winner.set(k, p);
|
|
4517
|
+
for (const [k, p] of winner) {
|
|
4518
|
+
for (const d of p.deps.get(k) ?? []) {
|
|
4519
|
+
if (!winner.has(d)) throw new Error(`compose: rule "${k}" references missing rule "${d}"`);
|
|
4520
|
+
}
|
|
4521
|
+
}
|
|
4522
|
+
const contributing = new Set(winner.values());
|
|
4523
|
+
const needsEmptyTl = [...contributing].some((p) => p.needsEmptyTl);
|
|
4524
|
+
const needsCollator = [...contributing].some((p) => p.needsCollator);
|
|
4525
|
+
const lines = [
|
|
4526
|
+
// Shared sentinel protocol (must match NAMED_FN_FAIL / NAMED_FN_END in codegen).
|
|
4527
|
+
"const _pfFail = {}",
|
|
4528
|
+
"let _pfEnd",
|
|
4529
|
+
...needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [],
|
|
4530
|
+
...needsCollator ? ["const _collator = new Intl.Collator(undefined, { sensitivity: 'accent' })"] : [],
|
|
4531
|
+
// Each contributing artifact's namespaced private prelude (regexes, _pf, …).
|
|
4532
|
+
...[...contributing].flatMap((p) => p.prelude),
|
|
4533
|
+
// The winning `_r_<Name>` function for each rule (one per name → no redeclare).
|
|
4534
|
+
...[...winner].map(([k, p]) => p.ruleFns.get(k))
|
|
4535
|
+
];
|
|
4536
|
+
const wrapperEntries = [...winner].map(([k, p]) => `${JSON.stringify(k)}: ${p.wrappers.get(k)}`);
|
|
4537
|
+
const body = [...lines, "return {", wrapperEntries.join(",\n"), "}"].join("\n");
|
|
4538
|
+
const env = {};
|
|
4539
|
+
for (const p of contributing) {
|
|
4540
|
+
if (p.mfFns.length) env[`${p.ns}mf`] = p.mfFns;
|
|
4541
|
+
if (p.buildFns.length) env[`${p.ns}build`] = p.buildFns;
|
|
4542
|
+
}
|
|
4543
|
+
return { body, env };
|
|
4544
|
+
}
|
|
4545
|
+
function emitFusedSource(pieces) {
|
|
4546
|
+
const { body, env } = fusedBody(pieces);
|
|
4547
|
+
if (Object.keys(env).length > 0) {
|
|
4548
|
+
throw new Error("emitFusedSource: artifact carries non-static callbacks (runtime-only); cannot emit static source");
|
|
4549
|
+
}
|
|
4550
|
+
return `/* @__PURE__ */ (() => {
|
|
4551
|
+
${body}
|
|
4552
|
+
})()`;
|
|
4553
|
+
}
|
|
4554
|
+
|
|
4155
4555
|
// src/combinators/scanTo.ts
|
|
4156
4556
|
function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
4157
4557
|
const meta = {
|
|
@@ -4246,6 +4646,12 @@ function escapeClassChar(ch) {
|
|
|
4246
4646
|
return ch.replace(/[\\\]^-]/g, "\\$&");
|
|
4247
4647
|
}
|
|
4248
4648
|
|
|
4649
|
+
// src/cst/offset-model.ts
|
|
4650
|
+
var { isFinite } = Number;
|
|
4651
|
+
|
|
4652
|
+
// src/index.ts
|
|
4653
|
+
registerRegexAnalyzer(firstSetFromRegex);
|
|
4654
|
+
|
|
4249
4655
|
// src/plugin/evaluator.ts
|
|
4250
4656
|
function isWordFactory(v2) {
|
|
4251
4657
|
return !!v2 && typeof v2 === "object" && v2.tag === "wordFactory";
|
|
@@ -4345,16 +4751,18 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
4345
4751
|
}
|
|
4346
4752
|
if (callee.name === "node" && code !== void 0) {
|
|
4347
4753
|
const [typeArg, parserArg, buildArg, optsArg] = node2.arguments;
|
|
4348
|
-
if (!typeArg || !parserArg ||
|
|
4754
|
+
if (!typeArg || !parserArg || typeArg.type === "SpreadElement" || parserArg.type === "SpreadElement") return null;
|
|
4349
4755
|
const typeVal = anyValue(typeArg, scope, code);
|
|
4350
4756
|
if (typeof typeVal !== "string") return null;
|
|
4351
4757
|
const inner = anyValue(parserArg, scope, code, mfs);
|
|
4352
4758
|
if (!isCombinator(inner)) return null;
|
|
4353
|
-
const
|
|
4759
|
+
const be = buildArg;
|
|
4760
|
+
const hasBuild = be !== void 0 && be.type !== "SpreadElement" && !(be.type === "Identifier" && be.name === "undefined");
|
|
4761
|
+
const buildSrc = hasBuild ? code.slice(be.start, be.end) : void 0;
|
|
4354
4762
|
const collapse = optsArg !== void 0 && optsArg.type !== "SpreadElement" ? staticCollapseOption(optsArg) : false;
|
|
4355
4763
|
try {
|
|
4356
|
-
const combi = node(typeVal, inner, () => null, collapse ? { collapse: true } : void 0);
|
|
4357
|
-
if (combi._def.tag === "node") combi._def.buildSrc = buildSrc;
|
|
4764
|
+
const combi = node(typeVal, inner, hasBuild ? () => null : void 0, collapse ? { collapse: true } : void 0);
|
|
4765
|
+
if (combi._def.tag === "node" && buildSrc !== void 0) combi._def.buildSrc = buildSrc;
|
|
4358
4766
|
return combi;
|
|
4359
4767
|
} catch {
|
|
4360
4768
|
return null;
|
|
@@ -4540,91 +4948,24 @@ function evaluateCombinatorArray(node2, scope, code) {
|
|
|
4540
4948
|
if (!val.every(isCombinator)) return null;
|
|
4541
4949
|
return val;
|
|
4542
4950
|
}
|
|
4543
|
-
function asFragmentFactory(expr) {
|
|
4544
|
-
if (expr.type !== "ArrowFunctionExpression" && expr.type !== "FunctionExpression" && expr.type !== "FunctionDeclaration") return null;
|
|
4545
|
-
const fn = expr;
|
|
4546
|
-
return factoryBodyAndReturn(fn) ? fn : null;
|
|
4547
|
-
}
|
|
4548
|
-
var unwrapParen = (e) => e && e.type === "ParenthesizedExpression" ? e.expression : e;
|
|
4549
|
-
function factoryBodyAndReturn(fn) {
|
|
4550
|
-
const body = fn.body;
|
|
4551
|
-
if (!body) return null;
|
|
4552
|
-
const b = unwrapParen(body);
|
|
4553
|
-
if (b.type === "ObjectExpression") return { statements: [], retObj: b };
|
|
4554
|
-
if (b.type === "BlockStatement") {
|
|
4555
|
-
const statements = [];
|
|
4556
|
-
for (const stmt of b.body) {
|
|
4557
|
-
if (stmt.type === "ReturnStatement") {
|
|
4558
|
-
const a = unwrapParen(stmt.argument);
|
|
4559
|
-
if (!a || a.type !== "ObjectExpression") return null;
|
|
4560
|
-
return { statements, retObj: a };
|
|
4561
|
-
}
|
|
4562
|
-
if (stmt.type === "VariableDeclaration") statements.push(stmt);
|
|
4563
|
-
else return null;
|
|
4564
|
-
}
|
|
4565
|
-
}
|
|
4566
|
-
return null;
|
|
4567
|
-
}
|
|
4568
|
-
function spreadFactoryCall(spread, resolve) {
|
|
4569
|
-
const call = spread.argument;
|
|
4570
|
-
if (!call || call.type !== "CallExpression") return null;
|
|
4571
|
-
if (!call.callee || call.callee.type !== "Identifier" || !call.callee.name) return null;
|
|
4572
|
-
const resolved = resolve(call.callee.name);
|
|
4573
|
-
return resolved ? { fn: resolved.fn, args: call.arguments ?? [], code: resolved.code } : null;
|
|
4574
|
-
}
|
|
4575
|
-
function factoryCallScope(fn, args, outer) {
|
|
4576
|
-
const s = new Map(outer);
|
|
4577
|
-
const params = fn.params ?? [];
|
|
4578
|
-
for (let i = 0; i < params.length; i++) {
|
|
4579
|
-
const pn = params[i];
|
|
4580
|
-
if (!pn || pn.type !== "Identifier" || !pn.name) continue;
|
|
4581
|
-
const arg = args[i];
|
|
4582
|
-
if (arg && arg.type === "Identifier" && arg.name && outer.has(arg.name)) {
|
|
4583
|
-
s.set(pn.name, outer.get(arg.name));
|
|
4584
|
-
}
|
|
4585
|
-
}
|
|
4586
|
-
return s;
|
|
4587
|
-
}
|
|
4588
4951
|
function propKey(prop) {
|
|
4589
4952
|
if (prop.type !== "Property" || prop.computed || !prop.key) return null;
|
|
4590
4953
|
if (prop.key.type === "Identifier") return prop.key.name ?? null;
|
|
4591
4954
|
if (prop.key.type === "Literal") return String(prop.key.value);
|
|
4592
4955
|
return null;
|
|
4593
4956
|
}
|
|
4594
|
-
function collectRuleKeys(retObj
|
|
4957
|
+
function collectRuleKeys(retObj) {
|
|
4595
4958
|
const out = [];
|
|
4596
4959
|
for (const prop of retObj.properties) {
|
|
4597
|
-
if (prop.type === "SpreadElement") {
|
|
4598
|
-
const sf = spreadFactoryCall(prop, resolve);
|
|
4599
|
-
if (!sf || seen.has(sf.fn)) return null;
|
|
4600
|
-
const br = factoryBodyAndReturn(sf.fn);
|
|
4601
|
-
if (!br) return null;
|
|
4602
|
-
const nested = collectRuleKeys(br.retObj, resolve, new Set(seen).add(sf.fn));
|
|
4603
|
-
if (!nested) return null;
|
|
4604
|
-
out.push(...nested);
|
|
4605
|
-
continue;
|
|
4606
|
-
}
|
|
4607
4960
|
const key = propKey(prop);
|
|
4608
4961
|
if (!key) return null;
|
|
4609
4962
|
out.push(key);
|
|
4610
4963
|
}
|
|
4611
4964
|
return out;
|
|
4612
4965
|
}
|
|
4613
|
-
function flattenRuleEntries(retObj, scope, code
|
|
4966
|
+
function flattenRuleEntries(retObj, scope, code) {
|
|
4614
4967
|
const out = [];
|
|
4615
4968
|
for (const prop of retObj.properties) {
|
|
4616
|
-
if (prop.type === "SpreadElement") {
|
|
4617
|
-
const sf = spreadFactoryCall(prop, resolve);
|
|
4618
|
-
if (!sf || seen.has(sf.fn)) return null;
|
|
4619
|
-
const br = factoryBodyAndReturn(sf.fn);
|
|
4620
|
-
if (!br) return null;
|
|
4621
|
-
const fragScope = factoryCallScope(sf.fn, sf.args, scope);
|
|
4622
|
-
if (!evalBodyStatements(br.statements, fragScope, sf.code)) return null;
|
|
4623
|
-
const nested = flattenRuleEntries(br.retObj, fragScope, sf.code, resolve, new Set(seen).add(sf.fn));
|
|
4624
|
-
if (!nested) return null;
|
|
4625
|
-
out.push(...nested);
|
|
4626
|
-
continue;
|
|
4627
|
-
}
|
|
4628
4969
|
const key = propKey(prop);
|
|
4629
4970
|
if (!key) return null;
|
|
4630
4971
|
out.push({ key, value: prop.value, scope, code });
|
|
@@ -4650,7 +4991,7 @@ function evalBodyStatements(statements, scope, code) {
|
|
|
4650
4991
|
}
|
|
4651
4992
|
return true;
|
|
4652
4993
|
}
|
|
4653
|
-
function evaluateParserFactory(factoryNode, scope, code, mapFnSources
|
|
4994
|
+
function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
4654
4995
|
if (factoryNode.type !== "ArrowFunctionExpression" && factoryNode.type !== "FunctionDeclaration" && factoryNode.type !== "FunctionExpression") return null;
|
|
4655
4996
|
const factory = factoryNode;
|
|
4656
4997
|
const params = factory.params;
|
|
@@ -4682,16 +5023,36 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources, resolveFa
|
|
|
4682
5023
|
if (!returnExpr) return null;
|
|
4683
5024
|
const retObj = returnExpr.type === "ParenthesizedExpression" ? returnExpr.expression : returnExpr;
|
|
4684
5025
|
if (retObj.type !== "ObjectExpression") return null;
|
|
4685
|
-
const keys = collectRuleKeys(retObj
|
|
5026
|
+
const keys = collectRuleKeys(retObj);
|
|
4686
5027
|
if (!keys) return null;
|
|
4687
5028
|
const ruleRefs = /* @__PURE__ */ new Map();
|
|
5029
|
+
const tagRef = (r, name) => {
|
|
5030
|
+
r._ruleName = name;
|
|
5031
|
+
};
|
|
4688
5032
|
for (const key of keys) {
|
|
4689
|
-
if (!ruleRefs.has(key))
|
|
4690
|
-
|
|
5033
|
+
if (!ruleRefs.has(key)) {
|
|
5034
|
+
const r = ref();
|
|
5035
|
+
tagRef(r, key);
|
|
5036
|
+
ruleRefs.set(key, r);
|
|
5037
|
+
}
|
|
5038
|
+
}
|
|
5039
|
+
const externalRefs = /* @__PURE__ */ new Map();
|
|
5040
|
+
const gProxy = new Proxy(Object.fromEntries(ruleRefs), {
|
|
5041
|
+
get(target, prop) {
|
|
5042
|
+
if (typeof prop !== "string" || prop in target) return target[prop];
|
|
5043
|
+
let ext = externalRefs.get(prop);
|
|
5044
|
+
if (!ext) {
|
|
5045
|
+
ext = ref();
|
|
5046
|
+
tagRef(ext, prop);
|
|
5047
|
+
externalRefs.set(prop, ext);
|
|
5048
|
+
}
|
|
5049
|
+
return ext;
|
|
5050
|
+
}
|
|
5051
|
+
});
|
|
4691
5052
|
const localScope = new Map(scope);
|
|
4692
|
-
localScope.set(proxyName,
|
|
5053
|
+
localScope.set(proxyName, gProxy);
|
|
4693
5054
|
if (!evalBodyStatements(statements, localScope, code)) return null;
|
|
4694
|
-
const entries = flattenRuleEntries(retObj, localScope, code
|
|
5055
|
+
const entries = flattenRuleEntries(retObj, localScope, code);
|
|
4695
5056
|
if (!entries) return null;
|
|
4696
5057
|
const finalByKey = /* @__PURE__ */ new Map();
|
|
4697
5058
|
for (const e of entries) finalByKey.set(e.key, e);
|
|
@@ -4753,19 +5114,14 @@ function referencesAny(node2, names, scope) {
|
|
|
4753
5114
|
}
|
|
4754
5115
|
|
|
4755
5116
|
// src/plugin/index.ts
|
|
5117
|
+
import { createHash } from "node:crypto";
|
|
4756
5118
|
var PARSEMAN_MODULE = "parseman";
|
|
4757
|
-
var
|
|
4758
|
-
function
|
|
4759
|
-
return
|
|
4760
|
-
extensions: [".
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
".js": [".ts", ".tsx", ".js", ".jsx"],
|
|
4764
|
-
".mjs": [".mts", ".mjs"],
|
|
4765
|
-
".cjs": [".cts", ".cjs"]
|
|
4766
|
-
},
|
|
4767
|
-
conditionNames: ["source", "development", "import", "require", "default"],
|
|
4768
|
-
mainFields: ["source", "module", "main"]
|
|
5119
|
+
var _compiledResolver = null;
|
|
5120
|
+
function getCompiledResolver() {
|
|
5121
|
+
return _compiledResolver ??= new ResolverFactory({
|
|
5122
|
+
extensions: [".js", ".mjs", ".cjs"],
|
|
5123
|
+
conditionNames: ["import", "require", "default"],
|
|
5124
|
+
mainFields: ["module", "main"]
|
|
4769
5125
|
});
|
|
4770
5126
|
}
|
|
4771
5127
|
var _moduleParseCache = /* @__PURE__ */ new Map();
|
|
@@ -4812,6 +5168,77 @@ var plugin_default = createUnplugin((opts = {}) => ({
|
|
|
4812
5168
|
return { code: result.code, map: result.map };
|
|
4813
5169
|
}
|
|
4814
5170
|
}));
|
|
5171
|
+
function exportLocalName(body, exported) {
|
|
5172
|
+
for (const st of body) {
|
|
5173
|
+
if (st.type !== "ExportNamedDeclaration") continue;
|
|
5174
|
+
const decl = st.declaration;
|
|
5175
|
+
if (decl?.type === "VariableDeclaration") {
|
|
5176
|
+
for (const d of decl.declarations ?? []) {
|
|
5177
|
+
const idn = d.id;
|
|
5178
|
+
if (idn?.type === "Identifier" && idn.name === exported) return exported;
|
|
5179
|
+
}
|
|
5180
|
+
}
|
|
5181
|
+
for (const sp of st.specifiers ?? []) {
|
|
5182
|
+
const exp = sp.exported?.name;
|
|
5183
|
+
const loc = sp.local?.name;
|
|
5184
|
+
if (exp === exported && loc) return loc;
|
|
5185
|
+
}
|
|
5186
|
+
}
|
|
5187
|
+
return null;
|
|
5188
|
+
}
|
|
5189
|
+
function topLevelInit(body, name) {
|
|
5190
|
+
for (const st of body) {
|
|
5191
|
+
const vd = st.type === "VariableDeclaration" ? st : st.type === "ExportNamedDeclaration" && st.declaration?.type === "VariableDeclaration" ? st.declaration : null;
|
|
5192
|
+
if (!vd) continue;
|
|
5193
|
+
for (const d of vd.declarations ?? []) {
|
|
5194
|
+
const idn = d.id;
|
|
5195
|
+
if (idn?.type === "Identifier" && idn.name === name && d.init) return d.init;
|
|
5196
|
+
}
|
|
5197
|
+
}
|
|
5198
|
+
return null;
|
|
5199
|
+
}
|
|
5200
|
+
function isComposedPiecesSymbol(n) {
|
|
5201
|
+
if (!n || n.type !== "CallExpression") return false;
|
|
5202
|
+
const callee = n.callee;
|
|
5203
|
+
const obj = callee?.object?.name;
|
|
5204
|
+
const prop = callee?.property?.name;
|
|
5205
|
+
const arg0 = n.arguments?.[0];
|
|
5206
|
+
return obj === "Symbol" && prop === "for" && arg0?.value === "parseman.composedPieces";
|
|
5207
|
+
}
|
|
5208
|
+
function findCarriedPiecesLiteral(root) {
|
|
5209
|
+
let found = null;
|
|
5210
|
+
const visit = (n) => {
|
|
5211
|
+
if (found || !n || typeof n !== "object") return;
|
|
5212
|
+
if (Array.isArray(n)) {
|
|
5213
|
+
for (const c of n) visit(c);
|
|
5214
|
+
return;
|
|
5215
|
+
}
|
|
5216
|
+
const node2 = n;
|
|
5217
|
+
if (node2.type === "CallExpression") {
|
|
5218
|
+
const callee = node2.callee;
|
|
5219
|
+
const obj = callee?.object?.name;
|
|
5220
|
+
const prop = callee?.property?.name;
|
|
5221
|
+
const args = node2.arguments;
|
|
5222
|
+
if (obj === "Object" && prop === "defineProperty" && args && isComposedPiecesSymbol(args[1])) {
|
|
5223
|
+
const descriptor = args[2];
|
|
5224
|
+
for (const p of descriptor?.properties ?? []) {
|
|
5225
|
+
const key = p.key;
|
|
5226
|
+
if ((key?.name === "value" || key?.value === "value") && p.value) {
|
|
5227
|
+
found = { start: p.value.start, end: p.value.end };
|
|
5228
|
+
return;
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
}
|
|
5232
|
+
}
|
|
5233
|
+
for (const k in node2) {
|
|
5234
|
+
if (k === "type" || k === "start" || k === "end") continue;
|
|
5235
|
+
const v2 = node2[k];
|
|
5236
|
+
if (v2 && typeof v2 === "object") visit(v2);
|
|
5237
|
+
}
|
|
5238
|
+
};
|
|
5239
|
+
visit(root);
|
|
5240
|
+
return found;
|
|
5241
|
+
}
|
|
4815
5242
|
function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSEMAN_MODULE])) {
|
|
4816
5243
|
let result;
|
|
4817
5244
|
try {
|
|
@@ -4849,63 +5276,6 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
4849
5276
|
}
|
|
4850
5277
|
if (macroImports.length === 0) return null;
|
|
4851
5278
|
const scope = /* @__PURE__ */ new Map();
|
|
4852
|
-
const factories = /* @__PURE__ */ new Map();
|
|
4853
|
-
const resolver = getFragmentResolver();
|
|
4854
|
-
const importedFactoryCache = /* @__PURE__ */ new Map();
|
|
4855
|
-
const OUTPUT_DIR = /([\\/])(dist|lib|build|out|output|compiled|cjs|esm|es)([\\/])/;
|
|
4856
|
-
const resolveSourcePath = (spec) => {
|
|
4857
|
-
let resolved = null;
|
|
4858
|
-
try {
|
|
4859
|
-
resolved = resolver.resolveFileSync(id, spec).path ?? null;
|
|
4860
|
-
} catch {
|
|
4861
|
-
}
|
|
4862
|
-
if (!resolved) return null;
|
|
4863
|
-
if (OUTPUT_DIR.test(resolved)) {
|
|
4864
|
-
const srcCandidate = resolved.replace(OUTPUT_DIR, "$1src$3").replace(/\.(c|m)?js$/, ".ts");
|
|
4865
|
-
try {
|
|
4866
|
-
if (fs.statSync(srcCandidate).isFile()) return srcCandidate;
|
|
4867
|
-
} catch {
|
|
4868
|
-
}
|
|
4869
|
-
}
|
|
4870
|
-
return resolved;
|
|
4871
|
-
};
|
|
4872
|
-
const resolveImportedFactory = (name) => {
|
|
4873
|
-
if (importedFactoryCache.has(name)) return importedFactoryCache.get(name);
|
|
4874
|
-
let result2 = null;
|
|
4875
|
-
const binding = importBindings.get(name);
|
|
4876
|
-
if (binding) {
|
|
4877
|
-
const filePath = resolveSourcePath(binding.source);
|
|
4878
|
-
const mod = filePath ? parseModuleCached(filePath) : null;
|
|
4879
|
-
if (mod) {
|
|
4880
|
-
for (const st of mod.body) {
|
|
4881
|
-
if (st.type !== "ExportNamedDeclaration" || !st.declaration) continue;
|
|
4882
|
-
const decl = st.declaration;
|
|
4883
|
-
if (decl.type === "VariableDeclaration") {
|
|
4884
|
-
for (const d of decl.declarations ?? []) {
|
|
4885
|
-
if (d.id?.type === "Identifier" && d.id.name === binding.imported && d.init) {
|
|
4886
|
-
const fac = asFragmentFactory(d.init);
|
|
4887
|
-
if (fac) {
|
|
4888
|
-
result2 = { fn: fac, code: mod.src };
|
|
4889
|
-
break;
|
|
4890
|
-
}
|
|
4891
|
-
}
|
|
4892
|
-
}
|
|
4893
|
-
} else if (decl.type === "FunctionDeclaration" && decl.id?.type === "Identifier" && decl.id.name === binding.imported) {
|
|
4894
|
-
const fac = asFragmentFactory(decl);
|
|
4895
|
-
if (fac) result2 = { fn: fac, code: mod.src };
|
|
4896
|
-
}
|
|
4897
|
-
if (result2) break;
|
|
4898
|
-
}
|
|
4899
|
-
}
|
|
4900
|
-
}
|
|
4901
|
-
importedFactoryCache.set(name, result2);
|
|
4902
|
-
return result2;
|
|
4903
|
-
};
|
|
4904
|
-
const resolveFactory = (n) => {
|
|
4905
|
-
const local = factories.get(n);
|
|
4906
|
-
if (local) return { fn: local, code };
|
|
4907
|
-
return resolveImportedFactory(n);
|
|
4908
|
-
};
|
|
4909
5279
|
const replacements = [];
|
|
4910
5280
|
const warnings = [];
|
|
4911
5281
|
let anyUnresolved = false;
|
|
@@ -4926,7 +5296,7 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
4926
5296
|
warn(init.start, `${label2}: rules() needs a factory argument`);
|
|
4927
5297
|
return null;
|
|
4928
5298
|
}
|
|
4929
|
-
const ruleMap = evaluateParserFactory(factoryArg, scope, code, []
|
|
5299
|
+
const ruleMap = evaluateParserFactory(factoryArg, scope, code, []);
|
|
4930
5300
|
if (!ruleMap) {
|
|
4931
5301
|
warn(init.start, `${label2}: rules(...) factory isn't statically evaluable`);
|
|
4932
5302
|
return null;
|
|
@@ -4939,6 +5309,89 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
4939
5309
|
return { replacement: compiled.replacement, ruleMap };
|
|
4940
5310
|
};
|
|
4941
5311
|
const isRulesCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "rules";
|
|
5312
|
+
const isComposeCall = (init) => init.type === "CallExpression" && init.callee.type === "Identifier" && init.callee.name === "compose";
|
|
5313
|
+
const localRuleMaps = /* @__PURE__ */ new Map();
|
|
5314
|
+
const nsFor = (label2) => `_${createHash("sha1").update(`${id}#${label2}`).digest("hex").slice(0, 8)}_`;
|
|
5315
|
+
const serializePieces = (p) => {
|
|
5316
|
+
const mapLit = (m) => `new Map([${[...m].map(([k, v2]) => `[${JSON.stringify(k)}, ${JSON.stringify(v2)}]`).join(", ")}])`;
|
|
5317
|
+
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: [] }`;
|
|
5318
|
+
};
|
|
5319
|
+
const serializeList = (list) => `[${list.map(serializePieces).join(", ")}]`;
|
|
5320
|
+
const withCarriedPieces = (grammarExpr, list) => `/* @__PURE__ */ (() => { const _g = ${grammarExpr}; Object.defineProperty(_g, Symbol.for('parseman.composedPieces'), { value: ${serializeList(list)} }); return _g })()`;
|
|
5321
|
+
const localComposedPieces = /* @__PURE__ */ new Map();
|
|
5322
|
+
const importedPiecesCache = /* @__PURE__ */ new Map();
|
|
5323
|
+
const importedPieces = (localName) => {
|
|
5324
|
+
if (importedPiecesCache.has(localName)) return importedPiecesCache.get(localName);
|
|
5325
|
+
let result2 = null;
|
|
5326
|
+
const binding = importBindings.get(localName);
|
|
5327
|
+
if (binding) {
|
|
5328
|
+
let file = null;
|
|
5329
|
+
try {
|
|
5330
|
+
file = getCompiledResolver().resolveFileSync(id, binding.source).path ?? null;
|
|
5331
|
+
} catch {
|
|
5332
|
+
}
|
|
5333
|
+
const mod = file ? parseModuleCached(file) : null;
|
|
5334
|
+
if (mod) {
|
|
5335
|
+
const localFor = exportLocalName(mod.body, binding.imported);
|
|
5336
|
+
const initNode = localFor ? topLevelInit(mod.body, localFor) : null;
|
|
5337
|
+
const literalRange = initNode ? findCarriedPiecesLiteral(initNode) : null;
|
|
5338
|
+
if (literalRange) {
|
|
5339
|
+
const literal2 = mod.src.slice(literalRange.start, literalRange.end);
|
|
5340
|
+
try {
|
|
5341
|
+
result2 = new Function(`return (${literal2})`)();
|
|
5342
|
+
} catch {
|
|
5343
|
+
result2 = null;
|
|
5344
|
+
}
|
|
5345
|
+
}
|
|
5346
|
+
}
|
|
5347
|
+
}
|
|
5348
|
+
importedPiecesCache.set(localName, result2);
|
|
5349
|
+
return result2;
|
|
5350
|
+
};
|
|
5351
|
+
const argPieces = (arg, label2) => {
|
|
5352
|
+
if (isRulesCall(arg)) {
|
|
5353
|
+
const factory = arg.arguments[0];
|
|
5354
|
+
const rm = factory ? evaluateParserFactory(factory, scope, code, []) : null;
|
|
5355
|
+
const p = rm ? compileLinkable([...rm], nsFor(label2)) : null;
|
|
5356
|
+
return p ? [p] : null;
|
|
5357
|
+
}
|
|
5358
|
+
if (arg.type === "Identifier") {
|
|
5359
|
+
const name = arg.name;
|
|
5360
|
+
const rm = localRuleMaps.get(name);
|
|
5361
|
+
if (rm) {
|
|
5362
|
+
const p = compileLinkable([...rm], nsFor(label2));
|
|
5363
|
+
return p ? [p] : null;
|
|
5364
|
+
}
|
|
5365
|
+
const composed = localComposedPieces.get(name);
|
|
5366
|
+
if (composed) return composed;
|
|
5367
|
+
return importedPieces(name);
|
|
5368
|
+
}
|
|
5369
|
+
return null;
|
|
5370
|
+
};
|
|
5371
|
+
const compileComposeCall = (init) => {
|
|
5372
|
+
const args = init.arguments;
|
|
5373
|
+
const arr = args[0];
|
|
5374
|
+
if (!arr || arr.type !== "ArrayExpression") {
|
|
5375
|
+
warn(init.start, "compose(): expected a static array of grammars/artifacts");
|
|
5376
|
+
return null;
|
|
5377
|
+
}
|
|
5378
|
+
const elements = arr.elements;
|
|
5379
|
+
const pieces = [];
|
|
5380
|
+
for (let i = 0; i < elements.length; i++) {
|
|
5381
|
+
const list = argPieces(elements[i], `compose${init.start}_${i}`);
|
|
5382
|
+
if (!list) {
|
|
5383
|
+
warn(init.start, `compose(): argument ${i} isn't a build-resolvable grammar; falling back to runtime`);
|
|
5384
|
+
return null;
|
|
5385
|
+
}
|
|
5386
|
+
pieces.push(...list);
|
|
5387
|
+
}
|
|
5388
|
+
try {
|
|
5389
|
+
return { replacement: emitFusedSource(pieces), pieces };
|
|
5390
|
+
} catch (e) {
|
|
5391
|
+
warn(init.start, `compose(): ${e.message}; falling back to runtime`);
|
|
5392
|
+
return null;
|
|
5393
|
+
}
|
|
5394
|
+
};
|
|
4942
5395
|
const unwrapVd = (stmt) => stmt.type === "VariableDeclaration" ? stmt : stmt.type === "ExportNamedDeclaration" && stmt.declaration?.type === "VariableDeclaration" ? stmt.declaration : null;
|
|
4943
5396
|
const refNames = /* @__PURE__ */ new Set();
|
|
4944
5397
|
for (const stmt of body) {
|
|
@@ -5017,16 +5470,23 @@ function transformMacro(code, id, moduleAliases = /* @__PURE__ */ new Set([PARSE
|
|
|
5017
5470
|
if (isRulesCall(init)) {
|
|
5018
5471
|
const compiledRules = compileRulesFactory(init, varName);
|
|
5019
5472
|
if (!compiledRules) continue;
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5473
|
+
localRuleMaps.set(varName, compiledRules.ruleMap);
|
|
5474
|
+
let replacement = compiledRules.replacement;
|
|
5475
|
+
if (exportPrefix) {
|
|
5476
|
+
const pieces = compileLinkable([...compiledRules.ruleMap], nsFor(varName));
|
|
5477
|
+
if (pieces && !pieces.mfFns.length && !pieces.buildFns.length) {
|
|
5478
|
+
replacement = withCarriedPieces(replacement, [pieces]);
|
|
5479
|
+
}
|
|
5480
|
+
}
|
|
5481
|
+
replacements.push({ start: init.start, end: init.end, replacement });
|
|
5025
5482
|
continue;
|
|
5026
5483
|
}
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5484
|
+
if (isComposeCall(init)) {
|
|
5485
|
+
const fused = compileComposeCall(init);
|
|
5486
|
+
if (!fused) continue;
|
|
5487
|
+
localComposedPieces.set(varName, fused.pieces);
|
|
5488
|
+
const replacement = exportPrefix ? withCarriedPieces(fused.replacement, fused.pieces) : fused.replacement;
|
|
5489
|
+
replacements.push({ start: init.start, end: init.end, replacement });
|
|
5030
5490
|
continue;
|
|
5031
5491
|
}
|
|
5032
5492
|
const mapFnSources = [];
|