parseman 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/combinators/first-set.d.ts +14 -0
- package/dist/combinators/first-set.d.ts.map +1 -1
- 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/index.cjs +329 -112
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +329 -112
- package/dist/index.js.map +4 -4
- package/dist/plugin/index.cjs +647 -108
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +647 -108
- package/dist/plugin/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -84,6 +84,54 @@ function sequenceFirstSet(parsers) {
|
|
|
84
84
|
}
|
|
85
85
|
return fs;
|
|
86
86
|
}
|
|
87
|
+
function firstSetOf(p, seen = /* @__PURE__ */ new Set()) {
|
|
88
|
+
if (seen.has(p)) return any();
|
|
89
|
+
seen.add(p);
|
|
90
|
+
const fs = (c) => firstSetOf(c, seen);
|
|
91
|
+
const d = p._def;
|
|
92
|
+
switch (d.tag) {
|
|
93
|
+
case "literal":
|
|
94
|
+
case "regex":
|
|
95
|
+
case "keywords":
|
|
96
|
+
return p._meta.firstSet;
|
|
97
|
+
// terminals: no refs, cached set is exact
|
|
98
|
+
case "lazy":
|
|
99
|
+
try {
|
|
100
|
+
return fs(d.thunk());
|
|
101
|
+
} catch {
|
|
102
|
+
return any();
|
|
103
|
+
}
|
|
104
|
+
case "choice": {
|
|
105
|
+
let out = empty();
|
|
106
|
+
for (const arm of d.parsers) out = union(out, fs(arm));
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
case "sequence": {
|
|
110
|
+
let out = empty();
|
|
111
|
+
for (const term of d.parsers) {
|
|
112
|
+
out = union(out, fs(term));
|
|
113
|
+
if (!matchesEmpty(term)) return out;
|
|
114
|
+
}
|
|
115
|
+
return out;
|
|
116
|
+
}
|
|
117
|
+
case "oneOrMore":
|
|
118
|
+
case "many":
|
|
119
|
+
case "optional":
|
|
120
|
+
case "transform":
|
|
121
|
+
case "label":
|
|
122
|
+
case "trivia":
|
|
123
|
+
case "node":
|
|
124
|
+
case "grammar":
|
|
125
|
+
case "expect":
|
|
126
|
+
return fs(d.parser);
|
|
127
|
+
case "sepBy":
|
|
128
|
+
return fs(d.parser);
|
|
129
|
+
case "skip":
|
|
130
|
+
return fs(d.main);
|
|
131
|
+
default:
|
|
132
|
+
return p._meta.firstSet;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
87
135
|
function mergeRanges(ranges) {
|
|
88
136
|
if (ranges.length === 0) return [];
|
|
89
137
|
const sorted = [...ranges].sort((a, b) => a.lo - b.lo);
|
|
@@ -3024,16 +3072,12 @@ function namedFnPrelude() {
|
|
|
3024
3072
|
function pushNamedFnDecl(ctx, fnName, bodyStmts, valueVar, endVar) {
|
|
3025
3073
|
ctx.namedFnDecls.push([
|
|
3026
3074
|
`function ${fnName}(input, _pos, _ctx) {`,
|
|
3027
|
-
` let _pfok = false, _pfv, _pfe = _pos`,
|
|
3028
3075
|
` _pfail: {`,
|
|
3029
3076
|
...reindentStmts(bodyStmts, 2),
|
|
3030
|
-
`
|
|
3031
|
-
`
|
|
3032
|
-
` _pfok = true`,
|
|
3077
|
+
` ${NAMED_FN_END} = ${endVar}`,
|
|
3078
|
+
` return ${valueVar}`,
|
|
3033
3079
|
` }`,
|
|
3034
|
-
`
|
|
3035
|
-
` ${NAMED_FN_END} = _pfe`,
|
|
3036
|
-
` return _pfv`,
|
|
3080
|
+
` return ${NAMED_FN_FAIL}`,
|
|
3037
3081
|
`}`
|
|
3038
3082
|
].join("\n"));
|
|
3039
3083
|
}
|
|
@@ -3734,11 +3778,16 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
3734
3778
|
const atStart = failsAtStart(p);
|
|
3735
3779
|
const staticFx = armStaticExpected(ctx, p);
|
|
3736
3780
|
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) :
|
|
3781
|
+
const fsGuard = deferRuleName !== void 0 ? `/*@FS:${deferRuleName}:${codeV}@*/true` : needsFirstSetGuard(p) ? firstSetCond(codeV, p._meta.firstSet) : (() => {
|
|
3782
|
+
if (p._meta.firstSet.kind !== "any" || matchesEmpty(p)) return null;
|
|
3783
|
+
const deep = firstSetOf(p);
|
|
3784
|
+
return deep.kind === "ranges" ? firstSetCond(codeV, deep) : null;
|
|
3785
|
+
})();
|
|
3738
3786
|
let gateCond = null;
|
|
3739
3787
|
if (gate) {
|
|
3740
3788
|
const gateIdx = ctx.mapFns.length;
|
|
3741
3789
|
ctx.mapFns.push(gate);
|
|
3790
|
+
ctx.mapFnSrcs.push(null);
|
|
3742
3791
|
gateCond = `${mfRef(ctx)}[${gateIdx}](_ctx.state)`;
|
|
3743
3792
|
}
|
|
3744
3793
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
@@ -3797,13 +3846,21 @@ function emitNonDisjoint(def, strategy, allExpected, ctx, pos) {
|
|
|
3797
3846
|
return emitLiteralsLongestFirst(def, strategy.sortedIndices, allExpected, ctx, pos);
|
|
3798
3847
|
return emitFirstMatch(def, ctx, pos);
|
|
3799
3848
|
}
|
|
3849
|
+
function pushMapFn(ctx, fn, src) {
|
|
3850
|
+
if (src !== null && ctx.mapFns.length === ctx.mapFnSrcs.length) {
|
|
3851
|
+
const hit = ctx.mapFnSrcs.indexOf(src);
|
|
3852
|
+
if (hit !== -1) return hit;
|
|
3853
|
+
}
|
|
3854
|
+
const idx = ctx.mapFns.length;
|
|
3855
|
+
ctx.mapFns.push(fn);
|
|
3856
|
+
ctx.mapFnSrcs.push(src);
|
|
3857
|
+
return idx;
|
|
3858
|
+
}
|
|
3800
3859
|
function emitTransformChain(p, baseValue, endV, startPos, ctx) {
|
|
3801
3860
|
const def = p._def;
|
|
3802
3861
|
if (def.tag === "transform") {
|
|
3803
3862
|
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);
|
|
3863
|
+
const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
|
|
3807
3864
|
const vv = v(ctx);
|
|
3808
3865
|
return {
|
|
3809
3866
|
stmts: [...innerR.stmts, `${ind(ctx)}const ${vv} = ${mfRef(ctx)}[${fnIdx}](${innerR.valueVar}, { start: ${startPos}, end: ${endV} })`],
|
|
@@ -3986,7 +4043,7 @@ function emitScanTo(def, ctx, pos) {
|
|
|
3986
4043
|
`${ind(ctx)}while (${curV} < input.length) {`
|
|
3987
4044
|
];
|
|
3988
4045
|
ctx.indent++;
|
|
3989
|
-
const probeCtx = { ...ctx, capturing: false };
|
|
4046
|
+
const probeCtx = { ...ctx, capturing: false, noHoist: true };
|
|
3990
4047
|
const { stmts: sentStmts, okVar: sentOk } = emitFallible(def.sentinel, probeCtx, curV);
|
|
3991
4048
|
stmts.push(...sentStmts, `${ind(ctx)}if (${sentOk}) { ${foundV} = true; break }`);
|
|
3992
4049
|
if (def.skip.length > 0) {
|
|
@@ -4177,6 +4234,32 @@ function emitExpect(def, ctx, pos) {
|
|
|
4177
4234
|
return { stmts, valueVar: valVar, endVar };
|
|
4178
4235
|
}
|
|
4179
4236
|
function emit(p, ctx, pos) {
|
|
4237
|
+
const usage = ctx.lazyUsage;
|
|
4238
|
+
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
|
|
4239
|
+
// overhead. A tiny shared wrapper (e.g. `optional(literal(';'))`) inlines
|
|
4240
|
+
// faster than it calls and barely moves the byte count; the size explosion
|
|
4241
|
+
// is all in LARGE choices/sequences referenced from many positions.
|
|
4242
|
+
(usage.sizes.get(p) ?? 0) >= HOIST_MIN_SUBTREE) {
|
|
4243
|
+
const existing = ctx.namedParsers.get(p);
|
|
4244
|
+
if (existing !== void 0) return emitNamedFnCall(ctx, existing, pos);
|
|
4245
|
+
const fnName = `${nsp(ctx)}_pf${ctx.namedParsers.size}`;
|
|
4246
|
+
ctx.namedParsers.set(p, fnName);
|
|
4247
|
+
const savedIndent = ctx.indent;
|
|
4248
|
+
const savedFailLabel = ctx.failLabel;
|
|
4249
|
+
const savedRecord = ctx.recordFail;
|
|
4250
|
+
ctx.indent = 1;
|
|
4251
|
+
ctx.failLabel = "_pfail";
|
|
4252
|
+
ctx.recordFail = true;
|
|
4253
|
+
const r = emitDispatch(p, ctx, "_pos");
|
|
4254
|
+
ctx.indent = savedIndent;
|
|
4255
|
+
ctx.failLabel = savedFailLabel;
|
|
4256
|
+
ctx.recordFail = savedRecord;
|
|
4257
|
+
pushNamedFnDecl(ctx, fnName, r.stmts, r.valueVar, r.endVar);
|
|
4258
|
+
return emitNamedFnCall(ctx, fnName, pos);
|
|
4259
|
+
}
|
|
4260
|
+
return emitDispatch(p, ctx, pos);
|
|
4261
|
+
}
|
|
4262
|
+
function emitDispatch(p, ctx, pos) {
|
|
4180
4263
|
const def = p._def;
|
|
4181
4264
|
switch (def.tag) {
|
|
4182
4265
|
case "literal":
|
|
@@ -4222,9 +4305,7 @@ function emit(p, ctx, pos) {
|
|
|
4222
4305
|
};
|
|
4223
4306
|
}
|
|
4224
4307
|
}
|
|
4225
|
-
const fnIdx = ctx.
|
|
4226
|
-
ctx.mapFns.push(def.fn);
|
|
4227
|
-
ctx.mapFnSrcs.push(def.fnSrc ?? null);
|
|
4308
|
+
const fnIdx = pushMapFn(ctx, def.fn, def.fnSrc ?? null);
|
|
4228
4309
|
const mv = v(ctx, "_mapped");
|
|
4229
4310
|
return {
|
|
4230
4311
|
stmts: [
|
|
@@ -4289,6 +4370,7 @@ function emit(p, ctx, pos) {
|
|
|
4289
4370
|
case "guard": {
|
|
4290
4371
|
const fnIdx = ctx.mapFns.length;
|
|
4291
4372
|
ctx.mapFns.push(def.predicate);
|
|
4373
|
+
ctx.mapFnSrcs.push(null);
|
|
4292
4374
|
const vv = v(ctx);
|
|
4293
4375
|
return {
|
|
4294
4376
|
stmts: [
|
|
@@ -4303,6 +4385,7 @@ function emit(p, ctx, pos) {
|
|
|
4303
4385
|
const evIdx = ctx.mapFns.length;
|
|
4304
4386
|
const extra = def.extra;
|
|
4305
4387
|
ctx.mapFns.push((() => extra));
|
|
4388
|
+
ctx.mapFnSrcs.push(null);
|
|
4306
4389
|
const innerParser = def.parser;
|
|
4307
4390
|
if (!ctx.namedParsers.has(innerParser)) {
|
|
4308
4391
|
const fnName = `_wcf${ctx.namedParsers.size}`;
|
|
@@ -4422,9 +4505,58 @@ function childrenOf(def) {
|
|
|
4422
4505
|
return [];
|
|
4423
4506
|
}
|
|
4424
4507
|
}
|
|
4508
|
+
var HOISTABLE_TAGS = /* @__PURE__ */ new Set([
|
|
4509
|
+
"sequence",
|
|
4510
|
+
"choice",
|
|
4511
|
+
"many",
|
|
4512
|
+
"oneOrMore",
|
|
4513
|
+
"optional",
|
|
4514
|
+
"sepBy",
|
|
4515
|
+
"transform",
|
|
4516
|
+
"node",
|
|
4517
|
+
"not"
|
|
4518
|
+
]);
|
|
4519
|
+
function isHoistableTag(tag) {
|
|
4520
|
+
return HOISTABLE_TAGS.has(tag);
|
|
4521
|
+
}
|
|
4522
|
+
var HOIST_MIN_SUBTREE = 3;
|
|
4425
4523
|
function analyzeLazyUsage(root) {
|
|
4426
4524
|
return analyzeLazyUsageMulti([root]);
|
|
4427
4525
|
}
|
|
4526
|
+
function subtreeSizes(roots) {
|
|
4527
|
+
const sizes = /* @__PURE__ */ new Map();
|
|
4528
|
+
const sz = (p) => {
|
|
4529
|
+
const cached = sizes.get(p);
|
|
4530
|
+
if (cached !== void 0) return cached;
|
|
4531
|
+
const def = p._def;
|
|
4532
|
+
let s = 1;
|
|
4533
|
+
if (def.tag !== "lazy") {
|
|
4534
|
+
for (const child of childrenOf(def)) s += child._def.tag === "lazy" ? 1 : sz(child);
|
|
4535
|
+
}
|
|
4536
|
+
sizes.set(p, s);
|
|
4537
|
+
return s;
|
|
4538
|
+
};
|
|
4539
|
+
const visitedLazy = /* @__PURE__ */ new Set();
|
|
4540
|
+
const visit = (p) => {
|
|
4541
|
+
const def = p._def;
|
|
4542
|
+
if (def.tag === "lazy") {
|
|
4543
|
+
if (visitedLazy.has(p)) return;
|
|
4544
|
+
visitedLazy.add(p);
|
|
4545
|
+
let resolved;
|
|
4546
|
+
try {
|
|
4547
|
+
resolved = def.thunk();
|
|
4548
|
+
} catch {
|
|
4549
|
+
return;
|
|
4550
|
+
}
|
|
4551
|
+
visit(resolved);
|
|
4552
|
+
return;
|
|
4553
|
+
}
|
|
4554
|
+
sz(p);
|
|
4555
|
+
for (const child of childrenOf(def)) visit(child);
|
|
4556
|
+
};
|
|
4557
|
+
for (const root of roots) visit(root);
|
|
4558
|
+
return sizes;
|
|
4559
|
+
}
|
|
4428
4560
|
function analyzeLazyUsageMulti(roots) {
|
|
4429
4561
|
const counts = /* @__PURE__ */ new Map();
|
|
4430
4562
|
const recursive = /* @__PURE__ */ new Set();
|
|
@@ -4451,10 +4583,14 @@ function analyzeLazyUsageMulti(roots) {
|
|
|
4451
4583
|
active.delete(p);
|
|
4452
4584
|
return;
|
|
4453
4585
|
}
|
|
4586
|
+
if (isHoistableTag(def.tag)) {
|
|
4587
|
+
counts.set(p, (counts.get(p) ?? 0) + 1);
|
|
4588
|
+
}
|
|
4454
4589
|
for (const child of childrenOf(def)) walk2(child);
|
|
4455
4590
|
}
|
|
4456
|
-
|
|
4457
|
-
|
|
4591
|
+
const rootsArr = [...roots];
|
|
4592
|
+
for (const root of rootsArr) walk2(root);
|
|
4593
|
+
return { counts, recursive, sizes: subtreeSizes(rootsArr) };
|
|
4458
4594
|
}
|
|
4459
4595
|
function ruleDependencies(ruleMap) {
|
|
4460
4596
|
const nameOf = /* @__PURE__ */ new Map();
|
|
@@ -4780,6 +4916,172 @@ function buildInlineExpression(ctx, r, mapFnSources, buildSources) {
|
|
|
4780
4916
|
].join("\n");
|
|
4781
4917
|
}
|
|
4782
4918
|
|
|
4919
|
+
// src/combinators/scanTo.ts
|
|
4920
|
+
function scanTo(sentinel, { skip: skip2 = [], orEOF = false } = {}) {
|
|
4921
|
+
const meta = {
|
|
4922
|
+
firstSet: any(),
|
|
4923
|
+
canMatchNewline: true,
|
|
4924
|
+
isTrivia: false
|
|
4925
|
+
};
|
|
4926
|
+
return {
|
|
4927
|
+
_tag: "scanTo",
|
|
4928
|
+
_meta: meta,
|
|
4929
|
+
_def: { tag: "scanTo", sentinel, skip: skip2, orEOF },
|
|
4930
|
+
parse(input, pos, ctx) {
|
|
4931
|
+
let cur = pos;
|
|
4932
|
+
const probeCtx = {
|
|
4933
|
+
trackLines: ctx.trackLines,
|
|
4934
|
+
state: ctx.state,
|
|
4935
|
+
...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
|
|
4936
|
+
};
|
|
4937
|
+
const emit2 = (end) => {
|
|
4938
|
+
if (end > pos && cstCaptureActive(ctx)) {
|
|
4939
|
+
const leaf = { _tag: "leaf", value: input.slice(pos, end), span: { start: pos, end } };
|
|
4940
|
+
pushCstLeaf(ctx, leaf);
|
|
4941
|
+
}
|
|
4942
|
+
};
|
|
4943
|
+
while (cur < input.length) {
|
|
4944
|
+
const s = sentinel.parse(input, cur, probeCtx);
|
|
4945
|
+
if (s.ok) {
|
|
4946
|
+
emit2(cur);
|
|
4947
|
+
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
4948
|
+
}
|
|
4949
|
+
let advanced = false;
|
|
4950
|
+
for (const skipper of skip2) {
|
|
4951
|
+
const r = skipper.parse(input, cur, probeCtx);
|
|
4952
|
+
if (r.ok && r.span.end > cur) {
|
|
4953
|
+
cur = r.span.end;
|
|
4954
|
+
advanced = true;
|
|
4955
|
+
break;
|
|
4956
|
+
}
|
|
4957
|
+
}
|
|
4958
|
+
if (!advanced) cur++;
|
|
4959
|
+
}
|
|
4960
|
+
if (orEOF) {
|
|
4961
|
+
emit2(cur);
|
|
4962
|
+
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
4963
|
+
}
|
|
4964
|
+
const sentDef = sentinel._def;
|
|
4965
|
+
const expected = sentDef.tag === "literal" ? [JSON.stringify(sentDef.value)] : ["sentinel"];
|
|
4966
|
+
return { ok: false, expected, span: { start: pos, end: cur } };
|
|
4967
|
+
}
|
|
4968
|
+
};
|
|
4969
|
+
}
|
|
4970
|
+
function balanced(open, close, options = {}) {
|
|
4971
|
+
const self = ref();
|
|
4972
|
+
const skips = options.skip ?? [];
|
|
4973
|
+
const stop = /* @__PURE__ */ new Set([open, close]);
|
|
4974
|
+
let bounded = true;
|
|
4975
|
+
for (const sk of skips) {
|
|
4976
|
+
const cs = firstSetClassChars(sk);
|
|
4977
|
+
if (cs === null) {
|
|
4978
|
+
bounded = false;
|
|
4979
|
+
break;
|
|
4980
|
+
}
|
|
4981
|
+
for (const ch of cs) stop.add(ch);
|
|
4982
|
+
}
|
|
4983
|
+
const cls = [...stop].map(escapeClassChar).join("");
|
|
4984
|
+
const content = bounded ? regex(new RegExp(`[^${cls}]+`)) : regex(new RegExp(`[^${escapeClassChar(open)}${escapeClassChar(close)}]`));
|
|
4985
|
+
const inner = many(choice(self, ...skips, content));
|
|
4986
|
+
const combi = transform(
|
|
4987
|
+
sequence(literal(open), inner, expect(literal(close), close)),
|
|
4988
|
+
// parts: strings (content/self) or arrays (a sequence-shaped skip) or a
|
|
4989
|
+
// ParseError (recovered close). `c` is the close string or a ParseError.
|
|
4990
|
+
([o, parts, c]) => o + parts.map((p) => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")
|
|
4991
|
+
);
|
|
4992
|
+
if (combi._def.tag === "transform") {
|
|
4993
|
+
combi._def.fnSrc = '([o, parts, c]) => o + parts.map(p => typeof p === "string" ? p : Array.isArray(p) ? p.join("") : "").join("") + (typeof c === "string" ? c : "")';
|
|
4994
|
+
}
|
|
4995
|
+
self.define(combi);
|
|
4996
|
+
return combi;
|
|
4997
|
+
}
|
|
4998
|
+
function firstSetClassChars(c) {
|
|
4999
|
+
const fs = c._meta.firstSet;
|
|
5000
|
+
if (fs.kind === "empty") return [];
|
|
5001
|
+
if (fs.kind !== "ranges") return null;
|
|
5002
|
+
const out = [];
|
|
5003
|
+
for (const { lo, hi } of fs.ranges) {
|
|
5004
|
+
if (hi - lo > 8) return null;
|
|
5005
|
+
for (let cp = lo; cp <= hi; cp++) out.push(String.fromCodePoint(cp));
|
|
5006
|
+
}
|
|
5007
|
+
return out;
|
|
5008
|
+
}
|
|
5009
|
+
function escapeClassChar(ch) {
|
|
5010
|
+
return ch.replace(/[\\\]^-]/g, "\\$&");
|
|
5011
|
+
}
|
|
5012
|
+
|
|
5013
|
+
// src/compiler/ir-serialize.ts
|
|
5014
|
+
function evalRuleMapIR(ir) {
|
|
5015
|
+
const _tf = (child, src) => {
|
|
5016
|
+
let fn2;
|
|
5017
|
+
try {
|
|
5018
|
+
fn2 = (0, eval)(`(${src})`);
|
|
5019
|
+
} catch {
|
|
5020
|
+
fn2 = () => {
|
|
5021
|
+
throw new Error("IR transform fn not materialized");
|
|
5022
|
+
};
|
|
5023
|
+
}
|
|
5024
|
+
const t = transform(child, fn2);
|
|
5025
|
+
t._def.fnSrc = src;
|
|
5026
|
+
return t;
|
|
5027
|
+
};
|
|
5028
|
+
const _nd = (type, child, src, opts) => {
|
|
5029
|
+
const n = node(type, child, void 0, opts);
|
|
5030
|
+
n._def.buildSrc = src;
|
|
5031
|
+
return n;
|
|
5032
|
+
};
|
|
5033
|
+
const fn = new Function(
|
|
5034
|
+
"rules",
|
|
5035
|
+
"ref",
|
|
5036
|
+
"regex",
|
|
5037
|
+
"literal",
|
|
5038
|
+
"keywords",
|
|
5039
|
+
"sequence",
|
|
5040
|
+
"choice",
|
|
5041
|
+
"many",
|
|
5042
|
+
"oneOrMore",
|
|
5043
|
+
"optional",
|
|
5044
|
+
"sepBy",
|
|
5045
|
+
"not",
|
|
5046
|
+
"node",
|
|
5047
|
+
"parser",
|
|
5048
|
+
"scanTo",
|
|
5049
|
+
"transform",
|
|
5050
|
+
"skip",
|
|
5051
|
+
"trivia",
|
|
5052
|
+
"label",
|
|
5053
|
+
"expect",
|
|
5054
|
+
"_tf",
|
|
5055
|
+
"_nd",
|
|
5056
|
+
`return (${ir})`
|
|
5057
|
+
);
|
|
5058
|
+
const map = fn(
|
|
5059
|
+
rules,
|
|
5060
|
+
ref,
|
|
5061
|
+
regex,
|
|
5062
|
+
literal,
|
|
5063
|
+
keywords,
|
|
5064
|
+
sequence,
|
|
5065
|
+
choice,
|
|
5066
|
+
many,
|
|
5067
|
+
oneOrMore,
|
|
5068
|
+
optional,
|
|
5069
|
+
sepBy,
|
|
5070
|
+
not,
|
|
5071
|
+
node,
|
|
5072
|
+
parser,
|
|
5073
|
+
scanTo,
|
|
5074
|
+
transform,
|
|
5075
|
+
skip,
|
|
5076
|
+
trivia,
|
|
5077
|
+
label,
|
|
5078
|
+
expect,
|
|
5079
|
+
_tf,
|
|
5080
|
+
_nd
|
|
5081
|
+
);
|
|
5082
|
+
return Object.entries(map);
|
|
5083
|
+
}
|
|
5084
|
+
|
|
4783
5085
|
// src/compiler/linker.ts
|
|
4784
5086
|
var _nsCounter = 0;
|
|
4785
5087
|
function linkable(rulesMap, ns) {
|
|
@@ -4864,9 +5166,18 @@ function fuseRules(pieces) {
|
|
|
4864
5166
|
return new Function("_env", body)(env);
|
|
4865
5167
|
}
|
|
4866
5168
|
var COMPOSED_PIECES = /* @__PURE__ */ Symbol.for("parseman.composedPieces");
|
|
5169
|
+
function isIRPiece(p) {
|
|
5170
|
+
return !!p && typeof p === "object" && typeof p.ir === "string" && typeof p.ns === "string" && !("ruleFns" in p);
|
|
5171
|
+
}
|
|
5172
|
+
function materializePiece(p) {
|
|
5173
|
+
if (!isIRPiece(p)) return p;
|
|
5174
|
+
const pieces = compileLinkable(evalRuleMapIR(p.ir), p.ns);
|
|
5175
|
+
if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
|
|
5176
|
+
return pieces;
|
|
5177
|
+
}
|
|
4867
5178
|
function itemPieces(item) {
|
|
4868
5179
|
const carried = item[COMPOSED_PIECES];
|
|
4869
|
-
if (Array.isArray(carried)) return carried;
|
|
5180
|
+
if (Array.isArray(carried)) return carried.map(materializePiece);
|
|
4870
5181
|
if (item.ruleFns instanceof Map) return [item];
|
|
4871
5182
|
return [linkable(item)];
|
|
4872
5183
|
}
|
|
@@ -4962,100 +5273,6 @@ function deeperFail(a, b) {
|
|
|
4962
5273
|
return a.span.start >= b.span.start ? a : b;
|
|
4963
5274
|
}
|
|
4964
5275
|
|
|
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
5276
|
// src/combinators/recover-list.ts
|
|
5060
5277
|
function tolerantElement(item, sentinel, until) {
|
|
5061
5278
|
const el = transform(
|