parseman 0.16.0 → 0.18.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/README.md +1 -1
- package/dist/combinators/expect.d.ts +2 -2
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.d.ts +14 -0
- package/dist/combinators/first-set.d.ts.map +1 -1
- package/dist/combinators/token.d.ts +10 -0
- package/dist/combinators/token.d.ts.map +1 -0
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts +28 -0
- package/dist/compiler/ir-serialize.d.ts.map +1 -0
- package/dist/compiler/linker.d.ts +9 -0
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/compiler/value-usage.d.ts.map +1 -1
- package/dist/index.cjs +517 -126
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +517 -126
- package/dist/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +838 -121
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +838 -121
- package/dist/plugin/index.js.map +4 -4
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -85,7 +85,7 @@ __export(index_exports, {
|
|
|
85
85
|
sequence: () => sequence,
|
|
86
86
|
shiftAbsolute: () => shiftAbsolute,
|
|
87
87
|
skip: () => skip,
|
|
88
|
-
|
|
88
|
+
token: () => token,
|
|
89
89
|
transform: () => transform,
|
|
90
90
|
trivia: () => trivia,
|
|
91
91
|
triviaEntries: () => triviaEntries,
|
|
@@ -155,6 +155,7 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
155
155
|
case "transform":
|
|
156
156
|
case "label":
|
|
157
157
|
case "trivia":
|
|
158
|
+
case "token":
|
|
158
159
|
case "expect":
|
|
159
160
|
case "withCtx":
|
|
160
161
|
case "node":
|
|
@@ -181,6 +182,55 @@ function sequenceFirstSet(parsers) {
|
|
|
181
182
|
}
|
|
182
183
|
return fs;
|
|
183
184
|
}
|
|
185
|
+
function firstSetOf(p, seen = /* @__PURE__ */ new Set()) {
|
|
186
|
+
if (seen.has(p)) return any();
|
|
187
|
+
seen.add(p);
|
|
188
|
+
const fs = (c) => firstSetOf(c, seen);
|
|
189
|
+
const d = p._def;
|
|
190
|
+
switch (d.tag) {
|
|
191
|
+
case "literal":
|
|
192
|
+
case "regex":
|
|
193
|
+
case "keywords":
|
|
194
|
+
return p._meta.firstSet;
|
|
195
|
+
// terminals: no refs, cached set is exact
|
|
196
|
+
case "lazy":
|
|
197
|
+
try {
|
|
198
|
+
return fs(d.thunk());
|
|
199
|
+
} catch {
|
|
200
|
+
return any();
|
|
201
|
+
}
|
|
202
|
+
case "choice": {
|
|
203
|
+
let out = empty();
|
|
204
|
+
for (const arm of d.parsers) out = union(out, fs(arm));
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
case "sequence": {
|
|
208
|
+
let out = empty();
|
|
209
|
+
for (const term of d.parsers) {
|
|
210
|
+
out = union(out, fs(term));
|
|
211
|
+
if (!matchesEmpty(term)) return out;
|
|
212
|
+
}
|
|
213
|
+
return out;
|
|
214
|
+
}
|
|
215
|
+
case "oneOrMore":
|
|
216
|
+
case "many":
|
|
217
|
+
case "optional":
|
|
218
|
+
case "transform":
|
|
219
|
+
case "label":
|
|
220
|
+
case "trivia":
|
|
221
|
+
case "token":
|
|
222
|
+
case "node":
|
|
223
|
+
case "grammar":
|
|
224
|
+
case "expect":
|
|
225
|
+
return fs(d.parser);
|
|
226
|
+
case "sepBy":
|
|
227
|
+
return fs(d.parser);
|
|
228
|
+
case "skip":
|
|
229
|
+
return fs(d.main);
|
|
230
|
+
default:
|
|
231
|
+
return p._meta.firstSet;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
184
234
|
function mergeRanges(ranges) {
|
|
185
235
|
if (ranges.length === 0) return [];
|
|
186
236
|
const sorted = [...ranges].sort((a, b) => a.lo - b.lo);
|
|
@@ -1295,6 +1345,7 @@ function markUnusedValues(root) {
|
|
|
1295
1345
|
return;
|
|
1296
1346
|
case "label":
|
|
1297
1347
|
case "trivia":
|
|
1348
|
+
case "token":
|
|
1298
1349
|
case "withCtx":
|
|
1299
1350
|
case "expect":
|
|
1300
1351
|
visit(def.parser, consumed);
|
|
@@ -1595,8 +1646,60 @@ function parse(combinator, input, opts = {}) {
|
|
|
1595
1646
|
return withErrors;
|
|
1596
1647
|
}
|
|
1597
1648
|
|
|
1649
|
+
// src/combinators/token.ts
|
|
1650
|
+
function token(root) {
|
|
1651
|
+
const meta = {
|
|
1652
|
+
firstSet: root._meta.firstSet,
|
|
1653
|
+
canMatchNewline: root._meta.canMatchNewline,
|
|
1654
|
+
isTrivia: false
|
|
1655
|
+
};
|
|
1656
|
+
return {
|
|
1657
|
+
_tag: "token",
|
|
1658
|
+
_meta: meta,
|
|
1659
|
+
_def: { tag: "token", parser: root },
|
|
1660
|
+
parse(input, pos, ctx) {
|
|
1661
|
+
const savedTrivia = ctx.trivia;
|
|
1662
|
+
const savedKinds = ctx.triviaKindLabels;
|
|
1663
|
+
const savedBuf = ctx._cstBuf;
|
|
1664
|
+
const savedChildren = ctx._cstChildren;
|
|
1665
|
+
const savedLeaves = ctx._cstLeaves;
|
|
1666
|
+
const savedRaw = ctx._cstRawChildren;
|
|
1667
|
+
const savedTriviaLog = ctx._cstTriviaLog;
|
|
1668
|
+
const savedOuterTriviaLog = ctx._triviaLog;
|
|
1669
|
+
const wasCapturing = cstCaptureActive(ctx);
|
|
1670
|
+
ctx.trivia = void 0;
|
|
1671
|
+
ctx.triviaKindLabels = void 0;
|
|
1672
|
+
ctx._cstBuf = void 0;
|
|
1673
|
+
ctx._cstChildren = void 0;
|
|
1674
|
+
ctx._cstLeaves = void 0;
|
|
1675
|
+
ctx._cstRawChildren = void 0;
|
|
1676
|
+
ctx._cstTriviaLog = void 0;
|
|
1677
|
+
delete ctx._triviaLog;
|
|
1678
|
+
let result;
|
|
1679
|
+
try {
|
|
1680
|
+
result = root.parse(input, pos, ctx);
|
|
1681
|
+
} finally {
|
|
1682
|
+
ctx.trivia = savedTrivia;
|
|
1683
|
+
ctx.triviaKindLabels = savedKinds;
|
|
1684
|
+
ctx._cstBuf = savedBuf;
|
|
1685
|
+
ctx._cstChildren = savedChildren;
|
|
1686
|
+
ctx._cstLeaves = savedLeaves;
|
|
1687
|
+
ctx._cstRawChildren = savedRaw;
|
|
1688
|
+
ctx._cstTriviaLog = savedTriviaLog;
|
|
1689
|
+
if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
|
|
1690
|
+
else ctx._triviaLog = savedOuterTriviaLog;
|
|
1691
|
+
}
|
|
1692
|
+
if (!result.ok) return result;
|
|
1693
|
+
const span = result.span;
|
|
1694
|
+
const value = input.slice(pos, span.end);
|
|
1695
|
+
if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
|
|
1696
|
+
return { ok: true, value, span };
|
|
1697
|
+
}
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1598
1701
|
// src/combinators/expect.ts
|
|
1599
|
-
function
|
|
1702
|
+
function deriveExpected(c) {
|
|
1600
1703
|
const def = c._def;
|
|
1601
1704
|
switch (def.tag) {
|
|
1602
1705
|
case "literal":
|
|
@@ -1608,22 +1711,23 @@ function staticExpected(c) {
|
|
|
1608
1711
|
case "label":
|
|
1609
1712
|
return [def.label];
|
|
1610
1713
|
case "choice":
|
|
1611
|
-
return def.parsers.flatMap(
|
|
1714
|
+
return def.parsers.flatMap(deriveExpected);
|
|
1612
1715
|
case "sequence":
|
|
1613
|
-
return def.parsers.length > 0 ?
|
|
1716
|
+
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
1614
1717
|
case "node":
|
|
1615
1718
|
case "grammar":
|
|
1616
1719
|
case "trivia":
|
|
1720
|
+
case "token":
|
|
1617
1721
|
case "optional":
|
|
1618
1722
|
case "many":
|
|
1619
1723
|
case "oneOrMore":
|
|
1620
1724
|
case "transform":
|
|
1621
1725
|
case "not":
|
|
1622
|
-
return
|
|
1726
|
+
return deriveExpected(def.parser);
|
|
1623
1727
|
case "lazy": {
|
|
1624
1728
|
const name = c._ruleName;
|
|
1625
1729
|
try {
|
|
1626
|
-
return
|
|
1730
|
+
return deriveExpected(def.thunk());
|
|
1627
1731
|
} catch {
|
|
1628
1732
|
return name ? [name] : [];
|
|
1629
1733
|
}
|
|
@@ -1633,7 +1737,7 @@ function staticExpected(c) {
|
|
|
1633
1737
|
}
|
|
1634
1738
|
}
|
|
1635
1739
|
function expect(combinator, label2) {
|
|
1636
|
-
const expected = label2 !== void 0 ? [label2] :
|
|
1740
|
+
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
1637
1741
|
const meta = {
|
|
1638
1742
|
firstSet: combinator._meta.firstSet,
|
|
1639
1743
|
canMatchNewline: combinator._meta.canMatchNewline,
|
|
@@ -3121,16 +3225,12 @@ function namedFnPrelude() {
|
|
|
3121
3225
|
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
3122
3226
|
ctx.namedFnDecls.push([
|
|
3123
3227
|
`function ${fnName}(input, _pos, _ctx) {`,
|
|
3124
|
-
` let _pfok = false, _pfv, _pfe = _pos`,
|
|
3125
3228
|
` _pfail: {`,
|
|
3126
3229
|
...reindentStmts(bodyStmts, 2),
|
|
3127
|
-
`
|
|
3128
|
-
`
|
|
3129
|
-
` _pfok = true`,
|
|
3230
|
+
` ${NAMED_FN_END} = ${endVar}`,
|
|
3231
|
+
` return ${valueVar}`,
|
|
3130
3232
|
` }`,
|
|
3131
|
-
`
|
|
3132
|
-
` ${NAMED_FN_END} = _pfe`,
|
|
3133
|
-
` return _pfv`,
|
|
3233
|
+
` return ${NAMED_FN_FAIL}`,
|
|
3134
3234
|
`}`
|
|
3135
3235
|
].join("\n"));
|
|
3136
3236
|
}
|
|
@@ -3289,6 +3389,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
3289
3389
|
case "guard":
|
|
3290
3390
|
case "not":
|
|
3291
3391
|
case "trivia":
|
|
3392
|
+
case "token":
|
|
3292
3393
|
case "scanTo":
|
|
3293
3394
|
case "unknown":
|
|
3294
3395
|
return false;
|
|
@@ -3350,6 +3451,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
3350
3451
|
case "regex":
|
|
3351
3452
|
case "keywords":
|
|
3352
3453
|
case "node":
|
|
3454
|
+
case "token":
|
|
3353
3455
|
return true;
|
|
3354
3456
|
case "not":
|
|
3355
3457
|
case "guard":
|
|
@@ -3628,9 +3730,9 @@ function emitSeq(def, ctx, pos) {
|
|
|
3628
3730
|
stmts.push(`${ind(ctx)}const ${arrV} = [${valueVars.join(", ")}]`);
|
|
3629
3731
|
return { stmts, valueVar: arrV, endVar };
|
|
3630
3732
|
}
|
|
3631
|
-
function
|
|
3733
|
+
function deriveExpectedArr(parsers) {
|
|
3632
3734
|
return JSON.stringify(parsers.flatMap((p) => {
|
|
3633
|
-
const e =
|
|
3735
|
+
const e = deriveExpected(p);
|
|
3634
3736
|
return e.length > 0 ? e : [p._tag];
|
|
3635
3737
|
}));
|
|
3636
3738
|
}
|
|
@@ -3651,7 +3753,7 @@ function failsAtStart(p) {
|
|
|
3651
3753
|
}
|
|
3652
3754
|
}
|
|
3653
3755
|
function armStaticExpected(ctx, p) {
|
|
3654
|
-
return hoistExpected(ctx,
|
|
3756
|
+
return hoistExpected(ctx, deriveExpectedArr([p]));
|
|
3655
3757
|
}
|
|
3656
3758
|
function canMatchEmptyAtStart(p) {
|
|
3657
3759
|
const d = p._def;
|
|
@@ -3689,7 +3791,7 @@ function emitDisjointArm(p, ctx, pos, valV, endV) {
|
|
|
3689
3791
|
];
|
|
3690
3792
|
}
|
|
3691
3793
|
function emitChoice(def, ctx, pos) {
|
|
3692
|
-
const allExpected =
|
|
3794
|
+
const allExpected = deriveExpectedArr(def.parsers);
|
|
3693
3795
|
if (def.disjoint) {
|
|
3694
3796
|
const codeV = v(ctx, "_code");
|
|
3695
3797
|
const valV = v(ctx, "_chv");
|
|
@@ -3750,7 +3852,7 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
3750
3852
|
const wordV = v(ctx, "_gw");
|
|
3751
3853
|
const endV = v(ctx, "_ge");
|
|
3752
3854
|
const valV = v(ctx, "_gcv");
|
|
3753
|
-
const regexExpected = JSON.stringify(
|
|
3855
|
+
const regexExpected = JSON.stringify(deriveExpected(superParser));
|
|
3754
3856
|
const stmts = [
|
|
3755
3857
|
`${ind(ctx)}${reVar}.lastIndex = ${pos}`,
|
|
3756
3858
|
`${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
|
|
@@ -3831,11 +3933,16 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
3831
3933
|
const atStart = failsAtStart(p);
|
|
3832
3934
|
const staticFx = armStaticExpected(ctx, p);
|
|
3833
3935
|
const deferRuleName = ctx.deferFirstSetRefs ? p._ruleName : void 0;
|
|
3834
|
-
const fsGuard = deferRuleName !== void 0 ? `/*@FS:${deferRuleName}:${codeV}@*/true` : needsFirstSetGuard(p) ? firstSetCond(codeV, p._meta.firstSet) :
|
|
3936
|
+
const fsGuard = deferRuleName !== void 0 ? `/*@FS:${deferRuleName}:${codeV}@*/true` : needsFirstSetGuard(p) ? firstSetCond(codeV, p._meta.firstSet) : (() => {
|
|
3937
|
+
if (p._meta.firstSet.kind !== "any" || matchesEmpty(p)) return null;
|
|
3938
|
+
const deep = firstSetOf(p);
|
|
3939
|
+
return deep.kind === "ranges" ? firstSetCond(codeV, deep) : null;
|
|
3940
|
+
})();
|
|
3835
3941
|
let gateCond = null;
|
|
3836
3942
|
if (gate) {
|
|
3837
3943
|
const gateIdx = ctx.mapFns.length;
|
|
3838
3944
|
ctx.mapFns.push(gate);
|
|
3945
|
+
ctx.mapFnSrcs.push(null);
|
|
3839
3946
|
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
3840
3947
|
}
|
|
3841
3948
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
@@ -3894,13 +4001,21 @@ function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
|
|
|
3894
4001
|
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
|
|
3895
4002
|
return emitFirstMatch(def, ctx, pos);
|
|
3896
4003
|
}
|
|
4004
|
+
function pushMapFn(ctx, fn, src) {
|
|
4005
|
+
if (src !== null && ctx.mapFns.length === ctx.mapFnSrcs.length) {
|
|
4006
|
+
const hit = ctx.mapFnSrcs.indexOf(src);
|
|
4007
|
+
if (hit !== -1) return hit;
|
|
4008
|
+
}
|
|
4009
|
+
const idx = ctx.mapFns.length;
|
|
4010
|
+
ctx.mapFns.push(fn);
|
|
4011
|
+
ctx.mapFnSrcs.push(src);
|
|
4012
|
+
return idx;
|
|
4013
|
+
}
|
|
3897
4014
|
function emitTransformChain(p, baseValue, endV, startPos, ctx) {
|
|
3898
4015
|
const def = p._def;
|
|
3899
4016
|
if (def.tag === "transform") {
|
|
3900
4017
|
const innerR = emitTransformChain(def.parser, baseValue, endV, startPos, ctx);
|
|
3901
|
-
const fnIdx = ctx.
|
|
3902
|
-
ctx.mapFns.push(def.fn);
|
|
3903
|
-
ctx.mapFnSrcs.push(def.fnSrc ?? null);
|
|
4018
|
+
const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
|
|
3904
4019
|
const vv = v(ctx);
|
|
3905
4020
|
return {
|
|
3906
4021
|
stmts: [...innerR.stmts, `${ind(ctx)}const ${vv} = ${mfRef(ctx)}[${fnIdx}](${innerR.valueVar}, { start: ${startPos}, end: ${endV} })`],
|
|
@@ -4083,7 +4198,7 @@ function emitScanTo(def, ctx, pos) {
|
|
|
4083
4198
|
`${ind(ctx)}while (${curV} < input.length) {`
|
|
4084
4199
|
];
|
|
4085
4200
|
ctx.indent++;
|
|
4086
|
-
const probeCtx = { ...ctx, capturing: false };
|
|
4201
|
+
const probeCtx = { ...ctx, capturing: false, noHoist: true };
|
|
4087
4202
|
const { stmts: sentStmts, okVar: sentOk } = emitFallible(def.sentinel, probeCtx, curV);
|
|
4088
4203
|
stmts.push(...sentStmts, `${ind(ctx)}if (${sentOk}) { ${foundV} = true; break }`);
|
|
4089
4204
|
if (def.skip.length > 0) {
|
|
@@ -4129,6 +4244,116 @@ function emitNot(def, ctx, pos) {
|
|
|
4129
4244
|
endVar: pos
|
|
4130
4245
|
};
|
|
4131
4246
|
}
|
|
4247
|
+
function escapeTokenLiteral(value) {
|
|
4248
|
+
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
4249
|
+
}
|
|
4250
|
+
function regexMatchesEmpty(source, flags) {
|
|
4251
|
+
try {
|
|
4252
|
+
return new RegExp(`^(?:${source})$`, flags).test("");
|
|
4253
|
+
} catch {
|
|
4254
|
+
return true;
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
function tokenTerminalSource(p) {
|
|
4258
|
+
const def = p._def;
|
|
4259
|
+
switch (def.tag) {
|
|
4260
|
+
case "literal":
|
|
4261
|
+
if (def.value.length === 0) return null;
|
|
4262
|
+
return {
|
|
4263
|
+
source: escapeTokenLiteral(def.value),
|
|
4264
|
+
caseInsensitive: def.caseInsensitive,
|
|
4265
|
+
rawCaseSensitive: def.caseInsensitive ? "" : def.value
|
|
4266
|
+
};
|
|
4267
|
+
case "regex": {
|
|
4268
|
+
if (def.flags.replace(/i/g, "") !== "") return null;
|
|
4269
|
+
if (regexMatchesEmpty(def.source, def.flags)) return null;
|
|
4270
|
+
return {
|
|
4271
|
+
source: `(?:${def.source})`,
|
|
4272
|
+
caseInsensitive: def.flags.includes("i"),
|
|
4273
|
+
rawCaseSensitive: def.flags.includes("i") ? "" : def.source
|
|
4274
|
+
};
|
|
4275
|
+
}
|
|
4276
|
+
default:
|
|
4277
|
+
return null;
|
|
4278
|
+
}
|
|
4279
|
+
}
|
|
4280
|
+
function tokenSequenceSource(p) {
|
|
4281
|
+
const def = p._def;
|
|
4282
|
+
const parts = def.tag === "sequence" ? def.parsers.map(tokenTerminalSource) : [tokenTerminalSource(p)];
|
|
4283
|
+
if (parts.some((part) => part === null)) return null;
|
|
4284
|
+
const typed = parts;
|
|
4285
|
+
const flags = typed.some((part) => part.caseInsensitive) ? "i" : "";
|
|
4286
|
+
if (flags.includes("i") && typed.some((part) => /[A-Za-z]/.test(part.rawCaseSensitive))) return null;
|
|
4287
|
+
return {
|
|
4288
|
+
source: typed.map((part) => part.source).join(""),
|
|
4289
|
+
flags,
|
|
4290
|
+
hasCaseSensitiveLetters: typed.some((part) => /[A-Za-z]/.test(part.rawCaseSensitive))
|
|
4291
|
+
};
|
|
4292
|
+
}
|
|
4293
|
+
function combineTokenRegexSources(parts) {
|
|
4294
|
+
const flags = parts.some((part) => part.flags.includes("i")) ? "i" : "";
|
|
4295
|
+
if (flags.includes("i") && parts.some((part) => part.flags === "" && part.hasCaseSensitiveLetters)) return null;
|
|
4296
|
+
return { source: parts.map((part) => part.source).join(""), flags };
|
|
4297
|
+
}
|
|
4298
|
+
function tokenNullableRegex(def) {
|
|
4299
|
+
const inner = def.parser._def;
|
|
4300
|
+
if (inner.tag === "many") {
|
|
4301
|
+
const seq = tokenSequenceSource(inner.parser);
|
|
4302
|
+
if (!seq) return null;
|
|
4303
|
+
return { tag: "regex", source: `(?:${seq.source})*`, flags: seq.flags };
|
|
4304
|
+
}
|
|
4305
|
+
if (inner.tag === "optional") {
|
|
4306
|
+
const seq = tokenSequenceSource(inner.parser);
|
|
4307
|
+
if (!seq) return null;
|
|
4308
|
+
return { tag: "regex", source: `(?:${seq.source})?`, flags: seq.flags };
|
|
4309
|
+
}
|
|
4310
|
+
if (inner.tag === "sepBy") {
|
|
4311
|
+
const item = tokenSequenceSource(inner.parser);
|
|
4312
|
+
const sep = tokenSequenceSource(inner.separator);
|
|
4313
|
+
if (!item || !sep) return null;
|
|
4314
|
+
const combined = combineTokenRegexSources([item, sep]);
|
|
4315
|
+
if (!combined) return null;
|
|
4316
|
+
return { tag: "regex", source: `(?:${item.source}(?:${sep.source}${item.source})*)?`, flags: combined.flags };
|
|
4317
|
+
}
|
|
4318
|
+
return null;
|
|
4319
|
+
}
|
|
4320
|
+
function emitToken(def, ctx, pos) {
|
|
4321
|
+
const lowered = tokenNullableRegex(def);
|
|
4322
|
+
if (lowered) return emitRegex(lowered, ctx, pos);
|
|
4323
|
+
const savedTrivia = ctx.activeTrivia;
|
|
4324
|
+
const savedKindLabels = ctx.triviaKindLabels;
|
|
4325
|
+
ctx.activeTrivia = void 0;
|
|
4326
|
+
ctx.triviaKindLabels = void 0;
|
|
4327
|
+
const inner = emitFallible(def.parser, ctx, pos);
|
|
4328
|
+
ctx.activeTrivia = savedTrivia;
|
|
4329
|
+
ctx.triviaKindLabels = savedKindLabels;
|
|
4330
|
+
const i = ind(ctx);
|
|
4331
|
+
const sc = v(ctx, "_tokCh");
|
|
4332
|
+
const sl = v(ctx, "_tokLv");
|
|
4333
|
+
const sr = v(ctx, "_tokRaw");
|
|
4334
|
+
const sv = v(ctx, "_tokTr");
|
|
4335
|
+
const sk = v(ctx, "_tokKinds");
|
|
4336
|
+
const stl = v(ctx, "_tokTl");
|
|
4337
|
+
const sol = v(ctx, "_tokLog");
|
|
4338
|
+
const sb = v(ctx, "_tokBuf");
|
|
4339
|
+
const valV = v(ctx, "_tok");
|
|
4340
|
+
return {
|
|
4341
|
+
stmts: [
|
|
4342
|
+
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${sv} = _ctx.trivia, ${sk} = _ctx.triviaKindLabels, ${stl} = _ctx._cstTriviaLog, ${sol} = _ctx._triviaLog, ${sb} = _ctx._cstBuf`,
|
|
4343
|
+
`${i}_ctx.trivia = undefined; _ctx.triviaKindLabels = undefined; _ctx._cstChildren = undefined; _ctx._cstLeaves = undefined; _ctx._cstRawChildren = undefined; _ctx._cstTriviaLog = undefined; _ctx._triviaLog = undefined; _ctx._cstBuf = undefined`,
|
|
4344
|
+
`${i}try {`,
|
|
4345
|
+
...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
|
|
4346
|
+
`${i}} finally {`,
|
|
4347
|
+
`${i} _ctx.trivia = ${sv}; _ctx.triviaKindLabels = ${sk}; _ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx._cstTriviaLog = ${stl}; _ctx._triviaLog = ${sol}; _ctx._cstBuf = ${sb}`,
|
|
4348
|
+
`${i}}`,
|
|
4349
|
+
...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
|
|
4350
|
+
`${i}const ${valV} = input.slice(${pos}, ${inner.endVar})`,
|
|
4351
|
+
...emitLeafCapture(ctx, valV, pos, inner.endVar)
|
|
4352
|
+
],
|
|
4353
|
+
valueVar: valV,
|
|
4354
|
+
endVar: inner.endVar
|
|
4355
|
+
};
|
|
4356
|
+
}
|
|
4132
4357
|
function emitNode(def, ctx, pos) {
|
|
4133
4358
|
const structural = def.build === void 0;
|
|
4134
4359
|
const mkType = structural ? null : analyzeMkInlineBuild(def);
|
|
@@ -4248,7 +4473,7 @@ function emitRecover(def, ctx, pos) {
|
|
|
4248
4473
|
`${ind0} if (${sentOk}) break`,
|
|
4249
4474
|
`${ind0} ${scanV}++`,
|
|
4250
4475
|
`${ind0} }`,
|
|
4251
|
-
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: ${JSON.stringify(
|
|
4476
|
+
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: ${JSON.stringify(deriveExpected(def.parser))} }`,
|
|
4252
4477
|
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
4253
4478
|
`${ind0} ${valVar} = ${errV}`,
|
|
4254
4479
|
`${ind0} ${endVar} = ${scanV}`,
|
|
@@ -4274,6 +4499,32 @@ function emitExpect(def, ctx, pos) {
|
|
|
4274
4499
|
return { stmts, valueVar: valVar, endVar };
|
|
4275
4500
|
}
|
|
4276
4501
|
function emit(p, ctx, pos) {
|
|
4502
|
+
const usage = ctx.lazyUsage;
|
|
4503
|
+
if (usage && !ctx.noHoist && !ctx.capAsTrivia && !ctx.ruleNames?.has(p) && isHoistableTag(p._def.tag) && (usage.counts.get(p) ?? 0) > 1 && // Only hoist subtrees big enough that de-duplicating them beats the call
|
|
4504
|
+
// overhead. A tiny shared wrapper (e.g. `optional(literal(';'))`) inlines
|
|
4505
|
+
// faster than it calls and barely moves the byte count; the size explosion
|
|
4506
|
+
// is all in LARGE choices/sequences referenced from many positions.
|
|
4507
|
+
(usage.sizes.get(p) ?? 0) >= HOIST_MIN_SUBTREE) {
|
|
4508
|
+
const existing = ctx.namedParsers.get(p);
|
|
4509
|
+
if (existing !== void 0) return emitNamedFnCall(ctx, existing, pos);
|
|
4510
|
+
const fnName = `${nsp(ctx)}_pf${ctx.namedParsers.size}`;
|
|
4511
|
+
ctx.namedParsers.set(p, fnName);
|
|
4512
|
+
const savedIndent = ctx.indent;
|
|
4513
|
+
const savedFailLabel = ctx.failLabel;
|
|
4514
|
+
const savedRecord = ctx.recordFail;
|
|
4515
|
+
ctx.indent = 1;
|
|
4516
|
+
ctx.failLabel = "_pfail";
|
|
4517
|
+
ctx.recordFail = true;
|
|
4518
|
+
const r = emitDispatch(p, ctx, "_pos");
|
|
4519
|
+
ctx.indent = savedIndent;
|
|
4520
|
+
ctx.failLabel = savedFailLabel;
|
|
4521
|
+
ctx.recordFail = savedRecord;
|
|
4522
|
+
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
4523
|
+
return emitNamedFnCall(ctx, fnName, pos);
|
|
4524
|
+
}
|
|
4525
|
+
return emitDispatch(p, ctx, pos);
|
|
4526
|
+
}
|
|
4527
|
+
function emitDispatch(p, ctx, pos) {
|
|
4277
4528
|
const def = p._def;
|
|
4278
4529
|
switch (def.tag) {
|
|
4279
4530
|
case "literal":
|
|
@@ -4319,9 +4570,7 @@ function emit(p, ctx, pos) {
|
|
|
4319
4570
|
};
|
|
4320
4571
|
}
|
|
4321
4572
|
}
|
|
4322
|
-
const fnIdx = ctx.
|
|
4323
|
-
ctx.mapFns.push(def.fn);
|
|
4324
|
-
ctx.mapFnSrcs.push(def.fnSrc ?? null);
|
|
4573
|
+
const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
|
|
4325
4574
|
const mv = v(ctx, "_mapped");
|
|
4326
4575
|
return {
|
|
4327
4576
|
stmts: [
|
|
@@ -4354,6 +4603,8 @@ function emit(p, ctx, pos) {
|
|
|
4354
4603
|
return emitLazy(p, def, ctx, pos);
|
|
4355
4604
|
case "trivia":
|
|
4356
4605
|
return emit(def.parser, ctx, pos);
|
|
4606
|
+
case "token":
|
|
4607
|
+
return emitToken(def, ctx, pos);
|
|
4357
4608
|
case "label":
|
|
4358
4609
|
return emit(def.parser, ctx, pos);
|
|
4359
4610
|
case "grammar": {
|
|
@@ -4386,6 +4637,7 @@ function emit(p, ctx, pos) {
|
|
|
4386
4637
|
case "guard": {
|
|
4387
4638
|
const fnIdx = ctx.mapFns.length;
|
|
4388
4639
|
ctx.mapFns.push(def.predicate);
|
|
4640
|
+
ctx.mapFnSrcs.push(null);
|
|
4389
4641
|
const vv = v(ctx);
|
|
4390
4642
|
return {
|
|
4391
4643
|
stmts: [
|
|
@@ -4400,6 +4652,7 @@ function emit(p, ctx, pos) {
|
|
|
4400
4652
|
const evIdx = ctx.mapFns.length;
|
|
4401
4653
|
const extra = def.extra;
|
|
4402
4654
|
ctx.mapFns.push((() => extra));
|
|
4655
|
+
ctx.mapFnSrcs.push(null);
|
|
4403
4656
|
const innerParser = def.parser;
|
|
4404
4657
|
if (!ctx.namedParsers.has(innerParser)) {
|
|
4405
4658
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
@@ -4453,6 +4706,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4453
4706
|
}
|
|
4454
4707
|
case "grammar":
|
|
4455
4708
|
case "trivia":
|
|
4709
|
+
case "token":
|
|
4456
4710
|
case "label":
|
|
4457
4711
|
case "optional":
|
|
4458
4712
|
case "many":
|
|
@@ -4488,6 +4742,7 @@ function childrenOf(def) {
|
|
|
4488
4742
|
case "optional":
|
|
4489
4743
|
case "transform":
|
|
4490
4744
|
case "trivia":
|
|
4745
|
+
case "token":
|
|
4491
4746
|
case "label":
|
|
4492
4747
|
case "grammar":
|
|
4493
4748
|
case "not":
|
|
@@ -4519,9 +4774,58 @@ function childrenOf(def) {
|
|
|
4519
4774
|
return [];
|
|
4520
4775
|
}
|
|
4521
4776
|
}
|
|
4777
|
+
var HOISTABLE_TAGS = /* @__PURE__ */ new Set([
|
|
4778
|
+
"sequence",
|
|
4779
|
+
"choice",
|
|
4780
|
+
"many",
|
|
4781
|
+
"oneOrMore",
|
|
4782
|
+
"optional",
|
|
4783
|
+
"sepBy",
|
|
4784
|
+
"transform",
|
|
4785
|
+
"node",
|
|
4786
|
+
"not"
|
|
4787
|
+
]);
|
|
4788
|
+
function isHoistableTag(tag) {
|
|
4789
|
+
return HOISTABLE_TAGS.has(tag);
|
|
4790
|
+
}
|
|
4791
|
+
var HOIST_MIN_SUBTREE = 3;
|
|
4522
4792
|
function analyzeLazyUsage(root) {
|
|
4523
4793
|
return analyzeLazyUsageMulti([root]);
|
|
4524
4794
|
}
|
|
4795
|
+
function subtreeSizes(roots) {
|
|
4796
|
+
const sizes = /* @__PURE__ */ new Map();
|
|
4797
|
+
const sz = (p) => {
|
|
4798
|
+
const cached = sizes.get(p);
|
|
4799
|
+
if (cached !== void 0) return cached;
|
|
4800
|
+
const def = p._def;
|
|
4801
|
+
let s = 1;
|
|
4802
|
+
if (def.tag !== "lazy") {
|
|
4803
|
+
for (const child of childrenOf(def)) s += child._def.tag === "lazy" ? 1 : sz(child);
|
|
4804
|
+
}
|
|
4805
|
+
sizes.set(p, s);
|
|
4806
|
+
return s;
|
|
4807
|
+
};
|
|
4808
|
+
const visitedLazy = /* @__PURE__ */ new Set();
|
|
4809
|
+
const visit = (p) => {
|
|
4810
|
+
const def = p._def;
|
|
4811
|
+
if (def.tag === "lazy") {
|
|
4812
|
+
if (visitedLazy.has(p)) return;
|
|
4813
|
+
visitedLazy.add(p);
|
|
4814
|
+
let resolved;
|
|
4815
|
+
try {
|
|
4816
|
+
resolved = def.thunk();
|
|
4817
|
+
} catch {
|
|
4818
|
+
return;
|
|
4819
|
+
}
|
|
4820
|
+
visit(resolved);
|
|
4821
|
+
return;
|
|
4822
|
+
}
|
|
4823
|
+
sz(p);
|
|
4824
|
+
for (const child of childrenOf(def)) visit(child);
|
|
4825
|
+
};
|
|
4826
|
+
for (const root of roots) visit(root);
|
|
4827
|
+
return sizes;
|
|
4828
|
+
}
|
|
4525
4829
|
function analyzeLazyUsageMulti(roots) {
|
|
4526
4830
|
const counts = /* @__PURE__ */ new Map();
|
|
4527
4831
|
const recursive = /* @__PURE__ */ new Set();
|
|
@@ -4548,10 +4852,14 @@ function analyzeLazyUsageMulti(roots) {
|
|
|
4548
4852
|
active.delete(p);
|
|
4549
4853
|
return;
|
|
4550
4854
|
}
|
|
4855
|
+
if (isHoistableTag(def.tag)) {
|
|
4856
|
+
counts.set(p, (counts.get(p) ?? 0) + 1);
|
|
4857
|
+
}
|
|
4551
4858
|
for (const child of childrenOf(def)) walk2(child);
|
|
4552
4859
|
}
|
|
4553
|
-
|
|
4554
|
-
|
|
4860
|
+
const rootsArr = [...roots];
|
|
4861
|
+
for (const root of rootsArr) walk2(root);
|
|
4862
|
+
return { counts, recursive, sizes: subtreeSizes(rootsArr) };
|
|
4555
4863
|
}
|
|
4556
4864
|
function ruleDependencies(ruleMap) {
|
|
4557
4865
|
const nameOf = /* @__PURE__ */ new Map();
|
|
@@ -4877,6 +5185,174 @@ function buildInlineExpression(ctx, r, mapFnSources, buildSources) {
|
|
|
4877
5185
|
].join("\n");
|
|
4878
5186
|
}
|
|
4879
5187
|
|
|
5188
|
+
// src/combinators/scanTo.ts
|
|
5189
|
+
function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
5190
|
+
const meta = {
|
|
5191
|
+
firstSet: any(),
|
|
5192
|
+
canMatchNewline: true,
|
|
5193
|
+
isTrivia: false
|
|
5194
|
+
};
|
|
5195
|
+
return {
|
|
5196
|
+
_tag: "scanTo",
|
|
5197
|
+
_meta: meta,
|
|
5198
|
+
_def: { tag: "scanTo", sentinel, skip: skip2, orEOF },
|
|
5199
|
+
parse(input, pos, ctx) {
|
|
5200
|
+
let cur = pos;
|
|
5201
|
+
const probeCtx = {
|
|
5202
|
+
trackLines: ctx.trackLines,
|
|
5203
|
+
state: ctx.state,
|
|
5204
|
+
...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
|
|
5205
|
+
};
|
|
5206
|
+
const emit2 = (end) => {
|
|
5207
|
+
if (end > pos && cstCaptureActive(ctx)) {
|
|
5208
|
+
const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
5209
|
+
pushCstLeaf(ctx, leaf);
|
|
5210
|
+
}
|
|
5211
|
+
};
|
|
5212
|
+
while (cur < input.length) {
|
|
5213
|
+
const s = sentinel.parse(input, cur, probeCtx);
|
|
5214
|
+
if (s.ok) {
|
|
5215
|
+
emit2(cur);
|
|
5216
|
+
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
5217
|
+
}
|
|
5218
|
+
let advanced = false;
|
|
5219
|
+
for (const skipper of skip2) {
|
|
5220
|
+
const r = skipper.parse(input, cur, probeCtx);
|
|
5221
|
+
if (r.ok && r.span.end > cur) {
|
|
5222
|
+
cur = r.span.end;
|
|
5223
|
+
advanced = true;
|
|
5224
|
+
break;
|
|
5225
|
+
}
|
|
5226
|
+
}
|
|
5227
|
+
if (!advanced) cur++;
|
|
5228
|
+
}
|
|
5229
|
+
if (orEOF) {
|
|
5230
|
+
emit2(cur);
|
|
5231
|
+
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
5232
|
+
}
|
|
5233
|
+
const sentDef = sentinel._def;
|
|
5234
|
+
const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
|
|
5235
|
+
return { ok: false, expected, span: { start: pos, end: cur } };
|
|
5236
|
+
}
|
|
5237
|
+
};
|
|
5238
|
+
}
|
|
5239
|
+
function balanced(open, close, options = {}) {
|
|
5240
|
+
const self = ref();
|
|
5241
|
+
const skips = options.skip ?? [];
|
|
5242
|
+
const stop = /* @__PURE__ */ new Set([open, close]);
|
|
5243
|
+
let bounded = true;
|
|
5244
|
+
for (const sk of skips) {
|
|
5245
|
+
const cs = firstSetClassChars(sk);
|
|
5246
|
+
if (cs === null) {
|
|
5247
|
+
bounded = false;
|
|
5248
|
+
break;
|
|
5249
|
+
}
|
|
5250
|
+
for (const ch of cs) stop.add(ch);
|
|
5251
|
+
}
|
|
5252
|
+
const cls = [...stop].map(escapeClassChar).join("");
|
|
5253
|
+
const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
|
|
5254
|
+
const inner = many(choice(self, ...skips, content));
|
|
5255
|
+
const combi = transform(
|
|
5256
|
+
sequence(literal(open), inner, expect(literal(close))),
|
|
5257
|
+
// parts: strings (content/self) or arrays (a sequence-shaped skip) or a
|
|
5258
|
+
// ParseError (recovered close). `c` is the close string or a ParseError.
|
|
5259
|
+
([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
|
|
5260
|
+
);
|
|
5261
|
+
if (combi._def.tag === "transform") {
|
|
5262
|
+
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
5263
|
+
}
|
|
5264
|
+
self.define(combi);
|
|
5265
|
+
return combi;
|
|
5266
|
+
}
|
|
5267
|
+
function firstSetClassChars(c) {
|
|
5268
|
+
const fs = c._meta.firstSet;
|
|
5269
|
+
if (fs.kind === "empty") return [];
|
|
5270
|
+
if (fs.kind !== "ranges") return null;
|
|
5271
|
+
const out = [];
|
|
5272
|
+
for (const { lo, hi } of fs.ranges) {
|
|
5273
|
+
if (hi - lo > 8) return null;
|
|
5274
|
+
for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
|
|
5275
|
+
}
|
|
5276
|
+
return out;
|
|
5277
|
+
}
|
|
5278
|
+
function escapeClassChar(ch) {
|
|
5279
|
+
return ch.replace(/[\\\]^-]/g, "\\$&");
|
|
5280
|
+
}
|
|
5281
|
+
|
|
5282
|
+
// src/compiler/ir-serialize.ts
|
|
5283
|
+
function evalRuleMapIR(ir) {
|
|
5284
|
+
const _tf = (child, src) => {
|
|
5285
|
+
let fn2;
|
|
5286
|
+
try {
|
|
5287
|
+
fn2 = (0, eval)(`(${src})`);
|
|
5288
|
+
} catch {
|
|
5289
|
+
fn2 = () => {
|
|
5290
|
+
throw new Error("IR transform fn not materialized");
|
|
5291
|
+
};
|
|
5292
|
+
}
|
|
5293
|
+
const t = transform(child, fn2);
|
|
5294
|
+
t._def.fnSrc = src;
|
|
5295
|
+
return t;
|
|
5296
|
+
};
|
|
5297
|
+
const _nd = (type, child, src, opts) => {
|
|
5298
|
+
const n = node(type, child, void 0, opts);
|
|
5299
|
+
n._def.buildSrc = src;
|
|
5300
|
+
return n;
|
|
5301
|
+
};
|
|
5302
|
+
const fn = new Function(
|
|
5303
|
+
"rules",
|
|
5304
|
+
"ref",
|
|
5305
|
+
"regex",
|
|
5306
|
+
"literal",
|
|
5307
|
+
"keywords",
|
|
5308
|
+
"sequence",
|
|
5309
|
+
"choice",
|
|
5310
|
+
"many",
|
|
5311
|
+
"oneOrMore",
|
|
5312
|
+
"optional",
|
|
5313
|
+
"sepBy",
|
|
5314
|
+
"not",
|
|
5315
|
+
"node",
|
|
5316
|
+
"parser",
|
|
5317
|
+
"scanTo",
|
|
5318
|
+
"token",
|
|
5319
|
+
"transform",
|
|
5320
|
+
"skip",
|
|
5321
|
+
"trivia",
|
|
5322
|
+
"label",
|
|
5323
|
+
"expect",
|
|
5324
|
+
"_tf",
|
|
5325
|
+
"_nd",
|
|
5326
|
+
`return (${ir})`
|
|
5327
|
+
);
|
|
5328
|
+
const map = fn(
|
|
5329
|
+
rules,
|
|
5330
|
+
ref,
|
|
5331
|
+
regex,
|
|
5332
|
+
literal,
|
|
5333
|
+
keywords,
|
|
5334
|
+
sequence,
|
|
5335
|
+
choice,
|
|
5336
|
+
many,
|
|
5337
|
+
oneOrMore,
|
|
5338
|
+
optional,
|
|
5339
|
+
sepBy,
|
|
5340
|
+
not,
|
|
5341
|
+
node,
|
|
5342
|
+
parser,
|
|
5343
|
+
scanTo,
|
|
5344
|
+
token,
|
|
5345
|
+
transform,
|
|
5346
|
+
skip,
|
|
5347
|
+
trivia,
|
|
5348
|
+
label,
|
|
5349
|
+
expect,
|
|
5350
|
+
_tf,
|
|
5351
|
+
_nd
|
|
5352
|
+
);
|
|
5353
|
+
return Object.entries(map);
|
|
5354
|
+
}
|
|
5355
|
+
|
|
4880
5356
|
// src/compiler/linker.ts
|
|
4881
5357
|
var _nsCounter = 0;
|
|
4882
5358
|
function linkable(rulesMap, ns) {
|
|
@@ -4961,9 +5437,18 @@ function fuseRules(pieces) {
|
|
|
4961
5437
|
return new Function("_env", body)(env);
|
|
4962
5438
|
}
|
|
4963
5439
|
var COMPOSED_PIECES = /* @__PURE__ */ Symbol.for("parseman.composedPieces");
|
|
5440
|
+
function isIRPiece(p) {
|
|
5441
|
+
return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
|
|
5442
|
+
}
|
|
5443
|
+
function materializePiece(p) {
|
|
5444
|
+
if (!isIRPiece(p)) return p;
|
|
5445
|
+
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns);
|
|
5446
|
+
if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
|
|
5447
|
+
return pieces;
|
|
5448
|
+
}
|
|
4964
5449
|
function itemPieces(item) {
|
|
4965
5450
|
const carried = item[COMPOSED_PIECES];
|
|
4966
|
-
if (Array.isArray(carried)) return carried;
|
|
5451
|
+
if (Array.isArray(carried)) return carried.map(materializePiece);
|
|
4967
5452
|
if (item.ruleFns instanceof Map) return [item];
|
|
4968
5453
|
return [linkable(item)];
|
|
4969
5454
|
}
|
|
@@ -5017,7 +5502,7 @@ function recover(combinator, sentinel) {
|
|
|
5017
5502
|
canMatchNewline: true,
|
|
5018
5503
|
isTrivia: false
|
|
5019
5504
|
};
|
|
5020
|
-
const expected =
|
|
5505
|
+
const expected = deriveExpected(combinator);
|
|
5021
5506
|
return {
|
|
5022
5507
|
_tag: "recover",
|
|
5023
5508
|
_meta: meta,
|
|
@@ -5059,100 +5544,6 @@ function deeperFail(a, b) {
|
|
|
5059
5544
|
return a.span.start >= b.span.start ? a : b;
|
|
5060
5545
|
}
|
|
5061
5546
|
|
|
5062
|
-
// src/combinators/scanTo.ts
|
|
5063
|
-
function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
5064
|
-
const meta = {
|
|
5065
|
-
firstSet: any(),
|
|
5066
|
-
canMatchNewline: true,
|
|
5067
|
-
isTrivia: false
|
|
5068
|
-
};
|
|
5069
|
-
return {
|
|
5070
|
-
_tag: "scanTo",
|
|
5071
|
-
_meta: meta,
|
|
5072
|
-
_def: { tag: "scanTo", sentinel, skip: skip2, orEOF },
|
|
5073
|
-
parse(input, pos, ctx) {
|
|
5074
|
-
let cur = pos;
|
|
5075
|
-
const probeCtx = {
|
|
5076
|
-
trackLines: ctx.trackLines,
|
|
5077
|
-
state: ctx.state,
|
|
5078
|
-
...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
|
|
5079
|
-
};
|
|
5080
|
-
const emit2 = (end) => {
|
|
5081
|
-
if (end > pos && cstCaptureActive(ctx)) {
|
|
5082
|
-
const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
5083
|
-
pushCstLeaf(ctx, leaf);
|
|
5084
|
-
}
|
|
5085
|
-
};
|
|
5086
|
-
while (cur < input.length) {
|
|
5087
|
-
const s = sentinel.parse(input, cur, probeCtx);
|
|
5088
|
-
if (s.ok) {
|
|
5089
|
-
emit2(cur);
|
|
5090
|
-
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
5091
|
-
}
|
|
5092
|
-
let advanced = false;
|
|
5093
|
-
for (const skipper of skip2) {
|
|
5094
|
-
const r = skipper.parse(input, cur, probeCtx);
|
|
5095
|
-
if (r.ok && r.span.end > cur) {
|
|
5096
|
-
cur = r.span.end;
|
|
5097
|
-
advanced = true;
|
|
5098
|
-
break;
|
|
5099
|
-
}
|
|
5100
|
-
}
|
|
5101
|
-
if (!advanced) cur++;
|
|
5102
|
-
}
|
|
5103
|
-
if (orEOF) {
|
|
5104
|
-
emit2(cur);
|
|
5105
|
-
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
5106
|
-
}
|
|
5107
|
-
const sentDef = sentinel._def;
|
|
5108
|
-
const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
|
|
5109
|
-
return { ok: false, expected, span: { start: pos, end: cur } };
|
|
5110
|
-
}
|
|
5111
|
-
};
|
|
5112
|
-
}
|
|
5113
|
-
function balanced(open, close, options = {}) {
|
|
5114
|
-
const self = ref();
|
|
5115
|
-
const skips = options.skip ?? [];
|
|
5116
|
-
const stop = /* @__PURE__ */ new Set([open, close]);
|
|
5117
|
-
let bounded = true;
|
|
5118
|
-
for (const sk of skips) {
|
|
5119
|
-
const cs = firstSetClassChars(sk);
|
|
5120
|
-
if (cs === null) {
|
|
5121
|
-
bounded = false;
|
|
5122
|
-
break;
|
|
5123
|
-
}
|
|
5124
|
-
for (const ch of cs) stop.add(ch);
|
|
5125
|
-
}
|
|
5126
|
-
const cls = [...stop].map(escapeClassChar).join("");
|
|
5127
|
-
const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
|
|
5128
|
-
const inner = many(choice(self, ...skips, content));
|
|
5129
|
-
const combi = transform(
|
|
5130
|
-
sequence(literal(open), inner, expect(literal(close), close)),
|
|
5131
|
-
// parts: strings (content/self) or arrays (a sequence-shaped skip) or a
|
|
5132
|
-
// ParseError (recovered close). `c` is the close string or a ParseError.
|
|
5133
|
-
([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
|
|
5134
|
-
);
|
|
5135
|
-
if (combi._def.tag === "transform") {
|
|
5136
|
-
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
5137
|
-
}
|
|
5138
|
-
self.define(combi);
|
|
5139
|
-
return combi;
|
|
5140
|
-
}
|
|
5141
|
-
function firstSetClassChars(c) {
|
|
5142
|
-
const fs = c._meta.firstSet;
|
|
5143
|
-
if (fs.kind === "empty") return [];
|
|
5144
|
-
if (fs.kind !== "ranges") return null;
|
|
5145
|
-
const out = [];
|
|
5146
|
-
for (const { lo, hi } of fs.ranges) {
|
|
5147
|
-
if (hi - lo > 8) return null;
|
|
5148
|
-
for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
|
|
5149
|
-
}
|
|
5150
|
-
return out;
|
|
5151
|
-
}
|
|
5152
|
-
function escapeClassChar(ch) {
|
|
5153
|
-
return ch.replace(/[\\\]^-]/g, "\\$&");
|
|
5154
|
-
}
|
|
5155
|
-
|
|
5156
5547
|
// src/combinators/recover-list.ts
|
|
5157
5548
|
function tolerantElement(item, sentinel, until) {
|
|
5158
5549
|
const el = transform(
|