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.js
CHANGED
|
@@ -58,6 +58,7 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
58
58
|
case "transform":
|
|
59
59
|
case "label":
|
|
60
60
|
case "trivia":
|
|
61
|
+
case "token":
|
|
61
62
|
case "expect":
|
|
62
63
|
case "withCtx":
|
|
63
64
|
case "node":
|
|
@@ -84,6 +85,55 @@ function sequenceFirstSet(parsers) {
|
|
|
84
85
|
}
|
|
85
86
|
return fs;
|
|
86
87
|
}
|
|
88
|
+
function firstSetOf(p, seen = /* @__PURE__ */ new Set()) {
|
|
89
|
+
if (seen.has(p)) return any();
|
|
90
|
+
seen.add(p);
|
|
91
|
+
const fs = (c) => firstSetOf(c, seen);
|
|
92
|
+
const d = p._def;
|
|
93
|
+
switch (d.tag) {
|
|
94
|
+
case "literal":
|
|
95
|
+
case "regex":
|
|
96
|
+
case "keywords":
|
|
97
|
+
return p._meta.firstSet;
|
|
98
|
+
// terminals: no refs, cached set is exact
|
|
99
|
+
case "lazy":
|
|
100
|
+
try {
|
|
101
|
+
return fs(d.thunk());
|
|
102
|
+
} catch {
|
|
103
|
+
return any();
|
|
104
|
+
}
|
|
105
|
+
case "choice": {
|
|
106
|
+
let out = empty();
|
|
107
|
+
for (const arm of d.parsers) out = union(out, fs(arm));
|
|
108
|
+
return out;
|
|
109
|
+
}
|
|
110
|
+
case "sequence": {
|
|
111
|
+
let out = empty();
|
|
112
|
+
for (const term of d.parsers) {
|
|
113
|
+
out = union(out, fs(term));
|
|
114
|
+
if (!matchesEmpty(term)) return out;
|
|
115
|
+
}
|
|
116
|
+
return out;
|
|
117
|
+
}
|
|
118
|
+
case "oneOrMore":
|
|
119
|
+
case "many":
|
|
120
|
+
case "optional":
|
|
121
|
+
case "transform":
|
|
122
|
+
case "label":
|
|
123
|
+
case "trivia":
|
|
124
|
+
case "token":
|
|
125
|
+
case "node":
|
|
126
|
+
case "grammar":
|
|
127
|
+
case "expect":
|
|
128
|
+
return fs(d.parser);
|
|
129
|
+
case "sepBy":
|
|
130
|
+
return fs(d.parser);
|
|
131
|
+
case "skip":
|
|
132
|
+
return fs(d.main);
|
|
133
|
+
default:
|
|
134
|
+
return p._meta.firstSet;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
87
137
|
function mergeRanges(ranges) {
|
|
88
138
|
if (ranges.length === 0) return [];
|
|
89
139
|
const sorted = [...ranges].sort((a, b) => a.lo - b.lo);
|
|
@@ -1198,6 +1248,7 @@ function markUnusedValues(root) {
|
|
|
1198
1248
|
return;
|
|
1199
1249
|
case "label":
|
|
1200
1250
|
case "trivia":
|
|
1251
|
+
case "token":
|
|
1201
1252
|
case "withCtx":
|
|
1202
1253
|
case "expect":
|
|
1203
1254
|
visit(def.parser, consumed);
|
|
@@ -1498,8 +1549,60 @@ function parse(combinator, input, opts = {}) {
|
|
|
1498
1549
|
return withErrors;
|
|
1499
1550
|
}
|
|
1500
1551
|
|
|
1552
|
+
// src/combinators/token.ts
|
|
1553
|
+
function token(root) {
|
|
1554
|
+
const meta = {
|
|
1555
|
+
firstSet: root._meta.firstSet,
|
|
1556
|
+
canMatchNewline: root._meta.canMatchNewline,
|
|
1557
|
+
isTrivia: false
|
|
1558
|
+
};
|
|
1559
|
+
return {
|
|
1560
|
+
_tag: "token",
|
|
1561
|
+
_meta: meta,
|
|
1562
|
+
_def: { tag: "token", parser: root },
|
|
1563
|
+
parse(input, pos, ctx) {
|
|
1564
|
+
const savedTrivia = ctx.trivia;
|
|
1565
|
+
const savedKinds = ctx.triviaKindLabels;
|
|
1566
|
+
const savedBuf = ctx._cstBuf;
|
|
1567
|
+
const savedChildren = ctx._cstChildren;
|
|
1568
|
+
const savedLeaves = ctx._cstLeaves;
|
|
1569
|
+
const savedRaw = ctx._cstRawChildren;
|
|
1570
|
+
const savedTriviaLog = ctx._cstTriviaLog;
|
|
1571
|
+
const savedOuterTriviaLog = ctx._triviaLog;
|
|
1572
|
+
const wasCapturing = cstCaptureActive(ctx);
|
|
1573
|
+
ctx.trivia = void 0;
|
|
1574
|
+
ctx.triviaKindLabels = void 0;
|
|
1575
|
+
ctx._cstBuf = void 0;
|
|
1576
|
+
ctx._cstChildren = void 0;
|
|
1577
|
+
ctx._cstLeaves = void 0;
|
|
1578
|
+
ctx._cstRawChildren = void 0;
|
|
1579
|
+
ctx._cstTriviaLog = void 0;
|
|
1580
|
+
delete ctx._triviaLog;
|
|
1581
|
+
let result;
|
|
1582
|
+
try {
|
|
1583
|
+
result = root.parse(input, pos, ctx);
|
|
1584
|
+
} finally {
|
|
1585
|
+
ctx.trivia = savedTrivia;
|
|
1586
|
+
ctx.triviaKindLabels = savedKinds;
|
|
1587
|
+
ctx._cstBuf = savedBuf;
|
|
1588
|
+
ctx._cstChildren = savedChildren;
|
|
1589
|
+
ctx._cstLeaves = savedLeaves;
|
|
1590
|
+
ctx._cstRawChildren = savedRaw;
|
|
1591
|
+
ctx._cstTriviaLog = savedTriviaLog;
|
|
1592
|
+
if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
|
|
1593
|
+
else ctx._triviaLog = savedOuterTriviaLog;
|
|
1594
|
+
}
|
|
1595
|
+
if (!result.ok) return result;
|
|
1596
|
+
const span = result.span;
|
|
1597
|
+
const value = input.slice(pos, span.end);
|
|
1598
|
+
if (wasCapturing) pushCstLeaf(ctx, { _tag: "leaf", value, span });
|
|
1599
|
+
return { ok: true, value, span };
|
|
1600
|
+
}
|
|
1601
|
+
};
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1501
1604
|
// src/combinators/expect.ts
|
|
1502
|
-
function
|
|
1605
|
+
function deriveExpected(c) {
|
|
1503
1606
|
const def = c._def;
|
|
1504
1607
|
switch (def.tag) {
|
|
1505
1608
|
case "literal":
|
|
@@ -1511,22 +1614,23 @@ function staticExpected(c) {
|
|
|
1511
1614
|
case "label":
|
|
1512
1615
|
return [def.label];
|
|
1513
1616
|
case "choice":
|
|
1514
|
-
return def.parsers.flatMap(
|
|
1617
|
+
return def.parsers.flatMap(deriveExpected);
|
|
1515
1618
|
case "sequence":
|
|
1516
|
-
return def.parsers.length > 0 ?
|
|
1619
|
+
return def.parsers.length > 0 ? deriveExpected(def.parsers[0]) : [];
|
|
1517
1620
|
case "node":
|
|
1518
1621
|
case "grammar":
|
|
1519
1622
|
case "trivia":
|
|
1623
|
+
case "token":
|
|
1520
1624
|
case "optional":
|
|
1521
1625
|
case "many":
|
|
1522
1626
|
case "oneOrMore":
|
|
1523
1627
|
case "transform":
|
|
1524
1628
|
case "not":
|
|
1525
|
-
return
|
|
1629
|
+
return deriveExpected(def.parser);
|
|
1526
1630
|
case "lazy": {
|
|
1527
1631
|
const name = c._ruleName;
|
|
1528
1632
|
try {
|
|
1529
|
-
return
|
|
1633
|
+
return deriveExpected(def.thunk());
|
|
1530
1634
|
} catch {
|
|
1531
1635
|
return name ? [name] : [];
|
|
1532
1636
|
}
|
|
@@ -1536,7 +1640,7 @@ function staticExpected(c) {
|
|
|
1536
1640
|
}
|
|
1537
1641
|
}
|
|
1538
1642
|
function expect(combinator, label2) {
|
|
1539
|
-
const expected = label2 !== void 0 ? [label2] :
|
|
1643
|
+
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
1540
1644
|
const meta = {
|
|
1541
1645
|
firstSet: combinator._meta.firstSet,
|
|
1542
1646
|
canMatchNewline: combinator._meta.canMatchNewline,
|
|
@@ -3024,16 +3128,12 @@ function namedFnPrelude() {
|
|
|
3024
3128
|
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
3025
3129
|
ctx.namedFnDecls.push([
|
|
3026
3130
|
`function ${fnName}(input, _pos, _ctx) {`,
|
|
3027
|
-
` let _pfok = false, _pfv, _pfe = _pos`,
|
|
3028
3131
|
` _pfail: {`,
|
|
3029
3132
|
...reindentStmts(bodyStmts, 2),
|
|
3030
|
-
`
|
|
3031
|
-
`
|
|
3032
|
-
` _pfok = true`,
|
|
3133
|
+
` ${NAMED_FN_END} = ${endVar}`,
|
|
3134
|
+
` return ${valueVar}`,
|
|
3033
3135
|
` }`,
|
|
3034
|
-
`
|
|
3035
|
-
` ${NAMED_FN_END} = _pfe`,
|
|
3036
|
-
` return _pfv`,
|
|
3136
|
+
` return ${NAMED_FN_FAIL}`,
|
|
3037
3137
|
`}`
|
|
3038
3138
|
].join("\n"));
|
|
3039
3139
|
}
|
|
@@ -3192,6 +3292,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
3192
3292
|
case "guard":
|
|
3193
3293
|
case "not":
|
|
3194
3294
|
case "trivia":
|
|
3295
|
+
case "token":
|
|
3195
3296
|
case "scanTo":
|
|
3196
3297
|
case "unknown":
|
|
3197
3298
|
return false;
|
|
@@ -3253,6 +3354,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
3253
3354
|
case "regex":
|
|
3254
3355
|
case "keywords":
|
|
3255
3356
|
case "node":
|
|
3357
|
+
case "token":
|
|
3256
3358
|
return true;
|
|
3257
3359
|
case "not":
|
|
3258
3360
|
case "guard":
|
|
@@ -3531,9 +3633,9 @@ function emitSeq(def, ctx, pos) {
|
|
|
3531
3633
|
stmts.push(`${ind(ctx)}const ${arrV} = [${valueVars.join(", ")}]`);
|
|
3532
3634
|
return { stmts, valueVar: arrV, endVar };
|
|
3533
3635
|
}
|
|
3534
|
-
function
|
|
3636
|
+
function deriveExpectedArr(parsers) {
|
|
3535
3637
|
return JSON.stringify(parsers.flatMap((p) => {
|
|
3536
|
-
const e =
|
|
3638
|
+
const e = deriveExpected(p);
|
|
3537
3639
|
return e.length > 0 ? e : [p._tag];
|
|
3538
3640
|
}));
|
|
3539
3641
|
}
|
|
@@ -3554,7 +3656,7 @@ function failsAtStart(p) {
|
|
|
3554
3656
|
}
|
|
3555
3657
|
}
|
|
3556
3658
|
function armStaticExpected(ctx, p) {
|
|
3557
|
-
return hoistExpected(ctx,
|
|
3659
|
+
return hoistExpected(ctx, deriveExpectedArr([p]));
|
|
3558
3660
|
}
|
|
3559
3661
|
function canMatchEmptyAtStart(p) {
|
|
3560
3662
|
const d = p._def;
|
|
@@ -3592,7 +3694,7 @@ function emitDisjointArm(p, ctx, pos, valV, endV) {
|
|
|
3592
3694
|
];
|
|
3593
3695
|
}
|
|
3594
3696
|
function emitChoice(def, ctx, pos) {
|
|
3595
|
-
const allExpected =
|
|
3697
|
+
const allExpected = deriveExpectedArr(def.parsers);
|
|
3596
3698
|
if (def.disjoint) {
|
|
3597
3699
|
const codeV = v(ctx, "_code");
|
|
3598
3700
|
const valV = v(ctx, "_chv");
|
|
@@ -3653,7 +3755,7 @@ function emitGreedyClassify(def, superIndex, ctx, pos) {
|
|
|
3653
3755
|
const wordV = v(ctx, "_gw");
|
|
3654
3756
|
const endV = v(ctx, "_ge");
|
|
3655
3757
|
const valV = v(ctx, "_gcv");
|
|
3656
|
-
const regexExpected = JSON.stringify(
|
|
3758
|
+
const regexExpected = JSON.stringify(deriveExpected(superParser));
|
|
3657
3759
|
const stmts = [
|
|
3658
3760
|
`${ind(ctx)}${reVar}.lastIndex = ${pos}`,
|
|
3659
3761
|
`${ind(ctx)}const ${matchV} = ${reVar}.exec(input)`,
|
|
@@ -3734,11 +3836,16 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
3734
3836
|
const atStart = failsAtStart(p);
|
|
3735
3837
|
const staticFx = armStaticExpected(ctx, p);
|
|
3736
3838
|
const deferRuleName = ctx.deferFirstSetRefs ? p._ruleName : void 0;
|
|
3737
|
-
const fsGuard = deferRuleName !== void 0 ? `/*@FS:${deferRuleName}:${codeV}@*/true` : needsFirstSetGuard(p) ? firstSetCond(codeV, p._meta.firstSet) :
|
|
3839
|
+
const fsGuard = deferRuleName !== void 0 ? `/*@FS:${deferRuleName}:${codeV}@*/true` : needsFirstSetGuard(p) ? firstSetCond(codeV, p._meta.firstSet) : (() => {
|
|
3840
|
+
if (p._meta.firstSet.kind !== "any" || matchesEmpty(p)) return null;
|
|
3841
|
+
const deep = firstSetOf(p);
|
|
3842
|
+
return deep.kind === "ranges" ? firstSetCond(codeV, deep) : null;
|
|
3843
|
+
})();
|
|
3738
3844
|
let gateCond = null;
|
|
3739
3845
|
if (gate) {
|
|
3740
3846
|
const gateIdx = ctx.mapFns.length;
|
|
3741
3847
|
ctx.mapFns.push(gate);
|
|
3848
|
+
ctx.mapFnSrcs.push(null);
|
|
3742
3849
|
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
3743
3850
|
}
|
|
3744
3851
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
@@ -3797,13 +3904,21 @@ function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
|
|
|
3797
3904
|
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
|
|
3798
3905
|
return emitFirstMatch(def, ctx, pos);
|
|
3799
3906
|
}
|
|
3907
|
+
function pushMapFn(ctx, fn, src) {
|
|
3908
|
+
if (src !== null && ctx.mapFns.length === ctx.mapFnSrcs.length) {
|
|
3909
|
+
const hit = ctx.mapFnSrcs.indexOf(src);
|
|
3910
|
+
if (hit !== -1) return hit;
|
|
3911
|
+
}
|
|
3912
|
+
const idx = ctx.mapFns.length;
|
|
3913
|
+
ctx.mapFns.push(fn);
|
|
3914
|
+
ctx.mapFnSrcs.push(src);
|
|
3915
|
+
return idx;
|
|
3916
|
+
}
|
|
3800
3917
|
function emitTransformChain(p, baseValue, endV, startPos, ctx) {
|
|
3801
3918
|
const def = p._def;
|
|
3802
3919
|
if (def.tag === "transform") {
|
|
3803
3920
|
const innerR = emitTransformChain(def.parser, baseValue, endV, startPos, ctx);
|
|
3804
|
-
const fnIdx = ctx.
|
|
3805
|
-
ctx.mapFns.push(def.fn);
|
|
3806
|
-
ctx.mapFnSrcs.push(def.fnSrc ?? null);
|
|
3921
|
+
const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
|
|
3807
3922
|
const vv = v(ctx);
|
|
3808
3923
|
return {
|
|
3809
3924
|
stmts: [...innerR.stmts, `${ind(ctx)}const ${vv} = ${mfRef(ctx)}[${fnIdx}](${innerR.valueVar}, { start: ${startPos}, end: ${endV} })`],
|
|
@@ -3986,7 +4101,7 @@ function emitScanTo(def, ctx, pos) {
|
|
|
3986
4101
|
`${ind(ctx)}while (${curV} < input.length) {`
|
|
3987
4102
|
];
|
|
3988
4103
|
ctx.indent++;
|
|
3989
|
-
const probeCtx = { ...ctx, capturing: false };
|
|
4104
|
+
const probeCtx = { ...ctx, capturing: false, noHoist: true };
|
|
3990
4105
|
const { stmts: sentStmts, okVar: sentOk } = emitFallible(def.sentinel, probeCtx, curV);
|
|
3991
4106
|
stmts.push(...sentStmts, `${ind(ctx)}if (${sentOk}) { ${foundV} = true; break }`);
|
|
3992
4107
|
if (def.skip.length > 0) {
|
|
@@ -4032,6 +4147,116 @@ function emitNot(def, ctx, pos) {
|
|
|
4032
4147
|
endVar: pos
|
|
4033
4148
|
};
|
|
4034
4149
|
}
|
|
4150
|
+
function escapeTokenLiteral(value) {
|
|
4151
|
+
return value.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
4152
|
+
}
|
|
4153
|
+
function regexMatchesEmpty(source, flags) {
|
|
4154
|
+
try {
|
|
4155
|
+
return new RegExp(`^(?:${source})$`, flags).test("");
|
|
4156
|
+
} catch {
|
|
4157
|
+
return true;
|
|
4158
|
+
}
|
|
4159
|
+
}
|
|
4160
|
+
function tokenTerminalSource(p) {
|
|
4161
|
+
const def = p._def;
|
|
4162
|
+
switch (def.tag) {
|
|
4163
|
+
case "literal":
|
|
4164
|
+
if (def.value.length === 0) return null;
|
|
4165
|
+
return {
|
|
4166
|
+
source: escapeTokenLiteral(def.value),
|
|
4167
|
+
caseInsensitive: def.caseInsensitive,
|
|
4168
|
+
rawCaseSensitive: def.caseInsensitive ? "" : def.value
|
|
4169
|
+
};
|
|
4170
|
+
case "regex": {
|
|
4171
|
+
if (def.flags.replace(/i/g, "") !== "") return null;
|
|
4172
|
+
if (regexMatchesEmpty(def.source, def.flags)) return null;
|
|
4173
|
+
return {
|
|
4174
|
+
source: `(?:${def.source})`,
|
|
4175
|
+
caseInsensitive: def.flags.includes("i"),
|
|
4176
|
+
rawCaseSensitive: def.flags.includes("i") ? "" : def.source
|
|
4177
|
+
};
|
|
4178
|
+
}
|
|
4179
|
+
default:
|
|
4180
|
+
return null;
|
|
4181
|
+
}
|
|
4182
|
+
}
|
|
4183
|
+
function tokenSequenceSource(p) {
|
|
4184
|
+
const def = p._def;
|
|
4185
|
+
const parts = def.tag === "sequence" ? def.parsers.map(tokenTerminalSource) : [tokenTerminalSource(p)];
|
|
4186
|
+
if (parts.some((part) => part === null)) return null;
|
|
4187
|
+
const typed = parts;
|
|
4188
|
+
const flags = typed.some((part) => part.caseInsensitive) ? "i" : "";
|
|
4189
|
+
if (flags.includes("i") && typed.some((part) => /[A-Za-z]/.test(part.rawCaseSensitive))) return null;
|
|
4190
|
+
return {
|
|
4191
|
+
source: typed.map((part) => part.source).join(""),
|
|
4192
|
+
flags,
|
|
4193
|
+
hasCaseSensitiveLetters: typed.some((part) => /[A-Za-z]/.test(part.rawCaseSensitive))
|
|
4194
|
+
};
|
|
4195
|
+
}
|
|
4196
|
+
function combineTokenRegexSources(parts) {
|
|
4197
|
+
const flags = parts.some((part) => part.flags.includes("i")) ? "i" : "";
|
|
4198
|
+
if (flags.includes("i") && parts.some((part) => part.flags === "" && part.hasCaseSensitiveLetters)) return null;
|
|
4199
|
+
return { source: parts.map((part) => part.source).join(""), flags };
|
|
4200
|
+
}
|
|
4201
|
+
function tokenNullableRegex(def) {
|
|
4202
|
+
const inner = def.parser._def;
|
|
4203
|
+
if (inner.tag === "many") {
|
|
4204
|
+
const seq = tokenSequenceSource(inner.parser);
|
|
4205
|
+
if (!seq) return null;
|
|
4206
|
+
return { tag: "regex", source: `(?:${seq.source})*`, flags: seq.flags };
|
|
4207
|
+
}
|
|
4208
|
+
if (inner.tag === "optional") {
|
|
4209
|
+
const seq = tokenSequenceSource(inner.parser);
|
|
4210
|
+
if (!seq) return null;
|
|
4211
|
+
return { tag: "regex", source: `(?:${seq.source})?`, flags: seq.flags };
|
|
4212
|
+
}
|
|
4213
|
+
if (inner.tag === "sepBy") {
|
|
4214
|
+
const item = tokenSequenceSource(inner.parser);
|
|
4215
|
+
const sep = tokenSequenceSource(inner.separator);
|
|
4216
|
+
if (!item || !sep) return null;
|
|
4217
|
+
const combined = combineTokenRegexSources([item, sep]);
|
|
4218
|
+
if (!combined) return null;
|
|
4219
|
+
return { tag: "regex", source: `(?:${item.source}(?:${sep.source}${item.source})*)?`, flags: combined.flags };
|
|
4220
|
+
}
|
|
4221
|
+
return null;
|
|
4222
|
+
}
|
|
4223
|
+
function emitToken(def, ctx, pos) {
|
|
4224
|
+
const lowered = tokenNullableRegex(def);
|
|
4225
|
+
if (lowered) return emitRegex(lowered, ctx, pos);
|
|
4226
|
+
const savedTrivia = ctx.activeTrivia;
|
|
4227
|
+
const savedKindLabels = ctx.triviaKindLabels;
|
|
4228
|
+
ctx.activeTrivia = void 0;
|
|
4229
|
+
ctx.triviaKindLabels = void 0;
|
|
4230
|
+
const inner = emitFallible(def.parser, ctx, pos);
|
|
4231
|
+
ctx.activeTrivia = savedTrivia;
|
|
4232
|
+
ctx.triviaKindLabels = savedKindLabels;
|
|
4233
|
+
const i = ind(ctx);
|
|
4234
|
+
const sc = v(ctx, "_tokCh");
|
|
4235
|
+
const sl = v(ctx, "_tokLv");
|
|
4236
|
+
const sr = v(ctx, "_tokRaw");
|
|
4237
|
+
const sv = v(ctx, "_tokTr");
|
|
4238
|
+
const sk = v(ctx, "_tokKinds");
|
|
4239
|
+
const stl = v(ctx, "_tokTl");
|
|
4240
|
+
const sol = v(ctx, "_tokLog");
|
|
4241
|
+
const sb = v(ctx, "_tokBuf");
|
|
4242
|
+
const valV = v(ctx, "_tok");
|
|
4243
|
+
return {
|
|
4244
|
+
stmts: [
|
|
4245
|
+
`${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`,
|
|
4246
|
+
`${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`,
|
|
4247
|
+
`${i}try {`,
|
|
4248
|
+
...reindentStmts(inner.stmts, ctx.indent + 1).map((stmt) => stmt.replace(/^(\s*)(?:const|let)\s+/, "$1var ")),
|
|
4249
|
+
`${i}} finally {`,
|
|
4250
|
+
`${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}`,
|
|
4251
|
+
`${i}}`,
|
|
4252
|
+
...emitIfFail(ctx, `!${inner.okVar}`, propagateFailBody(ctx)),
|
|
4253
|
+
`${i}const ${valV} = input.slice(${pos}, ${inner.endVar})`,
|
|
4254
|
+
...emitLeafCapture(ctx, valV, pos, inner.endVar)
|
|
4255
|
+
],
|
|
4256
|
+
valueVar: valV,
|
|
4257
|
+
endVar: inner.endVar
|
|
4258
|
+
};
|
|
4259
|
+
}
|
|
4035
4260
|
function emitNode(def, ctx, pos) {
|
|
4036
4261
|
const structural = def.build === void 0;
|
|
4037
4262
|
const mkType = structural ? null : analyzeMkInlineBuild(def);
|
|
@@ -4151,7 +4376,7 @@ function emitRecover(def, ctx, pos) {
|
|
|
4151
4376
|
`${ind0} if (${sentOk}) break`,
|
|
4152
4377
|
`${ind0} ${scanV}++`,
|
|
4153
4378
|
`${ind0} }`,
|
|
4154
|
-
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: ${JSON.stringify(
|
|
4379
|
+
`${ind0} const ${errV} = { _tag: 'parseError', span: { start: ${pos}, end: ${scanV} }, expected: ${JSON.stringify(deriveExpected(def.parser))} }`,
|
|
4155
4380
|
`${ind0} if (_ctx._errors) _ctx._errors.push(${errV})`,
|
|
4156
4381
|
`${ind0} ${valVar} = ${errV}`,
|
|
4157
4382
|
`${ind0} ${endVar} = ${scanV}`,
|
|
@@ -4177,6 +4402,32 @@ function emitExpect(def, ctx, pos) {
|
|
|
4177
4402
|
return { stmts, valueVar: valVar, endVar };
|
|
4178
4403
|
}
|
|
4179
4404
|
function emit(p, ctx, pos) {
|
|
4405
|
+
const usage = ctx.lazyUsage;
|
|
4406
|
+
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
|
|
4407
|
+
// overhead. A tiny shared wrapper (e.g. `optional(literal(';'))`) inlines
|
|
4408
|
+
// faster than it calls and barely moves the byte count; the size explosion
|
|
4409
|
+
// is all in LARGE choices/sequences referenced from many positions.
|
|
4410
|
+
(usage.sizes.get(p) ?? 0) >= HOIST_MIN_SUBTREE) {
|
|
4411
|
+
const existing = ctx.namedParsers.get(p);
|
|
4412
|
+
if (existing !== void 0) return emitNamedFnCall(ctx, existing, pos);
|
|
4413
|
+
const fnName = `${nsp(ctx)}_pf${ctx.namedParsers.size}`;
|
|
4414
|
+
ctx.namedParsers.set(p, fnName);
|
|
4415
|
+
const savedIndent = ctx.indent;
|
|
4416
|
+
const savedFailLabel = ctx.failLabel;
|
|
4417
|
+
const savedRecord = ctx.recordFail;
|
|
4418
|
+
ctx.indent = 1;
|
|
4419
|
+
ctx.failLabel = "_pfail";
|
|
4420
|
+
ctx.recordFail = true;
|
|
4421
|
+
const r = emitDispatch(p, ctx, "_pos");
|
|
4422
|
+
ctx.indent = savedIndent;
|
|
4423
|
+
ctx.failLabel = savedFailLabel;
|
|
4424
|
+
ctx.recordFail = savedRecord;
|
|
4425
|
+
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
4426
|
+
return emitNamedFnCall(ctx, fnName, pos);
|
|
4427
|
+
}
|
|
4428
|
+
return emitDispatch(p, ctx, pos);
|
|
4429
|
+
}
|
|
4430
|
+
function emitDispatch(p, ctx, pos) {
|
|
4180
4431
|
const def = p._def;
|
|
4181
4432
|
switch (def.tag) {
|
|
4182
4433
|
case "literal":
|
|
@@ -4222,9 +4473,7 @@ function emit(p, ctx, pos) {
|
|
|
4222
4473
|
};
|
|
4223
4474
|
}
|
|
4224
4475
|
}
|
|
4225
|
-
const fnIdx = ctx.
|
|
4226
|
-
ctx.mapFns.push(def.fn);
|
|
4227
|
-
ctx.mapFnSrcs.push(def.fnSrc ?? null);
|
|
4476
|
+
const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
|
|
4228
4477
|
const mv = v(ctx, "_mapped");
|
|
4229
4478
|
return {
|
|
4230
4479
|
stmts: [
|
|
@@ -4257,6 +4506,8 @@ function emit(p, ctx, pos) {
|
|
|
4257
4506
|
return emitLazy(p, def, ctx, pos);
|
|
4258
4507
|
case "trivia":
|
|
4259
4508
|
return emit(def.parser, ctx, pos);
|
|
4509
|
+
case "token":
|
|
4510
|
+
return emitToken(def, ctx, pos);
|
|
4260
4511
|
case "label":
|
|
4261
4512
|
return emit(def.parser, ctx, pos);
|
|
4262
4513
|
case "grammar": {
|
|
@@ -4289,6 +4540,7 @@ function emit(p, ctx, pos) {
|
|
|
4289
4540
|
case "guard": {
|
|
4290
4541
|
const fnIdx = ctx.mapFns.length;
|
|
4291
4542
|
ctx.mapFns.push(def.predicate);
|
|
4543
|
+
ctx.mapFnSrcs.push(null);
|
|
4292
4544
|
const vv = v(ctx);
|
|
4293
4545
|
return {
|
|
4294
4546
|
stmts: [
|
|
@@ -4303,6 +4555,7 @@ function emit(p, ctx, pos) {
|
|
|
4303
4555
|
const evIdx = ctx.mapFns.length;
|
|
4304
4556
|
const extra = def.extra;
|
|
4305
4557
|
ctx.mapFns.push((() => extra));
|
|
4558
|
+
ctx.mapFnSrcs.push(null);
|
|
4306
4559
|
const innerParser = def.parser;
|
|
4307
4560
|
if (!ctx.namedParsers.has(innerParser)) {
|
|
4308
4561
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
@@ -4356,6 +4609,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4356
4609
|
}
|
|
4357
4610
|
case "grammar":
|
|
4358
4611
|
case "trivia":
|
|
4612
|
+
case "token":
|
|
4359
4613
|
case "label":
|
|
4360
4614
|
case "optional":
|
|
4361
4615
|
case "many":
|
|
@@ -4391,6 +4645,7 @@ function childrenOf(def) {
|
|
|
4391
4645
|
case "optional":
|
|
4392
4646
|
case "transform":
|
|
4393
4647
|
case "trivia":
|
|
4648
|
+
case "token":
|
|
4394
4649
|
case "label":
|
|
4395
4650
|
case "grammar":
|
|
4396
4651
|
case "not":
|
|
@@ -4422,9 +4677,58 @@ function childrenOf(def) {
|
|
|
4422
4677
|
return [];
|
|
4423
4678
|
}
|
|
4424
4679
|
}
|
|
4680
|
+
var HOISTABLE_TAGS = /* @__PURE__ */ new Set([
|
|
4681
|
+
"sequence",
|
|
4682
|
+
"choice",
|
|
4683
|
+
"many",
|
|
4684
|
+
"oneOrMore",
|
|
4685
|
+
"optional",
|
|
4686
|
+
"sepBy",
|
|
4687
|
+
"transform",
|
|
4688
|
+
"node",
|
|
4689
|
+
"not"
|
|
4690
|
+
]);
|
|
4691
|
+
function isHoistableTag(tag) {
|
|
4692
|
+
return HOISTABLE_TAGS.has(tag);
|
|
4693
|
+
}
|
|
4694
|
+
var HOIST_MIN_SUBTREE = 3;
|
|
4425
4695
|
function analyzeLazyUsage(root) {
|
|
4426
4696
|
return analyzeLazyUsageMulti([root]);
|
|
4427
4697
|
}
|
|
4698
|
+
function subtreeSizes(roots) {
|
|
4699
|
+
const sizes = /* @__PURE__ */ new Map();
|
|
4700
|
+
const sz = (p) => {
|
|
4701
|
+
const cached = sizes.get(p);
|
|
4702
|
+
if (cached !== void 0) return cached;
|
|
4703
|
+
const def = p._def;
|
|
4704
|
+
let s = 1;
|
|
4705
|
+
if (def.tag !== "lazy") {
|
|
4706
|
+
for (const child of childrenOf(def)) s += child._def.tag === "lazy" ? 1 : sz(child);
|
|
4707
|
+
}
|
|
4708
|
+
sizes.set(p, s);
|
|
4709
|
+
return s;
|
|
4710
|
+
};
|
|
4711
|
+
const visitedLazy = /* @__PURE__ */ new Set();
|
|
4712
|
+
const visit = (p) => {
|
|
4713
|
+
const def = p._def;
|
|
4714
|
+
if (def.tag === "lazy") {
|
|
4715
|
+
if (visitedLazy.has(p)) return;
|
|
4716
|
+
visitedLazy.add(p);
|
|
4717
|
+
let resolved;
|
|
4718
|
+
try {
|
|
4719
|
+
resolved = def.thunk();
|
|
4720
|
+
} catch {
|
|
4721
|
+
return;
|
|
4722
|
+
}
|
|
4723
|
+
visit(resolved);
|
|
4724
|
+
return;
|
|
4725
|
+
}
|
|
4726
|
+
sz(p);
|
|
4727
|
+
for (const child of childrenOf(def)) visit(child);
|
|
4728
|
+
};
|
|
4729
|
+
for (const root of roots) visit(root);
|
|
4730
|
+
return sizes;
|
|
4731
|
+
}
|
|
4428
4732
|
function analyzeLazyUsageMulti(roots) {
|
|
4429
4733
|
const counts = /* @__PURE__ */ new Map();
|
|
4430
4734
|
const recursive = /* @__PURE__ */ new Set();
|
|
@@ -4451,10 +4755,14 @@ function analyzeLazyUsageMulti(roots) {
|
|
|
4451
4755
|
active.delete(p);
|
|
4452
4756
|
return;
|
|
4453
4757
|
}
|
|
4758
|
+
if (isHoistableTag(def.tag)) {
|
|
4759
|
+
counts.set(p, (counts.get(p) ?? 0) + 1);
|
|
4760
|
+
}
|
|
4454
4761
|
for (const child of childrenOf(def)) walk2(child);
|
|
4455
4762
|
}
|
|
4456
|
-
|
|
4457
|
-
|
|
4763
|
+
const rootsArr = [...roots];
|
|
4764
|
+
for (const root of rootsArr) walk2(root);
|
|
4765
|
+
return { counts, recursive, sizes: subtreeSizes(rootsArr) };
|
|
4458
4766
|
}
|
|
4459
4767
|
function ruleDependencies(ruleMap) {
|
|
4460
4768
|
const nameOf = /* @__PURE__ */ new Map();
|
|
@@ -4780,6 +5088,174 @@ function buildInlineExpression(ctx, r, mapFnSources, buildSources) {
|
|
|
4780
5088
|
].join("\n");
|
|
4781
5089
|
}
|
|
4782
5090
|
|
|
5091
|
+
// src/combinators/scanTo.ts
|
|
5092
|
+
function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
5093
|
+
const meta = {
|
|
5094
|
+
firstSet: any(),
|
|
5095
|
+
canMatchNewline: true,
|
|
5096
|
+
isTrivia: false
|
|
5097
|
+
};
|
|
5098
|
+
return {
|
|
5099
|
+
_tag: "scanTo",
|
|
5100
|
+
_meta: meta,
|
|
5101
|
+
_def: { tag: "scanTo", sentinel, skip: skip2, orEOF },
|
|
5102
|
+
parse(input, pos, ctx) {
|
|
5103
|
+
let cur = pos;
|
|
5104
|
+
const probeCtx = {
|
|
5105
|
+
trackLines: ctx.trackLines,
|
|
5106
|
+
state: ctx.state,
|
|
5107
|
+
...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
|
|
5108
|
+
};
|
|
5109
|
+
const emit2 = (end) => {
|
|
5110
|
+
if (end > pos && cstCaptureActive(ctx)) {
|
|
5111
|
+
const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
5112
|
+
pushCstLeaf(ctx, leaf);
|
|
5113
|
+
}
|
|
5114
|
+
};
|
|
5115
|
+
while (cur < input.length) {
|
|
5116
|
+
const s = sentinel.parse(input, cur, probeCtx);
|
|
5117
|
+
if (s.ok) {
|
|
5118
|
+
emit2(cur);
|
|
5119
|
+
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
5120
|
+
}
|
|
5121
|
+
let advanced = false;
|
|
5122
|
+
for (const skipper of skip2) {
|
|
5123
|
+
const r = skipper.parse(input, cur, probeCtx);
|
|
5124
|
+
if (r.ok && r.span.end > cur) {
|
|
5125
|
+
cur = r.span.end;
|
|
5126
|
+
advanced = true;
|
|
5127
|
+
break;
|
|
5128
|
+
}
|
|
5129
|
+
}
|
|
5130
|
+
if (!advanced) cur++;
|
|
5131
|
+
}
|
|
5132
|
+
if (orEOF) {
|
|
5133
|
+
emit2(cur);
|
|
5134
|
+
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
5135
|
+
}
|
|
5136
|
+
const sentDef = sentinel._def;
|
|
5137
|
+
const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
|
|
5138
|
+
return { ok: false, expected, span: { start: pos, end: cur } };
|
|
5139
|
+
}
|
|
5140
|
+
};
|
|
5141
|
+
}
|
|
5142
|
+
function balanced(open, close, options = {}) {
|
|
5143
|
+
const self = ref();
|
|
5144
|
+
const skips = options.skip ?? [];
|
|
5145
|
+
const stop = /* @__PURE__ */ new Set([open, close]);
|
|
5146
|
+
let bounded = true;
|
|
5147
|
+
for (const sk of skips) {
|
|
5148
|
+
const cs = firstSetClassChars(sk);
|
|
5149
|
+
if (cs === null) {
|
|
5150
|
+
bounded = false;
|
|
5151
|
+
break;
|
|
5152
|
+
}
|
|
5153
|
+
for (const ch of cs) stop.add(ch);
|
|
5154
|
+
}
|
|
5155
|
+
const cls = [...stop].map(escapeClassChar).join("");
|
|
5156
|
+
const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
|
|
5157
|
+
const inner = many(choice(self, ...skips, content));
|
|
5158
|
+
const combi = transform(
|
|
5159
|
+
sequence(literal(open), inner, expect(literal(close))),
|
|
5160
|
+
// parts: strings (content/self) or arrays (a sequence-shaped skip) or a
|
|
5161
|
+
// ParseError (recovered close). `c` is the close string or a ParseError.
|
|
5162
|
+
([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
|
|
5163
|
+
);
|
|
5164
|
+
if (combi._def.tag === "transform") {
|
|
5165
|
+
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
5166
|
+
}
|
|
5167
|
+
self.define(combi);
|
|
5168
|
+
return combi;
|
|
5169
|
+
}
|
|
5170
|
+
function firstSetClassChars(c) {
|
|
5171
|
+
const fs = c._meta.firstSet;
|
|
5172
|
+
if (fs.kind === "empty") return [];
|
|
5173
|
+
if (fs.kind !== "ranges") return null;
|
|
5174
|
+
const out = [];
|
|
5175
|
+
for (const { lo, hi } of fs.ranges) {
|
|
5176
|
+
if (hi - lo > 8) return null;
|
|
5177
|
+
for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
|
|
5178
|
+
}
|
|
5179
|
+
return out;
|
|
5180
|
+
}
|
|
5181
|
+
function escapeClassChar(ch) {
|
|
5182
|
+
return ch.replace(/[\\\]^-]/g, "\\$&");
|
|
5183
|
+
}
|
|
5184
|
+
|
|
5185
|
+
// src/compiler/ir-serialize.ts
|
|
5186
|
+
function evalRuleMapIR(ir) {
|
|
5187
|
+
const _tf = (child, src) => {
|
|
5188
|
+
let fn2;
|
|
5189
|
+
try {
|
|
5190
|
+
fn2 = (0, eval)(`(${src})`);
|
|
5191
|
+
} catch {
|
|
5192
|
+
fn2 = () => {
|
|
5193
|
+
throw new Error("IR transform fn not materialized");
|
|
5194
|
+
};
|
|
5195
|
+
}
|
|
5196
|
+
const t = transform(child, fn2);
|
|
5197
|
+
t._def.fnSrc = src;
|
|
5198
|
+
return t;
|
|
5199
|
+
};
|
|
5200
|
+
const _nd = (type, child, src, opts) => {
|
|
5201
|
+
const n = node(type, child, void 0, opts);
|
|
5202
|
+
n._def.buildSrc = src;
|
|
5203
|
+
return n;
|
|
5204
|
+
};
|
|
5205
|
+
const fn = new Function(
|
|
5206
|
+
"rules",
|
|
5207
|
+
"ref",
|
|
5208
|
+
"regex",
|
|
5209
|
+
"literal",
|
|
5210
|
+
"keywords",
|
|
5211
|
+
"sequence",
|
|
5212
|
+
"choice",
|
|
5213
|
+
"many",
|
|
5214
|
+
"oneOrMore",
|
|
5215
|
+
"optional",
|
|
5216
|
+
"sepBy",
|
|
5217
|
+
"not",
|
|
5218
|
+
"node",
|
|
5219
|
+
"parser",
|
|
5220
|
+
"scanTo",
|
|
5221
|
+
"token",
|
|
5222
|
+
"transform",
|
|
5223
|
+
"skip",
|
|
5224
|
+
"trivia",
|
|
5225
|
+
"label",
|
|
5226
|
+
"expect",
|
|
5227
|
+
"_tf",
|
|
5228
|
+
"_nd",
|
|
5229
|
+
`return (${ir})`
|
|
5230
|
+
);
|
|
5231
|
+
const map = fn(
|
|
5232
|
+
rules,
|
|
5233
|
+
ref,
|
|
5234
|
+
regex,
|
|
5235
|
+
literal,
|
|
5236
|
+
keywords,
|
|
5237
|
+
sequence,
|
|
5238
|
+
choice,
|
|
5239
|
+
many,
|
|
5240
|
+
oneOrMore,
|
|
5241
|
+
optional,
|
|
5242
|
+
sepBy,
|
|
5243
|
+
not,
|
|
5244
|
+
node,
|
|
5245
|
+
parser,
|
|
5246
|
+
scanTo,
|
|
5247
|
+
token,
|
|
5248
|
+
transform,
|
|
5249
|
+
skip,
|
|
5250
|
+
trivia,
|
|
5251
|
+
label,
|
|
5252
|
+
expect,
|
|
5253
|
+
_tf,
|
|
5254
|
+
_nd
|
|
5255
|
+
);
|
|
5256
|
+
return Object.entries(map);
|
|
5257
|
+
}
|
|
5258
|
+
|
|
4783
5259
|
// src/compiler/linker.ts
|
|
4784
5260
|
var _nsCounter = 0;
|
|
4785
5261
|
function linkable(rulesMap, ns) {
|
|
@@ -4864,9 +5340,18 @@ function fuseRules(pieces) {
|
|
|
4864
5340
|
return new Function("_env", body)(env);
|
|
4865
5341
|
}
|
|
4866
5342
|
var COMPOSED_PIECES = /* @__PURE__ */ Symbol.for("parseman.composedPieces");
|
|
5343
|
+
function isIRPiece(p) {
|
|
5344
|
+
return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
|
|
5345
|
+
}
|
|
5346
|
+
function materializePiece(p) {
|
|
5347
|
+
if (!isIRPiece(p)) return p;
|
|
5348
|
+
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns);
|
|
5349
|
+
if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
|
|
5350
|
+
return pieces;
|
|
5351
|
+
}
|
|
4867
5352
|
function itemPieces(item) {
|
|
4868
5353
|
const carried = item[COMPOSED_PIECES];
|
|
4869
|
-
if (Array.isArray(carried)) return carried;
|
|
5354
|
+
if (Array.isArray(carried)) return carried.map(materializePiece);
|
|
4870
5355
|
if (item.ruleFns instanceof Map) return [item];
|
|
4871
5356
|
return [linkable(item)];
|
|
4872
5357
|
}
|
|
@@ -4920,7 +5405,7 @@ function recover(combinator, sentinel) {
|
|
|
4920
5405
|
canMatchNewline: true,
|
|
4921
5406
|
isTrivia: false
|
|
4922
5407
|
};
|
|
4923
|
-
const expected =
|
|
5408
|
+
const expected = deriveExpected(combinator);
|
|
4924
5409
|
return {
|
|
4925
5410
|
_tag: "recover",
|
|
4926
5411
|
_meta: meta,
|
|
@@ -4962,100 +5447,6 @@ function deeperFail(a, b) {
|
|
|
4962
5447
|
return a.span.start >= b.span.start ? a : b;
|
|
4963
5448
|
}
|
|
4964
5449
|
|
|
4965
|
-
// src/combinators/scanTo.ts
|
|
4966
|
-
function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
4967
|
-
const meta = {
|
|
4968
|
-
firstSet: any(),
|
|
4969
|
-
canMatchNewline: true,
|
|
4970
|
-
isTrivia: false
|
|
4971
|
-
};
|
|
4972
|
-
return {
|
|
4973
|
-
_tag: "scanTo",
|
|
4974
|
-
_meta: meta,
|
|
4975
|
-
_def: { tag: "scanTo", sentinel, skip: skip2, orEOF },
|
|
4976
|
-
parse(input, pos, ctx) {
|
|
4977
|
-
let cur = pos;
|
|
4978
|
-
const probeCtx = {
|
|
4979
|
-
trackLines: ctx.trackLines,
|
|
4980
|
-
state: ctx.state,
|
|
4981
|
-
...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
|
|
4982
|
-
};
|
|
4983
|
-
const emit2 = (end) => {
|
|
4984
|
-
if (end > pos && cstCaptureActive(ctx)) {
|
|
4985
|
-
const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
4986
|
-
pushCstLeaf(ctx, leaf);
|
|
4987
|
-
}
|
|
4988
|
-
};
|
|
4989
|
-
while (cur < input.length) {
|
|
4990
|
-
const s = sentinel.parse(input, cur, probeCtx);
|
|
4991
|
-
if (s.ok) {
|
|
4992
|
-
emit2(cur);
|
|
4993
|
-
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
4994
|
-
}
|
|
4995
|
-
let advanced = false;
|
|
4996
|
-
for (const skipper of skip2) {
|
|
4997
|
-
const r = skipper.parse(input, cur, probeCtx);
|
|
4998
|
-
if (r.ok && r.span.end > cur) {
|
|
4999
|
-
cur = r.span.end;
|
|
5000
|
-
advanced = true;
|
|
5001
|
-
break;
|
|
5002
|
-
}
|
|
5003
|
-
}
|
|
5004
|
-
if (!advanced) cur++;
|
|
5005
|
-
}
|
|
5006
|
-
if (orEOF) {
|
|
5007
|
-
emit2(cur);
|
|
5008
|
-
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
5009
|
-
}
|
|
5010
|
-
const sentDef = sentinel._def;
|
|
5011
|
-
const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
|
|
5012
|
-
return { ok: false, expected, span: { start: pos, end: cur } };
|
|
5013
|
-
}
|
|
5014
|
-
};
|
|
5015
|
-
}
|
|
5016
|
-
function balanced(open, close, options = {}) {
|
|
5017
|
-
const self = ref();
|
|
5018
|
-
const skips = options.skip ?? [];
|
|
5019
|
-
const stop = /* @__PURE__ */ new Set([open, close]);
|
|
5020
|
-
let bounded = true;
|
|
5021
|
-
for (const sk of skips) {
|
|
5022
|
-
const cs = firstSetClassChars(sk);
|
|
5023
|
-
if (cs === null) {
|
|
5024
|
-
bounded = false;
|
|
5025
|
-
break;
|
|
5026
|
-
}
|
|
5027
|
-
for (const ch of cs) stop.add(ch);
|
|
5028
|
-
}
|
|
5029
|
-
const cls = [...stop].map(escapeClassChar).join("");
|
|
5030
|
-
const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
|
|
5031
|
-
const inner = many(choice(self, ...skips, content));
|
|
5032
|
-
const combi = transform(
|
|
5033
|
-
sequence(literal(open), inner, expect(literal(close), close)),
|
|
5034
|
-
// parts: strings (content/self) or arrays (a sequence-shaped skip) or a
|
|
5035
|
-
// ParseError (recovered close). `c` is the close string or a ParseError.
|
|
5036
|
-
([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
|
|
5037
|
-
);
|
|
5038
|
-
if (combi._def.tag === "transform") {
|
|
5039
|
-
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
5040
|
-
}
|
|
5041
|
-
self.define(combi);
|
|
5042
|
-
return combi;
|
|
5043
|
-
}
|
|
5044
|
-
function firstSetClassChars(c) {
|
|
5045
|
-
const fs = c._meta.firstSet;
|
|
5046
|
-
if (fs.kind === "empty") return [];
|
|
5047
|
-
if (fs.kind !== "ranges") return null;
|
|
5048
|
-
const out = [];
|
|
5049
|
-
for (const { lo, hi } of fs.ranges) {
|
|
5050
|
-
if (hi - lo > 8) return null;
|
|
5051
|
-
for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
|
|
5052
|
-
}
|
|
5053
|
-
return out;
|
|
5054
|
-
}
|
|
5055
|
-
function escapeClassChar(ch) {
|
|
5056
|
-
return ch.replace(/[\\\]^-]/g, "\\$&");
|
|
5057
|
-
}
|
|
5058
|
-
|
|
5059
5450
|
// src/combinators/recover-list.ts
|
|
5060
5451
|
function tolerantElement(item, sentinel, until) {
|
|
5061
5452
|
const el = transform(
|
|
@@ -5727,7 +6118,7 @@ export {
|
|
|
5727
6118
|
sequence,
|
|
5728
6119
|
shiftAbsolute,
|
|
5729
6120
|
skip,
|
|
5730
|
-
|
|
6121
|
+
token,
|
|
5731
6122
|
transform,
|
|
5732
6123
|
trivia,
|
|
5733
6124
|
triviaEntries,
|