parseman 0.18.1 → 0.19.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 +7 -3
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/literal.d.ts.map +1 -1
- package/dist/combinators/map.d.ts +5 -0
- package/dist/combinators/map.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +14 -13
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/combinators/ref.d.ts.map +1 -1
- package/dist/combinators/regex.d.ts.map +1 -1
- package/dist/combinators/repeat.d.ts.map +1 -1
- package/dist/combinators/trivia-skip.d.ts +1 -0
- package/dist/combinators/trivia-skip.d.ts.map +1 -1
- package/dist/compiler/build-arity.d.ts +3 -3
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/fields.d.ts +16 -0
- package/dist/compiler/fields.d.ts.map +1 -0
- package/dist/compiler/inline-build.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +17 -3
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/compiler/value-usage.d.ts.map +1 -1
- package/dist/cst/capture-buffer.d.ts +1 -0
- package/dist/cst/capture-buffer.d.ts.map +1 -1
- package/dist/index.cjs +498 -78
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +498 -78
- package/dist/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +498 -86
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.js +498 -86
- package/dist/plugin/index.js.map +4 -4
- package/dist/types.d.ts +31 -8
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -1
package/dist/index.cjs
CHANGED
|
@@ -49,6 +49,7 @@ __export(index_exports, {
|
|
|
49
49
|
createVisitor: () => createVisitor,
|
|
50
50
|
cstBuildHost: () => cstBuildHost,
|
|
51
51
|
expect: () => expect,
|
|
52
|
+
field: () => field,
|
|
52
53
|
gapIsSignificant: () => gapIsSignificant,
|
|
53
54
|
gapText: () => gapText,
|
|
54
55
|
guard: () => guard,
|
|
@@ -349,7 +350,8 @@ function saveCstMark(ctx) {
|
|
|
349
350
|
return {
|
|
350
351
|
raw: cstRawLen(ctx),
|
|
351
352
|
tlog: cstTlLen(ctx),
|
|
352
|
-
leaves: cstLeavesLen(ctx)
|
|
353
|
+
leaves: cstLeavesLen(ctx),
|
|
354
|
+
fields: ctx._fields?.length ?? 0
|
|
353
355
|
};
|
|
354
356
|
}
|
|
355
357
|
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
@@ -373,11 +375,13 @@ function rollbackCstCapture(ctx, mark) {
|
|
|
373
375
|
if (mark.tlog === 0) b.tl = void 0;
|
|
374
376
|
else b.tl.length = mark.tlog;
|
|
375
377
|
}
|
|
378
|
+
if (ctx._fields) ctx._fields.length = mark.fields;
|
|
376
379
|
return;
|
|
377
380
|
}
|
|
378
381
|
if (ctx._cstRawChildren) ctx._cstRawChildren.length = mark.raw;
|
|
379
382
|
if (ctx._cstTriviaLog) ctx._cstTriviaLog.length = mark.tlog;
|
|
380
383
|
if (ctx._cstLeaves) ctx._cstLeaves.length = mark.leaves;
|
|
384
|
+
if (ctx._fields) ctx._fields.length = mark.fields;
|
|
381
385
|
}
|
|
382
386
|
function pushCstTriviaEntry(ctx, start, end, kindIndex) {
|
|
383
387
|
const insertIdx = cstRawLen(ctx);
|
|
@@ -446,13 +450,12 @@ function literal(value, opts = {}) {
|
|
|
446
450
|
if (end > input.length) {
|
|
447
451
|
return failAt(ctx, [JSON.stringify(value)], pos);
|
|
448
452
|
}
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
if (matched) {
|
|
453
|
+
const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
|
|
454
|
+
if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
|
|
452
455
|
const span = { start: pos, end };
|
|
453
|
-
const leaf = { _tag: "leaf", value:
|
|
456
|
+
const leaf = { _tag: "leaf", value: matchedValue, span };
|
|
454
457
|
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf);
|
|
455
|
-
return { ok: true, value:
|
|
458
|
+
return { ok: true, value: matchedValue, span };
|
|
456
459
|
}
|
|
457
460
|
return failAt(ctx, [JSON.stringify(value)], pos);
|
|
458
461
|
}
|
|
@@ -465,10 +468,102 @@ function registerRegexAnalyzer(analyzer) {
|
|
|
465
468
|
firstSetAnalyzer = analyzer;
|
|
466
469
|
}
|
|
467
470
|
var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
|
|
471
|
+
var SCAN_BAIL_AT = 64;
|
|
472
|
+
var SPACE_RANGES = [
|
|
473
|
+
[9, 13],
|
|
474
|
+
[32, 32],
|
|
475
|
+
[160, 160],
|
|
476
|
+
[5760, 5760],
|
|
477
|
+
[8192, 8202],
|
|
478
|
+
[8232, 8233],
|
|
479
|
+
[8239, 8239],
|
|
480
|
+
[8287, 8287],
|
|
481
|
+
[12288, 12288],
|
|
482
|
+
[65279, 65279]
|
|
483
|
+
];
|
|
484
|
+
var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
485
|
+
function shorthandRanges(ch) {
|
|
486
|
+
if (ch === "d") return [[48, 57]];
|
|
487
|
+
if (ch === "s") return SPACE_RANGES;
|
|
488
|
+
return [[48, 57], [65, 90], [97, 122], [95, 95]];
|
|
489
|
+
}
|
|
490
|
+
function inRanges(cp, ranges) {
|
|
491
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
492
|
+
const [lo, hi] = ranges[i];
|
|
493
|
+
if (cp >= lo && cp <= hi) return true;
|
|
494
|
+
}
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
function readClassRanges(body) {
|
|
498
|
+
if (body.startsWith("^")) return null;
|
|
499
|
+
const ranges = [];
|
|
500
|
+
let i = 0;
|
|
501
|
+
const readAtom = () => {
|
|
502
|
+
const ch = body[i];
|
|
503
|
+
if (ch === void 0) return null;
|
|
504
|
+
if (ch === "\\") {
|
|
505
|
+
const esc = body[i + 1];
|
|
506
|
+
if (esc === void 0) return null;
|
|
507
|
+
i += 2;
|
|
508
|
+
if (esc === "d" || esc === "w" || esc === "s") return { ranges: shorthandRanges(esc) };
|
|
509
|
+
if (esc in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[esc] };
|
|
510
|
+
if (esc >= "a" && esc <= "z" || esc >= "A" && esc <= "Z") return null;
|
|
511
|
+
return { cp: esc.charCodeAt(0) };
|
|
512
|
+
}
|
|
513
|
+
i++;
|
|
514
|
+
return { cp: ch.charCodeAt(0) };
|
|
515
|
+
};
|
|
516
|
+
while (i < body.length) {
|
|
517
|
+
const lo = readAtom();
|
|
518
|
+
if (!lo) return null;
|
|
519
|
+
if ("ranges" in lo) {
|
|
520
|
+
ranges.push(...lo.ranges);
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
524
|
+
i++;
|
|
525
|
+
const hi = readAtom();
|
|
526
|
+
if (!hi || "ranges" in hi) return null;
|
|
527
|
+
ranges.push([lo.cp, hi.cp]);
|
|
528
|
+
} else {
|
|
529
|
+
ranges.push([lo.cp, lo.cp]);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
return ranges.length ? ranges : null;
|
|
533
|
+
}
|
|
534
|
+
function shortScanner(source, flags) {
|
|
535
|
+
if (/[imsuvy]/.test(flags)) return null;
|
|
536
|
+
let ranges = null;
|
|
537
|
+
let quant = "";
|
|
538
|
+
if (source[0] === "[") {
|
|
539
|
+
let end = 1;
|
|
540
|
+
while (end < source.length && source[end] !== "]") {
|
|
541
|
+
if (source[end] === "\\") end += 2;
|
|
542
|
+
else end++;
|
|
543
|
+
}
|
|
544
|
+
if (source[end] !== "]") return null;
|
|
545
|
+
ranges = readClassRanges(source.slice(1, end));
|
|
546
|
+
quant = source.slice(end + 1);
|
|
547
|
+
} else if (source[0] === "\\" && (source[1] === "d" || source[1] === "w" || source[1] === "s")) {
|
|
548
|
+
ranges = shorthandRanges(source[1]);
|
|
549
|
+
quant = source.slice(2);
|
|
550
|
+
}
|
|
551
|
+
if (!ranges || quant !== "+" && quant !== "*") return null;
|
|
552
|
+
const minOne = quant === "+";
|
|
553
|
+
return (input, pos) => {
|
|
554
|
+
let end = pos;
|
|
555
|
+
while (end < input.length && inRanges(input.charCodeAt(end), ranges)) {
|
|
556
|
+
end++;
|
|
557
|
+
if (end - pos >= SCAN_BAIL_AT) return void 0;
|
|
558
|
+
}
|
|
559
|
+
return minOne && end === pos ? null : end;
|
|
560
|
+
};
|
|
561
|
+
}
|
|
468
562
|
function regex(pattern, flags = "") {
|
|
469
563
|
const source = typeof pattern === "string" ? pattern : pattern.source;
|
|
470
564
|
const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
|
|
471
565
|
const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
|
|
566
|
+
const scan = shortScanner(source, resolvedFlags);
|
|
472
567
|
const { firstSet, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
|
|
473
568
|
const meta = { firstSet, canMatchNewline, isTrivia: false };
|
|
474
569
|
return {
|
|
@@ -476,6 +571,15 @@ function regex(pattern, flags = "") {
|
|
|
476
571
|
_meta: meta,
|
|
477
572
|
_def: { tag: "regex", source, flags: resolvedFlags },
|
|
478
573
|
parse(input, pos, ctx) {
|
|
574
|
+
const scanEnd = scan?.(input, pos);
|
|
575
|
+
if (scanEnd !== void 0) {
|
|
576
|
+
if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
|
|
577
|
+
const value = input.slice(pos, scanEnd);
|
|
578
|
+
const span2 = { start: pos, end: scanEnd };
|
|
579
|
+
const leaf2 = { _tag: "leaf", value, span: span2 };
|
|
580
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, leaf2);
|
|
581
|
+
return { ok: true, value, span: span2 };
|
|
582
|
+
}
|
|
479
583
|
anchored.lastIndex = pos;
|
|
480
584
|
const m = anchored.exec(input);
|
|
481
585
|
if (m === null) {
|
|
@@ -659,13 +763,10 @@ function choice(...args) {
|
|
|
659
763
|
};
|
|
660
764
|
const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
|
|
661
765
|
const autoNot = !disjoint && !hasGates && strategy?.tag === "firstMatch" ? computeAutoNot(parsers) : parsers.map(() => null);
|
|
662
|
-
let greedyRe = null;
|
|
663
766
|
let greedyLitMap = null;
|
|
664
767
|
let sortedParsers = null;
|
|
768
|
+
const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
|
|
665
769
|
if (strategy?.tag === "greedyClassify") {
|
|
666
|
-
const regexDef = getCoreRegexDef(parsers[strategy.superIndex]);
|
|
667
|
-
const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
|
|
668
|
-
greedyRe = new RegExp(regexDef.source, flags);
|
|
669
770
|
greedyLitMap = /* @__PURE__ */ new Map();
|
|
670
771
|
for (let i = 0; i < parsers.length; i++) {
|
|
671
772
|
if (i === strategy.superIndex) continue;
|
|
@@ -690,14 +791,21 @@ function choice(...args) {
|
|
|
690
791
|
const expected = [];
|
|
691
792
|
if (disjoint && pos < input.length) {
|
|
692
793
|
const code = input.codePointAt(pos);
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
if (
|
|
697
|
-
|
|
698
|
-
|
|
794
|
+
let parser2 = code < 128 ? asciiDispatch?.[code] ?? null : null;
|
|
795
|
+
if (!parser2) {
|
|
796
|
+
for (const p of parsers) {
|
|
797
|
+
if (inFirstSet(code, p._meta.firstSet)) {
|
|
798
|
+
parser2 = p;
|
|
799
|
+
break;
|
|
800
|
+
}
|
|
699
801
|
}
|
|
700
802
|
}
|
|
803
|
+
if (parser2) {
|
|
804
|
+
const result = parser2.parse(input, pos, ctx);
|
|
805
|
+
if (result.ok) return result;
|
|
806
|
+
expected.push(...result.expected);
|
|
807
|
+
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
808
|
+
}
|
|
701
809
|
return {
|
|
702
810
|
ok: false,
|
|
703
811
|
expected: parsers.flatMap((p) => {
|
|
@@ -873,6 +981,19 @@ function areDisjoint(sets) {
|
|
|
873
981
|
if (intersects(sets[i], sets[j])) return false;
|
|
874
982
|
return true;
|
|
875
983
|
}
|
|
984
|
+
function buildAsciiDispatch(parsers) {
|
|
985
|
+
const table = Array(128).fill(null);
|
|
986
|
+
for (const parser2 of parsers) {
|
|
987
|
+
const fs = parser2._meta.firstSet;
|
|
988
|
+
if (fs.kind !== "ranges") continue;
|
|
989
|
+
for (const { lo, hi } of fs.ranges) {
|
|
990
|
+
for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
|
|
991
|
+
table[code] = parser2;
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
return table;
|
|
996
|
+
}
|
|
876
997
|
|
|
877
998
|
// src/cst/trivia-kinds.ts
|
|
878
999
|
function unwrapTrivia(p) {
|
|
@@ -994,15 +1115,16 @@ function recordTriviaChunks(ctx, chunks) {
|
|
|
994
1115
|
// src/combinators/trivia-skip.ts
|
|
995
1116
|
var NOOP_COMMIT = () => {
|
|
996
1117
|
};
|
|
1118
|
+
var fastTriviaCache = /* @__PURE__ */ new WeakMap();
|
|
997
1119
|
function needsDeferredTriviaCommit(ctx) {
|
|
998
1120
|
return ctx._triviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
|
|
999
1121
|
}
|
|
1000
1122
|
function saveTriviaMark(ctx) {
|
|
1001
1123
|
const m = saveCstMark(ctx);
|
|
1002
|
-
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1124
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1003
1125
|
}
|
|
1004
1126
|
function rollbackTrivia(ctx, mark) {
|
|
1005
|
-
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves });
|
|
1127
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields });
|
|
1006
1128
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1007
1129
|
}
|
|
1008
1130
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1020,6 +1142,8 @@ function scanWithLabels(input, cur, ctx) {
|
|
|
1020
1142
|
function advanceTrivia(input, cur, ctx) {
|
|
1021
1143
|
const triviaP = ctx.trivia;
|
|
1022
1144
|
if (!triviaP) return cur;
|
|
1145
|
+
const fast = fastTriviaScanner(triviaP);
|
|
1146
|
+
if (fast) return fast(input, cur);
|
|
1023
1147
|
if (ctx.triviaKindLabels) {
|
|
1024
1148
|
const scan = scanWithLabels(input, cur, ctx);
|
|
1025
1149
|
return scan.end;
|
|
@@ -1032,6 +1156,10 @@ function scanTrivia(input, cur, ctx) {
|
|
|
1032
1156
|
if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
|
|
1033
1157
|
const log = ctx._triviaLog;
|
|
1034
1158
|
const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
|
|
1159
|
+
const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
|
|
1160
|
+
if (fast && log === void 0 && !captureTl) {
|
|
1161
|
+
return { end: fast(input, cur), commit: NOOP_COMMIT };
|
|
1162
|
+
}
|
|
1035
1163
|
if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
|
|
1036
1164
|
return scanWithLabels(input, cur, ctx);
|
|
1037
1165
|
}
|
|
@@ -1053,6 +1181,79 @@ function scanTrivia(input, cur, ctx) {
|
|
|
1053
1181
|
const tr = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1054
1182
|
return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
|
|
1055
1183
|
}
|
|
1184
|
+
function fastTriviaScanner(trivia2) {
|
|
1185
|
+
const cached = fastTriviaCache.get(trivia2);
|
|
1186
|
+
if (cached !== void 0) return cached;
|
|
1187
|
+
const scanner = buildFastTriviaScanner(trivia2);
|
|
1188
|
+
fastTriviaCache.set(trivia2, scanner);
|
|
1189
|
+
return scanner;
|
|
1190
|
+
}
|
|
1191
|
+
function buildFastTriviaScanner(trivia2) {
|
|
1192
|
+
const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
|
|
1193
|
+
const direct = regexTriviaScanner(core);
|
|
1194
|
+
if (direct) return direct;
|
|
1195
|
+
const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
|
|
1196
|
+
if (!repeat) return null;
|
|
1197
|
+
const one = regexTriviaScanner(repeat);
|
|
1198
|
+
if (one) return loopScanner([one]);
|
|
1199
|
+
if (repeat._def.tag !== "choice") return null;
|
|
1200
|
+
const arms = repeat._def.parsers.map(regexTriviaScanner);
|
|
1201
|
+
if (arms.some((s) => s === null)) return null;
|
|
1202
|
+
return loopScanner(arms);
|
|
1203
|
+
}
|
|
1204
|
+
function loopScanner(arms) {
|
|
1205
|
+
return (input, cur) => {
|
|
1206
|
+
let pos = cur;
|
|
1207
|
+
scan: while (pos < input.length) {
|
|
1208
|
+
for (const arm of arms) {
|
|
1209
|
+
const end = arm(input, pos);
|
|
1210
|
+
if (end > pos) {
|
|
1211
|
+
pos = end;
|
|
1212
|
+
continue scan;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
break;
|
|
1216
|
+
}
|
|
1217
|
+
return pos;
|
|
1218
|
+
};
|
|
1219
|
+
}
|
|
1220
|
+
function regexTriviaScanner(parser2) {
|
|
1221
|
+
if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
|
|
1222
|
+
const ws = whitespaceSource(parser2._def.source);
|
|
1223
|
+
if (ws) return ws;
|
|
1224
|
+
return blockCommentSource(parser2._def.source) ? scanBlockComment : null;
|
|
1225
|
+
}
|
|
1226
|
+
function whitespaceSource(source) {
|
|
1227
|
+
const m = /^\[([ \\tnrf]+)\][*+]$/.exec(source);
|
|
1228
|
+
if (!m) return null;
|
|
1229
|
+
const chars = /* @__PURE__ */ new Set();
|
|
1230
|
+
for (let i = 0; i < m[1].length; i++) {
|
|
1231
|
+
const ch = m[1][i];
|
|
1232
|
+
if (ch !== "\\") {
|
|
1233
|
+
chars.add(ch.charCodeAt(0));
|
|
1234
|
+
continue;
|
|
1235
|
+
}
|
|
1236
|
+
const esc = m[1][++i];
|
|
1237
|
+
if (esc === "t") chars.add(9);
|
|
1238
|
+
else if (esc === "n") chars.add(10);
|
|
1239
|
+
else if (esc === "r") chars.add(13);
|
|
1240
|
+
else if (esc === "f") chars.add(12);
|
|
1241
|
+
else return null;
|
|
1242
|
+
}
|
|
1243
|
+
return (input, cur) => {
|
|
1244
|
+
let pos = cur;
|
|
1245
|
+
while (pos < input.length && chars.has(input.charCodeAt(pos))) pos++;
|
|
1246
|
+
return pos;
|
|
1247
|
+
};
|
|
1248
|
+
}
|
|
1249
|
+
function blockCommentSource(source) {
|
|
1250
|
+
return source === "\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/" || source === "\\/\\*[^]*?\\*\\/";
|
|
1251
|
+
}
|
|
1252
|
+
function scanBlockComment(input, cur) {
|
|
1253
|
+
if (input.charCodeAt(cur) !== 47 || input.charCodeAt(cur + 1) !== 42) return cur;
|
|
1254
|
+
const close = input.indexOf("*/", cur + 2);
|
|
1255
|
+
return close === -1 ? cur : close + 2;
|
|
1256
|
+
}
|
|
1056
1257
|
|
|
1057
1258
|
// src/combinators/sequence.ts
|
|
1058
1259
|
function sequence(...parsers) {
|
|
@@ -1191,11 +1392,15 @@ function optional(combinator) {
|
|
|
1191
1392
|
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1192
1393
|
isTrivia: false
|
|
1193
1394
|
};
|
|
1395
|
+
const firstSetSkippable = !matchesEmpty(combinator);
|
|
1194
1396
|
return {
|
|
1195
1397
|
_tag: "optional",
|
|
1196
1398
|
_meta: meta,
|
|
1197
1399
|
_def: { tag: "optional", parser: combinator },
|
|
1198
1400
|
parse(input, pos, ctx) {
|
|
1401
|
+
if (firstSetSkippable && ctx._probe === void 0 && !startsFirstSet(combinator, input, pos)) {
|
|
1402
|
+
return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
1403
|
+
}
|
|
1199
1404
|
const mark = saveTriviaMark(ctx);
|
|
1200
1405
|
const result = combinator.parse(input, pos, ctx);
|
|
1201
1406
|
if (result.ok) return result;
|
|
@@ -1204,6 +1409,15 @@ function optional(combinator) {
|
|
|
1204
1409
|
}
|
|
1205
1410
|
};
|
|
1206
1411
|
}
|
|
1412
|
+
function startsFirstSet(combinator, input, pos) {
|
|
1413
|
+
const fs = combinator._meta.firstSet;
|
|
1414
|
+
if (fs.kind === "any") return true;
|
|
1415
|
+
if (fs.kind === "empty") return false;
|
|
1416
|
+
const code = input.codePointAt(pos);
|
|
1417
|
+
if (code === void 0) return false;
|
|
1418
|
+
for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
1419
|
+
return false;
|
|
1420
|
+
}
|
|
1207
1421
|
function sepBy(combinator, separator) {
|
|
1208
1422
|
const meta = {
|
|
1209
1423
|
firstSet: combinator._meta.firstSet,
|
|
@@ -1284,6 +1498,13 @@ function ref() {
|
|
|
1284
1498
|
define(p) {
|
|
1285
1499
|
if (resolved) throw new Error("ref<T>() already defined");
|
|
1286
1500
|
resolved = p;
|
|
1501
|
+
meta.firstSet = p._meta.firstSet;
|
|
1502
|
+
meta.canMatchNewline = p._meta.canMatchNewline;
|
|
1503
|
+
meta.isTrivia = p._meta.isTrivia;
|
|
1504
|
+
if (p._meta.triviaKindLabels !== void 0) meta.triviaKindLabels = p._meta.triviaKindLabels;
|
|
1505
|
+
else delete meta.triviaKindLabels;
|
|
1506
|
+
if (p._meta.disjoint !== void 0) meta.disjoint = p._meta.disjoint;
|
|
1507
|
+
else delete meta.disjoint;
|
|
1287
1508
|
}
|
|
1288
1509
|
};
|
|
1289
1510
|
return slot;
|
|
@@ -1324,6 +1545,9 @@ function markUnusedValues(root) {
|
|
|
1324
1545
|
case "transform":
|
|
1325
1546
|
visit(def.parser, true);
|
|
1326
1547
|
return;
|
|
1548
|
+
case "field":
|
|
1549
|
+
visit(def.parser, true);
|
|
1550
|
+
return;
|
|
1327
1551
|
case "skip":
|
|
1328
1552
|
visit(def.main, consumed);
|
|
1329
1553
|
visit(def.skipped, false);
|
|
@@ -1375,6 +1599,11 @@ function markUnusedValues(root) {
|
|
|
1375
1599
|
}
|
|
1376
1600
|
|
|
1377
1601
|
// src/combinators/parser.ts
|
|
1602
|
+
function tagRule(r, key) {
|
|
1603
|
+
;
|
|
1604
|
+
r._ruleName = key;
|
|
1605
|
+
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
|
|
1606
|
+
}
|
|
1378
1607
|
function rules(factory) {
|
|
1379
1608
|
const cache = {};
|
|
1380
1609
|
const proxy = new Proxy(cache, {
|
|
@@ -1383,7 +1612,7 @@ function rules(factory) {
|
|
|
1383
1612
|
const record = target;
|
|
1384
1613
|
if (!(key in record)) {
|
|
1385
1614
|
const r = ref();
|
|
1386
|
-
r
|
|
1615
|
+
tagRule(r, key);
|
|
1387
1616
|
record[key] = r;
|
|
1388
1617
|
}
|
|
1389
1618
|
return record[key];
|
|
@@ -1394,12 +1623,12 @@ function rules(factory) {
|
|
|
1394
1623
|
const placeholder = cache[key];
|
|
1395
1624
|
const parser2 = definitions[key];
|
|
1396
1625
|
if (placeholder !== void 0 && typeof placeholder.define === "function") {
|
|
1397
|
-
;
|
|
1626
|
+
tagRule(parser2, key);
|
|
1398
1627
|
placeholder.define(parser2);
|
|
1399
1628
|
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
1400
1629
|
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
1401
1630
|
} else {
|
|
1402
|
-
;
|
|
1631
|
+
tagRule(parser2, key);
|
|
1403
1632
|
cache[key] = parser2;
|
|
1404
1633
|
}
|
|
1405
1634
|
}
|
|
@@ -1456,44 +1685,130 @@ function buildReadsTrivia(def) {
|
|
|
1456
1685
|
const src = def.buildSrc ?? def.build.toString();
|
|
1457
1686
|
const arity = confirmedBuildArity(src);
|
|
1458
1687
|
if (arity === null) return true;
|
|
1459
|
-
return arity >=
|
|
1688
|
+
return arity >= 5;
|
|
1460
1689
|
}
|
|
1461
1690
|
function buildReadsState(def) {
|
|
1462
1691
|
if (!def.build) return true;
|
|
1463
1692
|
const src = def.buildSrc ?? def.build.toString();
|
|
1464
1693
|
const arity = confirmedBuildArity(src);
|
|
1465
1694
|
if (arity === null) return true;
|
|
1466
|
-
return arity >=
|
|
1695
|
+
return arity >= 6;
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
// src/compiler/fields.ts
|
|
1699
|
+
function buildReadsFields(def) {
|
|
1700
|
+
if (!def.build) return true;
|
|
1701
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
1702
|
+
const arity = confirmedBuildArity(src);
|
|
1703
|
+
if (arity === null) return true;
|
|
1704
|
+
return arity >= 2;
|
|
1705
|
+
}
|
|
1706
|
+
function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
1707
|
+
if (seen.has(p)) return false;
|
|
1708
|
+
seen.add(p);
|
|
1709
|
+
const d = p._def;
|
|
1710
|
+
switch (d.tag) {
|
|
1711
|
+
case "field":
|
|
1712
|
+
return true;
|
|
1713
|
+
case "node":
|
|
1714
|
+
return false;
|
|
1715
|
+
case "lazy": {
|
|
1716
|
+
try {
|
|
1717
|
+
return parserHasOwnFields(d.thunk(), seen);
|
|
1718
|
+
} catch {
|
|
1719
|
+
return false;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
case "sequence":
|
|
1723
|
+
case "choice":
|
|
1724
|
+
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
1725
|
+
case "sepBy":
|
|
1726
|
+
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
1727
|
+
case "skip":
|
|
1728
|
+
return parserHasOwnFields(d.main, seen) || parserHasOwnFields(d.skipped, seen);
|
|
1729
|
+
case "grammar":
|
|
1730
|
+
return parserHasOwnFields(d.parser, seen) || (d.triviaParser ? parserHasOwnFields(d.triviaParser, seen) : false);
|
|
1731
|
+
case "scanTo":
|
|
1732
|
+
return parserHasOwnFields(d.sentinel, seen) || d.skip.some((x) => parserHasOwnFields(x, seen));
|
|
1733
|
+
case "recover":
|
|
1734
|
+
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.sentinel, seen);
|
|
1735
|
+
case "many":
|
|
1736
|
+
case "oneOrMore":
|
|
1737
|
+
case "optional":
|
|
1738
|
+
case "transform":
|
|
1739
|
+
case "trivia":
|
|
1740
|
+
case "token":
|
|
1741
|
+
case "label":
|
|
1742
|
+
case "expect":
|
|
1743
|
+
case "withCtx":
|
|
1744
|
+
case "not":
|
|
1745
|
+
return parserHasOwnFields(d.parser, seen);
|
|
1746
|
+
default:
|
|
1747
|
+
return false;
|
|
1748
|
+
}
|
|
1749
|
+
}
|
|
1750
|
+
function buildFieldMap(captures) {
|
|
1751
|
+
if (!captures?.length) return void 0;
|
|
1752
|
+
const out = {};
|
|
1753
|
+
for (const cap of captures) {
|
|
1754
|
+
const entry = { value: cap.value, span: cap.span };
|
|
1755
|
+
const current = out[cap.name];
|
|
1756
|
+
if (current === void 0) out[cap.name] = entry;
|
|
1757
|
+
else if (Array.isArray(current)) current.push(entry);
|
|
1758
|
+
else out[cap.name] = [current, entry];
|
|
1759
|
+
}
|
|
1760
|
+
return out;
|
|
1467
1761
|
}
|
|
1468
1762
|
|
|
1469
1763
|
// src/combinators/node.ts
|
|
1470
|
-
function
|
|
1764
|
+
function unwrapChild(child) {
|
|
1471
1765
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
1472
1766
|
}
|
|
1473
|
-
function
|
|
1767
|
+
function isCstChild(value) {
|
|
1768
|
+
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "error");
|
|
1769
|
+
}
|
|
1770
|
+
function missingInferredType() {
|
|
1771
|
+
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
1772
|
+
}
|
|
1773
|
+
function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
1774
|
+
const hasExplicitType = typeof typeOrCombinator === "string";
|
|
1775
|
+
const type = hasExplicitType ? typeOrCombinator : void 0;
|
|
1776
|
+
const combinator = hasExplicitType ? combinatorOrBuild : typeOrCombinator;
|
|
1777
|
+
const build = hasExplicitType ? buildOrOpts : combinatorOrBuild;
|
|
1778
|
+
const opts = hasExplicitType ? maybeOpts : buildOrOpts;
|
|
1779
|
+
const baseDef = { tag: "node", parser: combinator, ...type === void 0 ? {} : { type }, ...build === void 0 ? {} : { build } };
|
|
1474
1780
|
const meta = {
|
|
1475
1781
|
firstSet: combinator._meta.firstSet,
|
|
1476
1782
|
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1477
1783
|
isTrivia: false
|
|
1478
1784
|
};
|
|
1785
|
+
const unwrap = opts?.unwrap === true;
|
|
1479
1786
|
const collapse = opts?.collapse === true;
|
|
1480
|
-
|
|
1787
|
+
if (unwrap && collapse) {
|
|
1788
|
+
throw new Error("node() options cannot set both unwrap and collapse");
|
|
1789
|
+
}
|
|
1790
|
+
const def = unwrap || collapse ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {} } : baseDef;
|
|
1481
1791
|
const capturesTrivia = build ? buildReadsTrivia(def) : true;
|
|
1482
1792
|
const clonesState = build ? buildReadsState(def) : true;
|
|
1793
|
+
const capturesFields = parserHasOwnFields(combinator) && (build ? buildReadsFields(def) : true);
|
|
1483
1794
|
return {
|
|
1484
1795
|
_tag: "node",
|
|
1485
1796
|
_meta: meta,
|
|
1486
1797
|
_def: def,
|
|
1487
1798
|
parse(input, pos, ctx) {
|
|
1488
1799
|
const saved = beginCstNodeCapture(ctx);
|
|
1800
|
+
const savedFields = ctx._fields;
|
|
1801
|
+
ctx._fields = capturesFields ? [] : void 0;
|
|
1489
1802
|
if (!capturesTrivia) ctx.captureTrivia = false;
|
|
1490
1803
|
const r = combinator.parse(input, pos, ctx);
|
|
1804
|
+
const fields = capturesFields ? buildFieldMap(ctx._fields) : void 0;
|
|
1805
|
+
ctx._fields = savedFields;
|
|
1491
1806
|
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
1492
1807
|
if (!r.ok) return r;
|
|
1493
1808
|
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
1494
|
-
const
|
|
1495
|
-
const
|
|
1496
|
-
const rawEntry =
|
|
1809
|
+
const nodeType = def.type ?? missingInferredType();
|
|
1810
|
+
const built = unwrap && children.length === 1 ? unwrapChild(children[0]) : collapse && children.length === 1 ? children[0] : !build && ctx.build?._parsemanCstCollapse && children.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children[0], children, rawChildren) ? children[0] : build ? build(children, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children };
|
|
1811
|
+
const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
|
|
1497
1812
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
1498
1813
|
pushCstChild(ctx, built, rawEntry);
|
|
1499
1814
|
}
|
|
@@ -1511,7 +1826,7 @@ function transform(combinator, fn) {
|
|
|
1511
1826
|
parse(input, pos, ctx) {
|
|
1512
1827
|
const result = combinator.parse(input, pos, ctx);
|
|
1513
1828
|
if (!result.ok) return result;
|
|
1514
|
-
return {
|
|
1829
|
+
return { ok: true, value: fn(result.value, result.span), span: result.span };
|
|
1515
1830
|
}
|
|
1516
1831
|
};
|
|
1517
1832
|
}
|
|
@@ -1525,7 +1840,7 @@ function skip(main, skipped) {
|
|
|
1525
1840
|
if (!result.ok) return result;
|
|
1526
1841
|
const s = skipped.parse(input, result.span.end, ctx);
|
|
1527
1842
|
if (!s.ok) return result;
|
|
1528
|
-
return {
|
|
1843
|
+
return { ok: true, value: result.value, span: { start: result.span.start, end: s.span.end } };
|
|
1529
1844
|
}
|
|
1530
1845
|
};
|
|
1531
1846
|
}
|
|
@@ -1549,7 +1864,20 @@ function label(name, combinator) {
|
|
|
1549
1864
|
_def: { tag: "label", label: name, parser: combinator },
|
|
1550
1865
|
parse(input, pos, ctx) {
|
|
1551
1866
|
const result = combinator.parse(input, pos, ctx);
|
|
1552
|
-
if (!result.ok) return {
|
|
1867
|
+
if (!result.ok) return { ok: false, expected: [name], span: result.span };
|
|
1868
|
+
return result;
|
|
1869
|
+
}
|
|
1870
|
+
};
|
|
1871
|
+
}
|
|
1872
|
+
function field(name, combinator) {
|
|
1873
|
+
return {
|
|
1874
|
+
_tag: combinator._tag,
|
|
1875
|
+
_meta: combinator._meta,
|
|
1876
|
+
_def: { tag: "field", name, parser: combinator },
|
|
1877
|
+
parse(input, pos, ctx) {
|
|
1878
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1879
|
+
if (!result.ok) return result;
|
|
1880
|
+
ctx._fields?.push({ name, value: result.value, span: result.span });
|
|
1553
1881
|
return result;
|
|
1554
1882
|
}
|
|
1555
1883
|
};
|
|
@@ -1763,9 +2091,9 @@ function expect(combinator, label2) {
|
|
|
1763
2091
|
|
|
1764
2092
|
// src/compiler/scannable-run.ts
|
|
1765
2093
|
var BACKSLASH = 92;
|
|
1766
|
-
var
|
|
2094
|
+
var CLASS_ESCAPES2 = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
1767
2095
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
1768
|
-
var
|
|
2096
|
+
var SPACE_RANGES2 = [
|
|
1769
2097
|
[9, 13],
|
|
1770
2098
|
[32, 32],
|
|
1771
2099
|
[160, 160],
|
|
@@ -1778,9 +2106,9 @@ var SPACE_RANGES = [
|
|
|
1778
2106
|
[12288, 12288],
|
|
1779
2107
|
[65279, 65279]
|
|
1780
2108
|
];
|
|
1781
|
-
function
|
|
2109
|
+
function shorthandRanges2(ch) {
|
|
1782
2110
|
if (ch === "d") return [[48, 57]];
|
|
1783
|
-
if (ch === "s") return
|
|
2111
|
+
if (ch === "s") return SPACE_RANGES2;
|
|
1784
2112
|
return [[48, 57], [65, 90], [97, 122], [95, 95]];
|
|
1785
2113
|
}
|
|
1786
2114
|
function readUnicodeEscape(body, i) {
|
|
@@ -1804,8 +2132,8 @@ function parseClassRanges(body) {
|
|
|
1804
2132
|
const e = body[i + 1];
|
|
1805
2133
|
if (e === void 0) return null;
|
|
1806
2134
|
i += 2;
|
|
1807
|
-
if (e in
|
|
1808
|
-
if (e === "d" || e === "w" || e === "s") return { set:
|
|
2135
|
+
if (e in CLASS_ESCAPES2) return { cp: CLASS_ESCAPES2[e] };
|
|
2136
|
+
if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges2(e) };
|
|
1809
2137
|
if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
|
|
1810
2138
|
return { cp: e.codePointAt(0) };
|
|
1811
2139
|
}
|
|
@@ -1831,9 +2159,9 @@ function parseClassRanges(body) {
|
|
|
1831
2159
|
return ranges.length ? ranges : null;
|
|
1832
2160
|
}
|
|
1833
2161
|
function classToRanges(cls) {
|
|
1834
|
-
if (cls === "\\d") return
|
|
1835
|
-
if (cls === "\\w") return
|
|
1836
|
-
if (cls === "\\s") return
|
|
2162
|
+
if (cls === "\\d") return shorthandRanges2("d");
|
|
2163
|
+
if (cls === "\\w") return shorthandRanges2("w");
|
|
2164
|
+
if (cls === "\\s") return shorthandRanges2("s");
|
|
1837
2165
|
const body = cls.slice(1, -1);
|
|
1838
2166
|
if (body.startsWith("^")) return null;
|
|
1839
2167
|
return parseClassRanges(body);
|
|
@@ -1851,7 +2179,7 @@ function literalCodePoints(frag) {
|
|
|
1851
2179
|
if (ch === "\\") {
|
|
1852
2180
|
const e = frag[i + 1];
|
|
1853
2181
|
if (e === void 0) return null;
|
|
1854
|
-
out.push(e in
|
|
2182
|
+
out.push(e in CLASS_ESCAPES2 ? CLASS_ESCAPES2[e] : e.codePointAt(0));
|
|
1855
2183
|
i += 2;
|
|
1856
2184
|
continue;
|
|
1857
2185
|
}
|
|
@@ -1944,7 +2272,7 @@ function parseSeqParts(source) {
|
|
|
1944
2272
|
if (e === "d" || e === "w" || e === "s") {
|
|
1945
2273
|
flush();
|
|
1946
2274
|
i += 2;
|
|
1947
|
-
i += runFrom(
|
|
2275
|
+
i += runFrom(shorthandRanges2(e), false, source[i]);
|
|
1948
2276
|
continue;
|
|
1949
2277
|
}
|
|
1950
2278
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -1953,8 +2281,8 @@ function parseSeqParts(source) {
|
|
|
1953
2281
|
cp2 = uni.cp;
|
|
1954
2282
|
i = uni.next;
|
|
1955
2283
|
} else if (e === void 0) return null;
|
|
1956
|
-
else if (e in
|
|
1957
|
-
cp2 =
|
|
2284
|
+
else if (e in CLASS_ESCAPES2) {
|
|
2285
|
+
cp2 = CLASS_ESCAPES2[e];
|
|
1958
2286
|
i += 2;
|
|
1959
2287
|
} else if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
|
|
1960
2288
|
else {
|
|
@@ -2061,7 +2389,7 @@ function rangesSubset(sub, sup) {
|
|
|
2061
2389
|
}
|
|
2062
2390
|
function parseClassOperand(body) {
|
|
2063
2391
|
if (body === "\\d" || body === "\\w" || body === "\\s") {
|
|
2064
|
-
return { ranges:
|
|
2392
|
+
return { ranges: shorthandRanges2(body[1]), negated: false };
|
|
2065
2393
|
}
|
|
2066
2394
|
if (body.length >= 2 && body[0] === "[" && body[body.length - 1] === "]") {
|
|
2067
2395
|
let inner = body.slice(1, -1);
|
|
@@ -2494,7 +2822,7 @@ function parseScanShapeCore(source) {
|
|
|
2494
2822
|
}
|
|
2495
2823
|
m = /^\\([dws])([+*])$/.exec(source);
|
|
2496
2824
|
if (m) {
|
|
2497
|
-
return { kind: "chars", ranges:
|
|
2825
|
+
return { kind: "chars", ranges: shorthandRanges2(m[1]), minOne: m[2] === "+" };
|
|
2498
2826
|
}
|
|
2499
2827
|
m = /^(\[(?:\\.|[^\]])+\]|\\[dws])(\[(?:\\.|[^\]])+\]|\\[dws])\*$/.exec(source);
|
|
2500
2828
|
if (m) {
|
|
@@ -3036,21 +3364,22 @@ function emitScannableTerminal(shape, c) {
|
|
|
3036
3364
|
}
|
|
3037
3365
|
|
|
3038
3366
|
// src/compiler/inline-build.ts
|
|
3039
|
-
var MK_BUILD_RE = /^\(\s*(
|
|
3367
|
+
var MK_BUILD_RE = /^\(\s*(\w+)\s*,\s*\w+\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\)\s*=>\s*mk\s*\(\s*(['"])([^'"]+)\5\s*,\s*\1\s*,\s*\3\s*,\s*\2\s*,\s*\4\s*\)\s*$/;
|
|
3040
3368
|
function escapeRegExp(s) {
|
|
3041
3369
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3042
3370
|
}
|
|
3043
3371
|
function looseMkBuildRe(type) {
|
|
3044
3372
|
return new RegExp(
|
|
3045
|
-
String.raw`^\(\s*(
|
|
3373
|
+
String.raw`^\(\s*(\w+)\s*,\s*\w+\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\)\s*=>\s*.+\(\s*(['"])${escapeRegExp(type)}\5\s*,\s*\1\s*,\s*\3\s*,\s*\2\s*,\s*\4\s*\)\s*$`
|
|
3046
3374
|
);
|
|
3047
3375
|
}
|
|
3048
3376
|
function analyzeMkInlineBuild(def) {
|
|
3049
3377
|
if (!def.build) return null;
|
|
3378
|
+
if (def.type === void 0) return null;
|
|
3050
3379
|
const src = (def.buildSrc ?? def.build.toString()).trim();
|
|
3051
3380
|
const strict = src.match(MK_BUILD_RE);
|
|
3052
3381
|
if (strict) {
|
|
3053
|
-
const mkType = strict[
|
|
3382
|
+
const mkType = strict[6];
|
|
3054
3383
|
return mkType === def.type ? def.type : null;
|
|
3055
3384
|
}
|
|
3056
3385
|
if (looseMkBuildRe(def.type).test(src)) return def.type;
|
|
@@ -3377,8 +3706,9 @@ function planDisjointDispatch(parsers) {
|
|
|
3377
3706
|
}
|
|
3378
3707
|
return total >= SWITCH_MIN_CASES ? { kind: "switch", cases } : { kind: "if" };
|
|
3379
3708
|
}
|
|
3380
|
-
function captureRestoreBody(mL, mR, mTl, mLg) {
|
|
3381
|
-
const
|
|
3709
|
+
function captureRestoreBody(mL, mR, mTl, mLg, mF = null) {
|
|
3710
|
+
const fieldRestore = mF ? `; if (_ctx._fields) _ctx._fields.length = ${mF}` : "";
|
|
3711
|
+
const base = `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${mL}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${mR}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${mTl}${fieldRestore}`;
|
|
3382
3712
|
return mLg ? `${base}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${mLg}` : base;
|
|
3383
3713
|
}
|
|
3384
3714
|
function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -3426,6 +3756,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
3426
3756
|
// Delegating wrappers: defer to the wrapped parser.
|
|
3427
3757
|
case "transform":
|
|
3428
3758
|
case "label":
|
|
3759
|
+
case "field":
|
|
3429
3760
|
case "expect":
|
|
3430
3761
|
case "withCtx":
|
|
3431
3762
|
case "grammar":
|
|
@@ -3472,6 +3803,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
3472
3803
|
case "optional":
|
|
3473
3804
|
case "transform":
|
|
3474
3805
|
case "label":
|
|
3806
|
+
case "field":
|
|
3475
3807
|
case "expect":
|
|
3476
3808
|
case "withCtx":
|
|
3477
3809
|
case "grammar":
|
|
@@ -3509,22 +3841,25 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
3509
3841
|
ctx.recordFail = savedRecord;
|
|
3510
3842
|
const ind0 = ind(ctx);
|
|
3511
3843
|
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
3844
|
+
const needsFieldRollback = needsRollback && parserHasOwnFields(inner);
|
|
3512
3845
|
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
3513
3846
|
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
3514
3847
|
const mTl = needsRollback ? v(ctx, "_fctl") : null;
|
|
3848
|
+
const mF = needsFieldRollback ? v(ctx, "_fcf") : null;
|
|
3515
3849
|
const stmts = [
|
|
3516
3850
|
`${ind0}let ${okV} = false, ${valV}, ${endV} = ${pos}`,
|
|
3517
3851
|
...mL ? [
|
|
3518
3852
|
`${ind0}const ${mL} = _ctx._cstLeaves?.length ?? 0`,
|
|
3519
3853
|
`${ind0}const ${mR} = _ctx._cstRawChildren?.length ?? 0`,
|
|
3520
|
-
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0
|
|
3854
|
+
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
3855
|
+
...mF ? [`${ind0}const ${mF} = _ctx._fields?.length ?? 0`] : []
|
|
3521
3856
|
] : [],
|
|
3522
3857
|
`${ind0}${lbl}: {`,
|
|
3523
3858
|
...r.stmts,
|
|
3524
3859
|
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
3525
3860
|
`${ind0}}`,
|
|
3526
3861
|
...mL ? [
|
|
3527
|
-
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null)} }`
|
|
3862
|
+
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
|
|
3528
3863
|
] : []
|
|
3529
3864
|
];
|
|
3530
3865
|
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
@@ -3751,6 +4086,7 @@ function failsAtStart(p) {
|
|
|
3751
4086
|
return true;
|
|
3752
4087
|
case "transform":
|
|
3753
4088
|
case "label":
|
|
4089
|
+
case "field":
|
|
3754
4090
|
return failsAtStart(d.parser);
|
|
3755
4091
|
default:
|
|
3756
4092
|
return false;
|
|
@@ -3770,6 +4106,7 @@ function canMatchEmptyAtStart(p) {
|
|
|
3770
4106
|
return true;
|
|
3771
4107
|
case "transform":
|
|
3772
4108
|
case "label":
|
|
4109
|
+
case "field":
|
|
3773
4110
|
return canMatchEmptyAtStart(d.parser);
|
|
3774
4111
|
case "literal":
|
|
3775
4112
|
return d.value.length === 0;
|
|
@@ -3952,11 +4289,13 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
3952
4289
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
3953
4290
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
3954
4291
|
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
4292
|
+
const armNeedsFieldRollback = armNeedsRollback && parserHasOwnFields(p);
|
|
3955
4293
|
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
3956
4294
|
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
3957
4295
|
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
3958
4296
|
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
3959
|
-
const
|
|
4297
|
+
const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
|
|
4298
|
+
const rollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
|
|
3960
4299
|
const failSlot = atStart ? staticFx : "_ctx._fx";
|
|
3961
4300
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
3962
4301
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
@@ -3966,7 +4305,8 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
3966
4305
|
`${ind(ctx)}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
|
|
3967
4306
|
`${ind(ctx)}const ${markRaw} = _ctx._cstRawChildren?.length ?? 0`,
|
|
3968
4307
|
`${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
3969
|
-
`${ind(ctx)}const ${markLog} = _ctx._triviaLog?.length ?? 0
|
|
4308
|
+
`${ind(ctx)}const ${markLog} = _ctx._triviaLog?.length ?? 0`,
|
|
4309
|
+
...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
|
|
3970
4310
|
);
|
|
3971
4311
|
}
|
|
3972
4312
|
const { stmts: armStmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos, atStart);
|
|
@@ -4359,6 +4699,9 @@ function emitToken(def, ctx, pos) {
|
|
|
4359
4699
|
};
|
|
4360
4700
|
}
|
|
4361
4701
|
function emitNode(def, ctx, pos) {
|
|
4702
|
+
if (def.type === void 0) {
|
|
4703
|
+
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
4704
|
+
}
|
|
4362
4705
|
const structural = def.build === void 0;
|
|
4363
4706
|
const mkType = structural ? null : analyzeMkInlineBuild(def);
|
|
4364
4707
|
let buildIdx = null;
|
|
@@ -4370,25 +4713,36 @@ function emitNode(def, ctx, pos) {
|
|
|
4370
4713
|
const i = ind(ctx);
|
|
4371
4714
|
const capturesTrivia = mkType !== null || !structural && buildReadsTrivia(def);
|
|
4372
4715
|
const clonesState = !structural && buildReadsState(def);
|
|
4716
|
+
const hasFields = parserHasOwnFields(def.parser);
|
|
4717
|
+
const capturesFields = hasFields && !structural && buildReadsFields(def);
|
|
4373
4718
|
const chV = v(ctx, "_ch");
|
|
4374
4719
|
const rawV = v(ctx, "_raw");
|
|
4375
4720
|
const capTLv = structural ? v(ctx, "_ctl") : null;
|
|
4376
4721
|
const capSTv = structural ? v(ctx, "_cst") : null;
|
|
4722
|
+
const capFv = structural && hasFields ? v(ctx, "_cf") : null;
|
|
4377
4723
|
const tlV = capturesTrivia || structural ? v(ctx, "_tl") : "_EMPTY_TL";
|
|
4378
4724
|
if (!capturesTrivia) ctx.needsEmptyTl = true;
|
|
4379
4725
|
const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
|
|
4380
4726
|
if (structural) ctx.needsHostReads = true;
|
|
4381
|
-
const
|
|
4727
|
+
const hostTriviaGate = `_ctx.build !== undefined && (_ctx.build._parsemanCaptureTrivia !== undefined ? _ctx.build._parsemanCaptureTrivia(${JSON.stringify(def.type)}) : (_ctx._pmCapTL ??= _hostReads(_ctx.build, 5)))`;
|
|
4728
|
+
const allocStmt = structural ? `${i}const ${capTLv} = ${hostTriviaGate}, ${capSTv} = _ctx._pmCapST ??= (_ctx.build === undefined || _hostReads(_ctx.build, 6))${capFv ? `, ${capFv} = _ctx.build !== undefined && _hostReads(_ctx.build, 2)` : ""}
|
|
4382
4729
|
${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capturesTrivia ? `${i}const ${chV} = [], ${rawV} = [], ${tlV} = []` : `${i}const ${chV} = [], ${rawV} = []`;
|
|
4383
4730
|
const innerTl = structural ? `${capTLv} ? ${tlV} : undefined` : capturesTrivia ? tlV : "undefined";
|
|
4731
|
+
const fieldsOn = structural ? capFv ?? "false" : capturesFields ? "true" : "false";
|
|
4732
|
+
const sf = hasFields ? v(ctx, "_sf") : null;
|
|
4733
|
+
const fArr = hasFields ? v(ctx, "_fa") : null;
|
|
4734
|
+
const fObj = hasFields ? v(ctx, "_fields") : "undefined";
|
|
4384
4735
|
const stmts = [
|
|
4385
4736
|
allocStmt,
|
|
4386
|
-
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog`,
|
|
4387
|
-
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}`
|
|
4737
|
+
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
4738
|
+
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
|
|
4388
4739
|
];
|
|
4389
4740
|
const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
4390
4741
|
stmts.push(...innerStmts);
|
|
4391
|
-
|
|
4742
|
+
if (sf && fArr) {
|
|
4743
|
+
stmts.push(`${i}const ${fArr} = _ctx._fields`);
|
|
4744
|
+
}
|
|
4745
|
+
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${sf ? `; _ctx._fields = ${sf}` : ""}`);
|
|
4392
4746
|
stmts.push(...emitIfFail(ctx, `!${okVar}`, propagateFailBody(ctx)));
|
|
4393
4747
|
let stV = "undefined";
|
|
4394
4748
|
if (structural) {
|
|
@@ -4398,14 +4752,33 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
4398
4752
|
stV = v(ctx, "_nst");
|
|
4399
4753
|
stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
|
|
4400
4754
|
}
|
|
4755
|
+
if (sf && fArr) {
|
|
4756
|
+
const fe = v(ctx, "_fe");
|
|
4757
|
+
const cur = v(ctx, "_fc");
|
|
4758
|
+
stmts.push(
|
|
4759
|
+
`${i}let ${fObj} = undefined`,
|
|
4760
|
+
`${i}if (${fArr} && ${fArr}.length) {`,
|
|
4761
|
+
`${i} ${fObj} = {}`,
|
|
4762
|
+
`${i} for (const ${fe} of ${fArr}) {`,
|
|
4763
|
+
`${i} const ${cur} = ${fObj}[${fe}.name], _entry = { value: ${fe}.value, span: ${fe}.span }`,
|
|
4764
|
+
`${i} if (${cur} === undefined) ${fObj}[${fe}.name] = _entry`,
|
|
4765
|
+
`${i} else if (Array.isArray(${cur})) ${cur}.push(_entry)`,
|
|
4766
|
+
`${i} else ${fObj}[${fe}.name] = [${cur}, _entry]`,
|
|
4767
|
+
`${i} }`,
|
|
4768
|
+
`${i}}`
|
|
4769
|
+
);
|
|
4770
|
+
}
|
|
4401
4771
|
const ndV = v(ctx, "_nd");
|
|
4402
|
-
const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${
|
|
4403
|
-
const ndExpr = ctx.ns || structural ? `_ctx.build !== undefined ? _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${
|
|
4404
|
-
const
|
|
4772
|
+
const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
|
|
4773
|
+
const ndExpr = ctx.ns || structural ? `_ctx.build !== undefined ? _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV}) : (${buildExpr})` : buildExpr;
|
|
4774
|
+
const hostCollapseExpr = ctx.ns || structural ? `_ctx.build !== undefined && _ctx.build._parsemanCstCollapse !== undefined && ${chV}.length === 1 && ${rawV}.length === 1 && _ctx.build._parsemanCstCollapse(${JSON.stringify(def.type)}, ${chV}[0], ${chV}, ${rawV}) ? ${chV}[0] : (${ndExpr})` : ndExpr;
|
|
4775
|
+
const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
|
|
4776
|
+
const collapseExpr = `${chV}.length === 1 ? ${chV}[0] : (${ndExpr})`;
|
|
4777
|
+
const finalExpr = def.unwrap ? unwrapExpr : def.collapse ? collapseExpr : hostCollapseExpr;
|
|
4405
4778
|
stmts.push(
|
|
4406
4779
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
4407
4780
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
4408
|
-
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && ${ndV}._tag === 'node') ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : '', span: { start: ${pos}, end: ${endVar} } })`
|
|
4781
|
+
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === 'error')) ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : '', span: { start: ${pos}, end: ${endVar} } })`
|
|
4409
4782
|
);
|
|
4410
4783
|
return { stmts, valueVar: ndV, endVar };
|
|
4411
4784
|
}
|
|
@@ -4620,6 +4993,17 @@ function emitDispatch(p, ctx, pos) {
|
|
|
4620
4993
|
endVar: inner.endVar
|
|
4621
4994
|
};
|
|
4622
4995
|
}
|
|
4996
|
+
case "field": {
|
|
4997
|
+
const inner = emit(def.parser, ctx, pos);
|
|
4998
|
+
return {
|
|
4999
|
+
stmts: [
|
|
5000
|
+
...inner.stmts,
|
|
5001
|
+
`${ind(ctx)}if (_ctx._fields) _ctx._fields.push({ name: ${JSON.stringify(def.name)}, value: ${inner.valueVar}, span: { start: ${pos}, end: ${inner.endVar} } })`
|
|
5002
|
+
],
|
|
5003
|
+
valueVar: inner.valueVar,
|
|
5004
|
+
endVar: inner.endVar
|
|
5005
|
+
};
|
|
5006
|
+
}
|
|
4623
5007
|
case "grammar": {
|
|
4624
5008
|
const savedTrivia = ctx.activeTrivia;
|
|
4625
5009
|
const savedKindLabels = ctx.triviaKindLabels;
|
|
@@ -4721,6 +5105,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4721
5105
|
case "trivia":
|
|
4722
5106
|
case "token":
|
|
4723
5107
|
case "label":
|
|
5108
|
+
case "field":
|
|
4724
5109
|
case "optional":
|
|
4725
5110
|
case "many":
|
|
4726
5111
|
case "oneOrMore":
|
|
@@ -4757,6 +5142,7 @@ function childrenOf(def) {
|
|
|
4757
5142
|
case "trivia":
|
|
4758
5143
|
case "token":
|
|
4759
5144
|
case "label":
|
|
5145
|
+
case "field":
|
|
4760
5146
|
case "grammar":
|
|
4761
5147
|
case "not":
|
|
4762
5148
|
case "node":
|
|
@@ -4998,6 +5384,11 @@ function assertRuleName(name) {
|
|
|
4998
5384
|
);
|
|
4999
5385
|
}
|
|
5000
5386
|
}
|
|
5387
|
+
function publicRuleWrapperSource(rule, fnSource) {
|
|
5388
|
+
const labels = rule._meta.triviaKindLabels;
|
|
5389
|
+
if (labels === void 0) return fnSource;
|
|
5390
|
+
return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
|
|
5391
|
+
}
|
|
5001
5392
|
function compileLinkable(ruleMapArg, ns) {
|
|
5002
5393
|
if (!ns) throw new Error("compileLinkable: ns must be a non-empty namespace");
|
|
5003
5394
|
for (const [, rule] of ruleMapArg) markUnusedValues(rule);
|
|
@@ -5100,7 +5491,7 @@ function compileLinkable(ruleMapArg, ns) {
|
|
|
5100
5491
|
ctx.recordFail = savedRec;
|
|
5101
5492
|
pushNamedFnDecl(ctx, fn, body.stmts, body.valueVar, body.endVar);
|
|
5102
5493
|
}
|
|
5103
|
-
perEntry.push({ key, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
5494
|
+
perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
5104
5495
|
}
|
|
5105
5496
|
if (ctx.runtimeParsers.length !== 0) return null;
|
|
5106
5497
|
const mfSrcs = ctx.mapFns.length > 0 && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : null;
|
|
@@ -5123,14 +5514,14 @@ function compileLinkable(ruleMapArg, ns) {
|
|
|
5123
5514
|
...privateFns
|
|
5124
5515
|
].filter(Boolean);
|
|
5125
5516
|
const wrappers = /* @__PURE__ */ new Map();
|
|
5126
|
-
for (const { key, r } of perEntry) {
|
|
5127
|
-
wrappers.set(key, [
|
|
5517
|
+
for (const { key, rule, r } of perEntry) {
|
|
5518
|
+
wrappers.set(key, publicRuleWrapperSource(rule, [
|
|
5128
5519
|
`function(input, _pos, _ctx) {`,
|
|
5129
5520
|
` let pos = _pos`,
|
|
5130
5521
|
...r.stmts,
|
|
5131
5522
|
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
5132
5523
|
`}`
|
|
5133
|
-
].join("\n"));
|
|
5524
|
+
].join("\n")));
|
|
5134
5525
|
}
|
|
5135
5526
|
const firstSets = /* @__PURE__ */ new Map();
|
|
5136
5527
|
for (const [key, rule] of ruleMap) {
|
|
@@ -5333,6 +5724,7 @@ function evalRuleMapIR(ir) {
|
|
|
5333
5724
|
"skip",
|
|
5334
5725
|
"trivia",
|
|
5335
5726
|
"label",
|
|
5727
|
+
"field",
|
|
5336
5728
|
"expect",
|
|
5337
5729
|
"_tf",
|
|
5338
5730
|
"_nd",
|
|
@@ -5359,6 +5751,7 @@ function evalRuleMapIR(ir) {
|
|
|
5359
5751
|
skip,
|
|
5360
5752
|
trivia,
|
|
5361
5753
|
label,
|
|
5754
|
+
field,
|
|
5362
5755
|
expect,
|
|
5363
5756
|
_tf,
|
|
5364
5757
|
_nd
|
|
@@ -5373,9 +5766,26 @@ function linkable(rulesMap, ns) {
|
|
|
5373
5766
|
if (!pieces) throw new Error("linkable(): this grammar cannot be compiled to a linkable artifact (contains a runtime-only parser fallback)");
|
|
5374
5767
|
return pieces;
|
|
5375
5768
|
}
|
|
5376
|
-
function
|
|
5769
|
+
function normalizeCstCollapse(collapse) {
|
|
5770
|
+
if (collapse === true) return () => true;
|
|
5771
|
+
if (Array.isArray(collapse)) {
|
|
5772
|
+
const types = new Set(collapse);
|
|
5773
|
+
return (type) => types.has(type);
|
|
5774
|
+
}
|
|
5775
|
+
return typeof collapse === "function" ? collapse : void 0;
|
|
5776
|
+
}
|
|
5777
|
+
function buildCstNode(type, children, _fields, span, _rawChildren, _triviaLog, state) {
|
|
5377
5778
|
return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children] };
|
|
5378
5779
|
}
|
|
5780
|
+
function cstBuildHost(typeOrOptions, children, _fields, span, rawChildren, triviaLog, state) {
|
|
5781
|
+
if (typeof typeOrOptions === "string") {
|
|
5782
|
+
return buildCstNode(typeOrOptions, children ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
|
|
5783
|
+
}
|
|
5784
|
+
const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
|
|
5785
|
+
const host = (type, children2, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children2, fields, span2, rawChildren2, triviaLog2, state2);
|
|
5786
|
+
if (collapse) host._parsemanCstCollapse = collapse;
|
|
5787
|
+
return host;
|
|
5788
|
+
}
|
|
5379
5789
|
function pick(grammar, names) {
|
|
5380
5790
|
const p = grammar.ruleFns instanceof Map ? grammar : linkable(grammar);
|
|
5381
5791
|
const keep = /* @__PURE__ */ new Set();
|
|
@@ -5407,8 +5817,9 @@ function fusedBody(pieces) {
|
|
|
5407
5817
|
}
|
|
5408
5818
|
}
|
|
5409
5819
|
const contributing = new Set(winner.values());
|
|
5410
|
-
const
|
|
5411
|
-
const
|
|
5820
|
+
const contributingPieces = [...contributing];
|
|
5821
|
+
const needsEmptyTl = contributingPieces.some((p) => p.needsEmptyTl);
|
|
5822
|
+
const needsHostReads = contributingPieces.some((p) => p.needsHostReads);
|
|
5412
5823
|
const lines = [
|
|
5413
5824
|
// Shared sentinel protocol (must match NAMED_FN_FAIL / NAMED_FN_END in codegen).
|
|
5414
5825
|
"const _pfFail = {}",
|
|
@@ -5416,7 +5827,7 @@ function fusedBody(pieces) {
|
|
|
5416
5827
|
...needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [],
|
|
5417
5828
|
...needsHostReads ? [HOST_READS_DECL] : [],
|
|
5418
5829
|
// Each contributing artifact's namespaced private prelude (regexes, _pf, …).
|
|
5419
|
-
...[...
|
|
5830
|
+
...[...new Set(contributingPieces.flatMap((p) => p.prelude))],
|
|
5420
5831
|
// The winning `_r_<Name>` function for each rule (one per name → no redeclare).
|
|
5421
5832
|
...[...winner].map(([k, p]) => p.ruleFns.get(k))
|
|
5422
5833
|
];
|
|
@@ -5439,7 +5850,7 @@ function fusedBody(pieces) {
|
|
|
5439
5850
|
}
|
|
5440
5851
|
);
|
|
5441
5852
|
const env = {};
|
|
5442
|
-
for (const p of
|
|
5853
|
+
for (const p of contributingPieces) {
|
|
5443
5854
|
if (p.mfFns.length) env[`${p.ns}mf`] = p.mfFns;
|
|
5444
5855
|
if (p.buildFns.length) env[`${p.ns}build`] = p.buildFns;
|
|
5445
5856
|
}
|
|
@@ -5459,14 +5870,23 @@ function materializePiece(p) {
|
|
|
5459
5870
|
if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
|
|
5460
5871
|
return pieces;
|
|
5461
5872
|
}
|
|
5462
|
-
function
|
|
5873
|
+
function nextComposeNs(used) {
|
|
5874
|
+
let ns;
|
|
5875
|
+
do {
|
|
5876
|
+
ns = `_lk${_nsCounter++}_`;
|
|
5877
|
+
} while (used.has(ns));
|
|
5878
|
+
used.add(ns);
|
|
5879
|
+
return ns;
|
|
5880
|
+
}
|
|
5881
|
+
function itemPieces(item, used) {
|
|
5463
5882
|
const carried = item[COMPOSED_PIECES];
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
return
|
|
5883
|
+
const pieces = Array.isArray(carried) ? carried.map(materializePiece) : item.ruleFns instanceof Map ? [item] : [linkable(item, nextComposeNs(used))];
|
|
5884
|
+
for (const p of pieces) used.add(p.ns);
|
|
5885
|
+
return pieces;
|
|
5467
5886
|
}
|
|
5468
5887
|
function compose(items) {
|
|
5469
|
-
const
|
|
5888
|
+
const used = /* @__PURE__ */ new Set();
|
|
5889
|
+
const pieces = items.flatMap((item) => itemPieces(item, used));
|
|
5470
5890
|
const map = fuseRules(pieces);
|
|
5471
5891
|
Object.defineProperty(map, COMPOSED_PIECES, { value: pieces, enumerable: false });
|
|
5472
5892
|
return map;
|