parseman 0.18.2 → 0.20.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 -4
- 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 +7 -7
- package/dist/combinators/regex.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/scannable-run.d.ts +2 -10
- package/dist/compiler/scannable-run.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 +568 -262
- 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 +568 -252
- package/dist/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +568 -260
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.js +568 -260
- package/dist/plugin/index.js.map +4 -4
- package/dist/regex/classes.d.ts +40 -0
- package/dist/regex/classes.d.ts.map +1 -0
- package/dist/regex/first-set.d.ts +35 -0
- package/dist/regex/first-set.d.ts.map +1 -0
- package/dist/types.d.ts +31 -8
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -3
- package/dist/combinators/regex-analyze.d.ts +0 -6
- package/dist/combinators/regex-analyze.d.ts.map +0 -1
package/dist/plugin/index.cjs
CHANGED
|
@@ -217,6 +217,13 @@ function ref() {
|
|
|
217
217
|
define(p) {
|
|
218
218
|
if (resolved) throw new Error("ref<T>() already defined");
|
|
219
219
|
resolved = p;
|
|
220
|
+
meta.firstSet = p._meta.firstSet;
|
|
221
|
+
meta.canMatchNewline = p._meta.canMatchNewline;
|
|
222
|
+
meta.isTrivia = p._meta.isTrivia;
|
|
223
|
+
if (p._meta.triviaKindLabels !== void 0) meta.triviaKindLabels = p._meta.triviaKindLabels;
|
|
224
|
+
else delete meta.triviaKindLabels;
|
|
225
|
+
if (p._meta.disjoint !== void 0) meta.disjoint = p._meta.disjoint;
|
|
226
|
+
else delete meta.disjoint;
|
|
220
227
|
}
|
|
221
228
|
};
|
|
222
229
|
return slot;
|
|
@@ -324,7 +331,8 @@ function saveCstMark(ctx) {
|
|
|
324
331
|
return {
|
|
325
332
|
raw: cstRawLen(ctx),
|
|
326
333
|
tlog: cstTlLen(ctx),
|
|
327
|
-
leaves: cstLeavesLen(ctx)
|
|
334
|
+
leaves: cstLeavesLen(ctx),
|
|
335
|
+
fields: ctx._fields?.length ?? 0
|
|
328
336
|
};
|
|
329
337
|
}
|
|
330
338
|
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
@@ -348,11 +356,13 @@ function rollbackCstCapture(ctx, mark) {
|
|
|
348
356
|
if (mark.tlog === 0) b.tl = void 0;
|
|
349
357
|
else b.tl.length = mark.tlog;
|
|
350
358
|
}
|
|
359
|
+
if (ctx._fields) ctx._fields.length = mark.fields;
|
|
351
360
|
return;
|
|
352
361
|
}
|
|
353
362
|
if (ctx._cstRawChildren) ctx._cstRawChildren.length = mark.raw;
|
|
354
363
|
if (ctx._cstTriviaLog) ctx._cstTriviaLog.length = mark.tlog;
|
|
355
364
|
if (ctx._cstLeaves) ctx._cstLeaves.length = mark.leaves;
|
|
365
|
+
if (ctx._fields) ctx._fields.length = mark.fields;
|
|
356
366
|
}
|
|
357
367
|
function pushCstTriviaEntry(ctx, start, end, kindIndex) {
|
|
358
368
|
const insertIdx = cstRawLen(ctx);
|
|
@@ -396,9 +406,9 @@ function asciiFoldEq(a, b) {
|
|
|
396
406
|
}
|
|
397
407
|
function literal(value, opts = {}) {
|
|
398
408
|
const caseInsensitive = opts.caseInsensitive ?? false;
|
|
399
|
-
const
|
|
409
|
+
const firstSet2 = value.length > 0 ? fromChar(value.codePointAt(0)) : empty();
|
|
400
410
|
const meta = {
|
|
401
|
-
firstSet,
|
|
411
|
+
firstSet: firstSet2,
|
|
402
412
|
canMatchNewline: value.includes("\n"),
|
|
403
413
|
isTrivia: false
|
|
404
414
|
};
|
|
@@ -410,7 +420,7 @@ function literal(value, opts = {}) {
|
|
|
410
420
|
meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? firstLower === firstUpper ? { kind: "ranges", ranges: [{ lo: firstLower, hi: firstLower }] } : { kind: "ranges", ranges: [
|
|
411
421
|
{ lo: firstLower, hi: firstLower },
|
|
412
422
|
{ lo: firstUpper, hi: firstUpper }
|
|
413
|
-
] } :
|
|
423
|
+
] } : firstSet2;
|
|
414
424
|
}
|
|
415
425
|
return {
|
|
416
426
|
_tag: "literal",
|
|
@@ -433,68 +443,66 @@ function literal(value, opts = {}) {
|
|
|
433
443
|
};
|
|
434
444
|
}
|
|
435
445
|
|
|
436
|
-
// src/
|
|
437
|
-
var
|
|
438
|
-
function registerRegexAnalyzer(analyzer) {
|
|
439
|
-
firstSetAnalyzer = analyzer;
|
|
440
|
-
}
|
|
441
|
-
var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
|
|
442
|
-
var SCAN_BAIL_AT = 64;
|
|
446
|
+
// src/regex/classes.ts
|
|
447
|
+
var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
443
448
|
var SPACE_RANGES = [
|
|
444
449
|
[9, 13],
|
|
445
450
|
[32, 32],
|
|
446
451
|
[160, 160],
|
|
447
452
|
[5760, 5760],
|
|
448
453
|
[8192, 8202],
|
|
449
|
-
[8232,
|
|
454
|
+
[8232, 8232],
|
|
455
|
+
[8233, 8233],
|
|
450
456
|
[8239, 8239],
|
|
451
457
|
[8287, 8287],
|
|
452
458
|
[12288, 12288],
|
|
453
459
|
[65279, 65279]
|
|
454
460
|
];
|
|
455
|
-
var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
456
461
|
function shorthandRanges(ch) {
|
|
457
462
|
if (ch === "d") return [[48, 57]];
|
|
458
463
|
if (ch === "s") return SPACE_RANGES;
|
|
459
464
|
return [[48, 57], [65, 90], [97, 122], [95, 95]];
|
|
460
465
|
}
|
|
461
|
-
function
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
}
|
|
466
|
-
return false;
|
|
466
|
+
function readUnicodeEscape(body, i) {
|
|
467
|
+
if (body[i] !== "\\" || body[i + 1] !== "u") return null;
|
|
468
|
+
const hex = body.slice(i + 2, i + 6);
|
|
469
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
|
|
470
|
+
return { cp: Number.parseInt(hex, 16), next: i + 6 };
|
|
467
471
|
}
|
|
468
|
-
function
|
|
469
|
-
if (body.startsWith("^")) return null;
|
|
472
|
+
function parseClassRanges(body) {
|
|
470
473
|
const ranges = [];
|
|
471
474
|
let i = 0;
|
|
472
475
|
const readAtom = () => {
|
|
473
476
|
const ch = body[i];
|
|
474
477
|
if (ch === void 0) return null;
|
|
475
478
|
if (ch === "\\") {
|
|
476
|
-
const
|
|
477
|
-
if (
|
|
479
|
+
const uni = readUnicodeEscape(body, i);
|
|
480
|
+
if (uni) {
|
|
481
|
+
i = uni.next;
|
|
482
|
+
return { cp: uni.cp };
|
|
483
|
+
}
|
|
484
|
+
const e = body[i + 1];
|
|
485
|
+
if (e === void 0) return null;
|
|
478
486
|
i += 2;
|
|
479
|
-
if (
|
|
480
|
-
if (
|
|
481
|
-
if (
|
|
482
|
-
return { cp:
|
|
487
|
+
if (e in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[e] };
|
|
488
|
+
if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges(e) };
|
|
489
|
+
if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
|
|
490
|
+
return { cp: e.codePointAt(0) };
|
|
483
491
|
}
|
|
484
|
-
i
|
|
485
|
-
return { cp: ch.
|
|
492
|
+
i += ch.length;
|
|
493
|
+
return { cp: ch.codePointAt(0) };
|
|
486
494
|
};
|
|
487
495
|
while (i < body.length) {
|
|
488
496
|
const lo = readAtom();
|
|
489
|
-
if (
|
|
490
|
-
if ("
|
|
491
|
-
ranges.push(...lo.
|
|
497
|
+
if (lo === null) return null;
|
|
498
|
+
if ("set" in lo) {
|
|
499
|
+
ranges.push(...lo.set);
|
|
492
500
|
continue;
|
|
493
501
|
}
|
|
494
502
|
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
495
|
-
i
|
|
503
|
+
i += 1;
|
|
496
504
|
const hi = readAtom();
|
|
497
|
-
if (
|
|
505
|
+
if (hi === null || "set" in hi) return null;
|
|
498
506
|
ranges.push([lo.cp, hi.cp]);
|
|
499
507
|
} else {
|
|
500
508
|
ranges.push([lo.cp, lo.cp]);
|
|
@@ -502,6 +510,25 @@ function readClassRanges(body) {
|
|
|
502
510
|
}
|
|
503
511
|
return ranges.length ? ranges : null;
|
|
504
512
|
}
|
|
513
|
+
|
|
514
|
+
// src/combinators/regex.ts
|
|
515
|
+
var firstSetAnalyzer = null;
|
|
516
|
+
function registerRegexAnalyzer(analyzer) {
|
|
517
|
+
firstSetAnalyzer = analyzer;
|
|
518
|
+
}
|
|
519
|
+
var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
|
|
520
|
+
var SCAN_BAIL_AT = 64;
|
|
521
|
+
function inRanges(cp, ranges) {
|
|
522
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
523
|
+
const [lo, hi] = ranges[i];
|
|
524
|
+
if (cp >= lo && cp <= hi) return true;
|
|
525
|
+
}
|
|
526
|
+
return false;
|
|
527
|
+
}
|
|
528
|
+
function readClassRanges(body) {
|
|
529
|
+
if (body.startsWith("^")) return null;
|
|
530
|
+
return parseClassRanges(body);
|
|
531
|
+
}
|
|
505
532
|
function shortScanner(source, flags) {
|
|
506
533
|
if (/[imsuvy]/.test(flags)) return null;
|
|
507
534
|
let ranges = null;
|
|
@@ -535,8 +562,8 @@ function regex(pattern, flags = "") {
|
|
|
535
562
|
const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
|
|
536
563
|
const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
|
|
537
564
|
const scan = shortScanner(source, resolvedFlags);
|
|
538
|
-
const { firstSet, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
|
|
539
|
-
const meta = { firstSet, canMatchNewline, isTrivia: false };
|
|
565
|
+
const { firstSet: firstSet2, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
|
|
566
|
+
const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
|
|
540
567
|
return {
|
|
541
568
|
_tag: "regex",
|
|
542
569
|
_meta: meta,
|
|
@@ -564,111 +591,266 @@ function regex(pattern, flags = "") {
|
|
|
564
591
|
};
|
|
565
592
|
}
|
|
566
593
|
|
|
567
|
-
// src/
|
|
568
|
-
var
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
return extractFirstSet(ast.body);
|
|
573
|
-
} catch {
|
|
574
|
-
return { firstSet: any(), canMatchNewline: true };
|
|
575
|
-
}
|
|
594
|
+
// src/regex/first-set.ts
|
|
595
|
+
var ANY = { t: "any" };
|
|
596
|
+
var EMPTY2 = { t: "empty" };
|
|
597
|
+
function charNode(set, nl) {
|
|
598
|
+
return { t: "char", set, nl };
|
|
576
599
|
}
|
|
577
|
-
function
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
600
|
+
function rangesToSet(ranges) {
|
|
601
|
+
let fs2 = empty();
|
|
602
|
+
for (const [lo, hi] of ranges) fs2 = union(fs2, fromRange(lo, hi));
|
|
603
|
+
return fs2;
|
|
604
|
+
}
|
|
605
|
+
function rangesHaveNewline(ranges) {
|
|
606
|
+
return ranges.some(([lo, hi]) => lo <= 10 && 10 <= hi);
|
|
607
|
+
}
|
|
608
|
+
var BAIL = /* @__PURE__ */ Symbol("regex-bail");
|
|
609
|
+
function parseRegex(src) {
|
|
610
|
+
let i = 0;
|
|
611
|
+
const parseAlt = () => {
|
|
612
|
+
const arms = [parseSeq()];
|
|
613
|
+
while (src[i] === "|") {
|
|
614
|
+
i++;
|
|
615
|
+
arms.push(parseSeq());
|
|
583
616
|
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
617
|
+
return arms.length === 1 ? arms[0] : { t: "alt", arms };
|
|
618
|
+
};
|
|
619
|
+
const parseSeq = () => {
|
|
620
|
+
const parts = [];
|
|
621
|
+
while (i < src.length) {
|
|
622
|
+
const ch = src[i];
|
|
623
|
+
if (ch === "|" || ch === ")") break;
|
|
624
|
+
parts.push(parseQuantified());
|
|
625
|
+
}
|
|
626
|
+
if (parts.length === 0) return EMPTY2;
|
|
627
|
+
return parts.length === 1 ? parts[0] : { t: "seq", parts };
|
|
628
|
+
};
|
|
629
|
+
const parseQuantified = () => {
|
|
630
|
+
const atom = parseAtom();
|
|
631
|
+
const ch = src[i];
|
|
632
|
+
let min = null;
|
|
633
|
+
if (ch === "*") {
|
|
634
|
+
min = 0;
|
|
635
|
+
i++;
|
|
636
|
+
} else if (ch === "+") {
|
|
637
|
+
min = 1;
|
|
638
|
+
i++;
|
|
639
|
+
} else if (ch === "?") {
|
|
640
|
+
min = 0;
|
|
641
|
+
i++;
|
|
642
|
+
} else if (ch === "{") {
|
|
643
|
+
min = parseBraceQuantifier();
|
|
587
644
|
}
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
645
|
+
if (min === null) return atom;
|
|
646
|
+
if (src[i] === "?") i++;
|
|
647
|
+
return { t: "rep", node: atom, min };
|
|
648
|
+
};
|
|
649
|
+
const parseBraceQuantifier = () => {
|
|
650
|
+
const close = src.indexOf("}", i);
|
|
651
|
+
if (close === -1) return null;
|
|
652
|
+
const m = /^(\d+)(?:,(\d*))?$/.exec(src.slice(i + 1, close));
|
|
653
|
+
if (!m) return null;
|
|
654
|
+
i = close + 1;
|
|
655
|
+
return Number.parseInt(m[1], 10);
|
|
656
|
+
};
|
|
657
|
+
const parseAtom = () => {
|
|
658
|
+
const ch = src[i];
|
|
659
|
+
switch (ch) {
|
|
660
|
+
case "(":
|
|
661
|
+
return parseGroup();
|
|
662
|
+
case "[":
|
|
663
|
+
return parseClass();
|
|
664
|
+
case ".":
|
|
665
|
+
i++;
|
|
666
|
+
return charNode(any(), false);
|
|
667
|
+
// `.` matches any char except line terminators
|
|
668
|
+
case "\\":
|
|
669
|
+
return parseEscape();
|
|
670
|
+
case "^":
|
|
671
|
+
case "$":
|
|
672
|
+
i++;
|
|
673
|
+
return EMPTY2;
|
|
674
|
+
// anchors are zero-width
|
|
675
|
+
case "{":
|
|
676
|
+
i++;
|
|
677
|
+
return charNode(fromRange(123, 123), false);
|
|
678
|
+
// a `{` with nothing to quantify is a literal brace
|
|
679
|
+
default:
|
|
680
|
+
i += ch.length;
|
|
681
|
+
return charNode(fromRange(ch.codePointAt(0), ch.codePointAt(0)), ch === "\n");
|
|
606
682
|
}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
}
|
|
618
|
-
|
|
683
|
+
};
|
|
684
|
+
const parseGroup = () => {
|
|
685
|
+
i++;
|
|
686
|
+
let lookaround = false;
|
|
687
|
+
if (src[i] === "?") {
|
|
688
|
+
const c1 = src[i + 1];
|
|
689
|
+
if (c1 === ":") i += 2;
|
|
690
|
+
else if (c1 === "=" || c1 === "!") {
|
|
691
|
+
i += 2;
|
|
692
|
+
lookaround = true;
|
|
693
|
+
} else if (c1 === "<") {
|
|
694
|
+
const c2 = src[i + 2];
|
|
695
|
+
if (c2 === "=" || c2 === "!") {
|
|
696
|
+
i += 3;
|
|
697
|
+
lookaround = true;
|
|
698
|
+
} else {
|
|
699
|
+
const gt = src.indexOf(">", i);
|
|
700
|
+
if (gt === -1) throw BAIL;
|
|
701
|
+
i = gt + 1;
|
|
702
|
+
}
|
|
703
|
+
} else throw BAIL;
|
|
619
704
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
};
|
|
638
|
-
if (val === "s") return { firstSet: fromRange(9, 13), canMatchNewline: true };
|
|
639
|
-
if (val === "n") return { firstSet: fromRange(10, 10), canMatchNewline: true };
|
|
705
|
+
const inner = parseAlt();
|
|
706
|
+
if (src[i] !== ")") throw BAIL;
|
|
707
|
+
i++;
|
|
708
|
+
return lookaround ? EMPTY2 : inner;
|
|
709
|
+
};
|
|
710
|
+
const parseClass = () => {
|
|
711
|
+
let k = i + 1;
|
|
712
|
+
const negated = src[k] === "^";
|
|
713
|
+
if (negated) k++;
|
|
714
|
+
let body = "";
|
|
715
|
+
while (k < src.length && src[k] !== "]") {
|
|
716
|
+
if (src[k] === "\\") {
|
|
717
|
+
body += src[k] + (src[k + 1] ?? "");
|
|
718
|
+
k += 2;
|
|
719
|
+
} else {
|
|
720
|
+
body += src[k];
|
|
721
|
+
k++;
|
|
640
722
|
}
|
|
641
|
-
return { firstSet: any(), canMatchNewline: true };
|
|
642
723
|
}
|
|
643
|
-
|
|
644
|
-
|
|
724
|
+
if (src[k] !== "]") throw BAIL;
|
|
725
|
+
i = k + 1;
|
|
726
|
+
if (negated) return charNode(any(), true);
|
|
727
|
+
const ranges = parseClassRanges(body);
|
|
728
|
+
if (!ranges) return charNode(any(), true);
|
|
729
|
+
return charNode(rangesToSet(ranges), rangesHaveNewline(ranges));
|
|
730
|
+
};
|
|
731
|
+
const parseEscape = () => {
|
|
732
|
+
const e = src[i + 1];
|
|
733
|
+
if (e === void 0) throw BAIL;
|
|
734
|
+
if (e === "u" && /^[0-9a-fA-F]{4}$/.test(src.slice(i + 2, i + 6))) {
|
|
735
|
+
const cp = Number.parseInt(src.slice(i + 2, i + 6), 16);
|
|
736
|
+
i += 6;
|
|
737
|
+
return charNode(fromRange(cp, cp), cp === 10);
|
|
738
|
+
}
|
|
739
|
+
if (e === "x" && /^[0-9a-fA-F]{2}$/.test(src.slice(i + 2, i + 4))) {
|
|
740
|
+
const cp = Number.parseInt(src.slice(i + 2, i + 4), 16);
|
|
741
|
+
i += 4;
|
|
742
|
+
return charNode(fromRange(cp, cp), cp === 10);
|
|
743
|
+
}
|
|
744
|
+
i += 2;
|
|
745
|
+
switch (e) {
|
|
746
|
+
case "d":
|
|
747
|
+
return charNode(rangesToSet(shorthandRanges("d")), false);
|
|
748
|
+
case "w":
|
|
749
|
+
return charNode(rangesToSet(shorthandRanges("w")), false);
|
|
750
|
+
case "s":
|
|
751
|
+
return charNode(rangesToSet(shorthandRanges("s")), true);
|
|
752
|
+
case "D":
|
|
753
|
+
case "W":
|
|
754
|
+
case "S":
|
|
755
|
+
return charNode(any(), true);
|
|
756
|
+
// negated shorthand → widen
|
|
757
|
+
case "b":
|
|
758
|
+
case "B":
|
|
759
|
+
return EMPTY2;
|
|
760
|
+
// word boundary: zero-width
|
|
761
|
+
case "n":
|
|
762
|
+
return charNode(fromRange(10, 10), true);
|
|
763
|
+
case "r":
|
|
764
|
+
return charNode(fromRange(13, 13), false);
|
|
765
|
+
case "t":
|
|
766
|
+
return charNode(fromRange(9, 9), false);
|
|
767
|
+
case "f":
|
|
768
|
+
return charNode(fromRange(12, 12), false);
|
|
769
|
+
case "v":
|
|
770
|
+
return charNode(fromRange(11, 11), false);
|
|
771
|
+
case "0":
|
|
772
|
+
return charNode(fromRange(0, 0), false);
|
|
773
|
+
default:
|
|
774
|
+
if (e >= "1" && e <= "9") return ANY;
|
|
775
|
+
return charNode(fromRange(e.codePointAt(0), e.codePointAt(0)), e === "\n");
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
const node2 = parseAlt();
|
|
779
|
+
if (i < src.length) throw BAIL;
|
|
780
|
+
return node2;
|
|
781
|
+
}
|
|
782
|
+
function nullable(n) {
|
|
783
|
+
switch (n.t) {
|
|
784
|
+
case "char":
|
|
785
|
+
return false;
|
|
786
|
+
case "any":
|
|
787
|
+
return true;
|
|
788
|
+
case "empty":
|
|
789
|
+
return true;
|
|
790
|
+
case "seq":
|
|
791
|
+
return n.parts.every(nullable);
|
|
792
|
+
case "alt":
|
|
793
|
+
return n.arms.some(nullable);
|
|
794
|
+
case "rep":
|
|
795
|
+
return n.min === 0 || nullable(n.node);
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
function firstSet(n) {
|
|
799
|
+
switch (n.t) {
|
|
800
|
+
case "char":
|
|
801
|
+
return n.set;
|
|
802
|
+
case "any":
|
|
803
|
+
return any();
|
|
804
|
+
case "empty":
|
|
805
|
+
return empty();
|
|
806
|
+
case "rep":
|
|
807
|
+
return firstSet(n.node);
|
|
808
|
+
case "alt": {
|
|
645
809
|
let fs2 = empty();
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
if (expr.type === "ClassRange") {
|
|
649
|
-
const from = expr.from.codePoint;
|
|
650
|
-
const to = expr.to.codePoint;
|
|
651
|
-
fs2 = union(fs2, fromRange(from, to));
|
|
652
|
-
if (from <= 10 && 10 <= to) canNL = true;
|
|
653
|
-
} else if (expr.type === "Char") {
|
|
654
|
-
const r = extractFirstSet(expr);
|
|
655
|
-
fs2 = union(fs2, r.firstSet);
|
|
656
|
-
canNL = canNL || r.canMatchNewline;
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
|
-
if (node2.negative) return { firstSet: any(), canMatchNewline: true };
|
|
660
|
-
return { firstSet: fs2, canMatchNewline: canNL };
|
|
810
|
+
for (const arm of n.arms) fs2 = union(fs2, firstSet(arm));
|
|
811
|
+
return fs2;
|
|
661
812
|
}
|
|
662
|
-
case "
|
|
663
|
-
|
|
813
|
+
case "seq": {
|
|
814
|
+
let fs2 = empty();
|
|
815
|
+
for (const part of n.parts) {
|
|
816
|
+
fs2 = union(fs2, firstSet(part));
|
|
817
|
+
if (!nullable(part)) break;
|
|
818
|
+
}
|
|
819
|
+
return fs2;
|
|
664
820
|
}
|
|
665
|
-
|
|
666
|
-
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
function firstCanBeNewline(n) {
|
|
824
|
+
switch (n.t) {
|
|
825
|
+
case "char":
|
|
826
|
+
return n.nl;
|
|
827
|
+
case "any":
|
|
828
|
+
return true;
|
|
829
|
+
case "empty":
|
|
830
|
+
return false;
|
|
831
|
+
case "rep":
|
|
832
|
+
return firstCanBeNewline(n.node);
|
|
833
|
+
case "alt":
|
|
834
|
+
return n.arms.some(firstCanBeNewline);
|
|
835
|
+
case "seq": {
|
|
836
|
+
for (const part of n.parts) {
|
|
837
|
+
if (firstCanBeNewline(part)) return true;
|
|
838
|
+
if (!nullable(part)) break;
|
|
839
|
+
}
|
|
840
|
+
return false;
|
|
667
841
|
}
|
|
668
|
-
default:
|
|
669
|
-
return { firstSet: any(), canMatchNewline: true };
|
|
670
842
|
}
|
|
671
843
|
}
|
|
844
|
+
function firstSetFromRegex(source) {
|
|
845
|
+
let ast;
|
|
846
|
+
try {
|
|
847
|
+
ast = parseRegex(source);
|
|
848
|
+
} catch {
|
|
849
|
+
return { firstSet: any(), canMatchNewline: true };
|
|
850
|
+
}
|
|
851
|
+
if (nullable(ast)) return { firstSet: any(), canMatchNewline: true };
|
|
852
|
+
return { firstSet: firstSet(ast), canMatchNewline: firstCanBeNewline(ast) };
|
|
853
|
+
}
|
|
672
854
|
|
|
673
855
|
// src/combinators/keywords.ts
|
|
674
856
|
function word(str, boundary = "_0-9A-Za-z") {
|
|
@@ -683,19 +865,19 @@ function keywords(words, opts = {}) {
|
|
|
683
865
|
const boundary = opts.boundary ? `(?![${opts.boundary}])` : "";
|
|
684
866
|
const flags = opts.caseInsensitive ? "iuy" : "uy";
|
|
685
867
|
const re = new RegExp(`(?:${alt})${boundary}`, flags);
|
|
686
|
-
let
|
|
868
|
+
let firstSet2 = empty();
|
|
687
869
|
for (const w of sorted) {
|
|
688
870
|
if (w.length === 0) continue;
|
|
689
871
|
const cp = w.codePointAt(0);
|
|
690
|
-
|
|
872
|
+
firstSet2 = union(firstSet2, fromChar(cp));
|
|
691
873
|
if (opts.caseInsensitive) {
|
|
692
874
|
const u = String.fromCodePoint(cp).toUpperCase().codePointAt(0);
|
|
693
875
|
const l = String.fromCodePoint(cp).toLowerCase().codePointAt(0);
|
|
694
|
-
if (u !== void 0)
|
|
695
|
-
if (l !== void 0)
|
|
876
|
+
if (u !== void 0) firstSet2 = union(firstSet2, fromChar(u));
|
|
877
|
+
if (l !== void 0) firstSet2 = union(firstSet2, fromChar(l));
|
|
696
878
|
}
|
|
697
879
|
}
|
|
698
|
-
const meta = { firstSet, canMatchNewline: false, isTrivia: false };
|
|
880
|
+
const meta = { firstSet: firstSet2, canMatchNewline: false, isTrivia: false };
|
|
699
881
|
return {
|
|
700
882
|
_tag: "keywords",
|
|
701
883
|
_meta: meta,
|
|
@@ -1089,10 +1271,10 @@ function needsDeferredTriviaCommit(ctx) {
|
|
|
1089
1271
|
}
|
|
1090
1272
|
function saveTriviaMark(ctx) {
|
|
1091
1273
|
const m = saveCstMark(ctx);
|
|
1092
|
-
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1274
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1093
1275
|
}
|
|
1094
1276
|
function rollbackTrivia(ctx, mark) {
|
|
1095
|
-
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves });
|
|
1277
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields });
|
|
1096
1278
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1097
1279
|
}
|
|
1098
1280
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1476,6 +1658,9 @@ function markUnusedValues(root) {
|
|
|
1476
1658
|
case "transform":
|
|
1477
1659
|
visit(def.parser, true);
|
|
1478
1660
|
return;
|
|
1661
|
+
case "field":
|
|
1662
|
+
visit(def.parser, true);
|
|
1663
|
+
return;
|
|
1479
1664
|
case "skip":
|
|
1480
1665
|
visit(def.main, consumed);
|
|
1481
1666
|
visit(def.skipped, false);
|
|
@@ -1527,6 +1712,11 @@ function markUnusedValues(root) {
|
|
|
1527
1712
|
}
|
|
1528
1713
|
|
|
1529
1714
|
// src/combinators/parser.ts
|
|
1715
|
+
function tagRule(r, key) {
|
|
1716
|
+
;
|
|
1717
|
+
r._ruleName = key;
|
|
1718
|
+
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
|
|
1719
|
+
}
|
|
1530
1720
|
function rules(factory) {
|
|
1531
1721
|
const cache = {};
|
|
1532
1722
|
const proxy = new Proxy(cache, {
|
|
@@ -1535,7 +1725,7 @@ function rules(factory) {
|
|
|
1535
1725
|
const record = target;
|
|
1536
1726
|
if (!(key in record)) {
|
|
1537
1727
|
const r = ref();
|
|
1538
|
-
r
|
|
1728
|
+
tagRule(r, key);
|
|
1539
1729
|
record[key] = r;
|
|
1540
1730
|
}
|
|
1541
1731
|
return record[key];
|
|
@@ -1546,12 +1736,12 @@ function rules(factory) {
|
|
|
1546
1736
|
const placeholder = cache[key];
|
|
1547
1737
|
const parser2 = definitions[key];
|
|
1548
1738
|
if (placeholder !== void 0 && typeof placeholder.define === "function") {
|
|
1549
|
-
;
|
|
1739
|
+
tagRule(parser2, key);
|
|
1550
1740
|
placeholder.define(parser2);
|
|
1551
1741
|
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
1552
1742
|
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
1553
1743
|
} else {
|
|
1554
|
-
;
|
|
1744
|
+
tagRule(parser2, key);
|
|
1555
1745
|
cache[key] = parser2;
|
|
1556
1746
|
}
|
|
1557
1747
|
}
|
|
@@ -1608,44 +1798,130 @@ function buildReadsTrivia(def) {
|
|
|
1608
1798
|
const src = def.buildSrc ?? def.build.toString();
|
|
1609
1799
|
const arity = confirmedBuildArity(src);
|
|
1610
1800
|
if (arity === null) return true;
|
|
1611
|
-
return arity >=
|
|
1801
|
+
return arity >= 5;
|
|
1612
1802
|
}
|
|
1613
1803
|
function buildReadsState(def) {
|
|
1614
1804
|
if (!def.build) return true;
|
|
1615
1805
|
const src = def.buildSrc ?? def.build.toString();
|
|
1616
1806
|
const arity = confirmedBuildArity(src);
|
|
1617
1807
|
if (arity === null) return true;
|
|
1618
|
-
return arity >=
|
|
1808
|
+
return arity >= 6;
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
// src/compiler/fields.ts
|
|
1812
|
+
function buildReadsFields(def) {
|
|
1813
|
+
if (!def.build) return true;
|
|
1814
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
1815
|
+
const arity = confirmedBuildArity(src);
|
|
1816
|
+
if (arity === null) return true;
|
|
1817
|
+
return arity >= 2;
|
|
1818
|
+
}
|
|
1819
|
+
function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
1820
|
+
if (seen.has(p)) return false;
|
|
1821
|
+
seen.add(p);
|
|
1822
|
+
const d = p._def;
|
|
1823
|
+
switch (d.tag) {
|
|
1824
|
+
case "field":
|
|
1825
|
+
return true;
|
|
1826
|
+
case "node":
|
|
1827
|
+
return false;
|
|
1828
|
+
case "lazy": {
|
|
1829
|
+
try {
|
|
1830
|
+
return parserHasOwnFields(d.thunk(), seen);
|
|
1831
|
+
} catch {
|
|
1832
|
+
return false;
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
case "sequence":
|
|
1836
|
+
case "choice":
|
|
1837
|
+
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
1838
|
+
case "sepBy":
|
|
1839
|
+
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
1840
|
+
case "skip":
|
|
1841
|
+
return parserHasOwnFields(d.main, seen) || parserHasOwnFields(d.skipped, seen);
|
|
1842
|
+
case "grammar":
|
|
1843
|
+
return parserHasOwnFields(d.parser, seen) || (d.triviaParser ? parserHasOwnFields(d.triviaParser, seen) : false);
|
|
1844
|
+
case "scanTo":
|
|
1845
|
+
return parserHasOwnFields(d.sentinel, seen) || d.skip.some((x) => parserHasOwnFields(x, seen));
|
|
1846
|
+
case "recover":
|
|
1847
|
+
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.sentinel, seen);
|
|
1848
|
+
case "many":
|
|
1849
|
+
case "oneOrMore":
|
|
1850
|
+
case "optional":
|
|
1851
|
+
case "transform":
|
|
1852
|
+
case "trivia":
|
|
1853
|
+
case "token":
|
|
1854
|
+
case "label":
|
|
1855
|
+
case "expect":
|
|
1856
|
+
case "withCtx":
|
|
1857
|
+
case "not":
|
|
1858
|
+
return parserHasOwnFields(d.parser, seen);
|
|
1859
|
+
default:
|
|
1860
|
+
return false;
|
|
1861
|
+
}
|
|
1862
|
+
}
|
|
1863
|
+
function buildFieldMap(captures) {
|
|
1864
|
+
if (!captures?.length) return void 0;
|
|
1865
|
+
const out = {};
|
|
1866
|
+
for (const cap of captures) {
|
|
1867
|
+
const entry = { value: cap.value, span: cap.span };
|
|
1868
|
+
const current = out[cap.name];
|
|
1869
|
+
if (current === void 0) out[cap.name] = entry;
|
|
1870
|
+
else if (Array.isArray(current)) current.push(entry);
|
|
1871
|
+
else out[cap.name] = [current, entry];
|
|
1872
|
+
}
|
|
1873
|
+
return out;
|
|
1619
1874
|
}
|
|
1620
1875
|
|
|
1621
1876
|
// src/combinators/node.ts
|
|
1622
|
-
function
|
|
1877
|
+
function unwrapChild(child) {
|
|
1623
1878
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
1624
1879
|
}
|
|
1625
|
-
function
|
|
1880
|
+
function isCstChild(value) {
|
|
1881
|
+
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "error");
|
|
1882
|
+
}
|
|
1883
|
+
function missingInferredType() {
|
|
1884
|
+
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
1885
|
+
}
|
|
1886
|
+
function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
1887
|
+
const hasExplicitType = typeof typeOrCombinator === "string";
|
|
1888
|
+
const type = hasExplicitType ? typeOrCombinator : void 0;
|
|
1889
|
+
const combinator = hasExplicitType ? combinatorOrBuild : typeOrCombinator;
|
|
1890
|
+
const build = hasExplicitType ? buildOrOpts : combinatorOrBuild;
|
|
1891
|
+
const opts = hasExplicitType ? maybeOpts : buildOrOpts;
|
|
1892
|
+
const baseDef = { tag: "node", parser: combinator, ...type === void 0 ? {} : { type }, ...build === void 0 ? {} : { build } };
|
|
1626
1893
|
const meta = {
|
|
1627
1894
|
firstSet: combinator._meta.firstSet,
|
|
1628
1895
|
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1629
1896
|
isTrivia: false
|
|
1630
1897
|
};
|
|
1898
|
+
const unwrap = opts?.unwrap === true;
|
|
1631
1899
|
const collapse = opts?.collapse === true;
|
|
1632
|
-
|
|
1900
|
+
if (unwrap && collapse) {
|
|
1901
|
+
throw new Error("node() options cannot set both unwrap and collapse");
|
|
1902
|
+
}
|
|
1903
|
+
const def = unwrap || collapse ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {} } : baseDef;
|
|
1633
1904
|
const capturesTrivia = build ? buildReadsTrivia(def) : true;
|
|
1634
1905
|
const clonesState = build ? buildReadsState(def) : true;
|
|
1906
|
+
const capturesFields = parserHasOwnFields(combinator) && (build ? buildReadsFields(def) : true);
|
|
1635
1907
|
return {
|
|
1636
1908
|
_tag: "node",
|
|
1637
1909
|
_meta: meta,
|
|
1638
1910
|
_def: def,
|
|
1639
1911
|
parse(input, pos, ctx) {
|
|
1640
1912
|
const saved = beginCstNodeCapture(ctx);
|
|
1913
|
+
const savedFields = ctx._fields;
|
|
1914
|
+
ctx._fields = capturesFields ? [] : void 0;
|
|
1641
1915
|
if (!capturesTrivia) ctx.captureTrivia = false;
|
|
1642
1916
|
const r = combinator.parse(input, pos, ctx);
|
|
1917
|
+
const fields = capturesFields ? buildFieldMap(ctx._fields) : void 0;
|
|
1918
|
+
ctx._fields = savedFields;
|
|
1643
1919
|
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
1644
1920
|
if (!r.ok) return r;
|
|
1645
1921
|
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
1646
|
-
const
|
|
1647
|
-
const
|
|
1648
|
-
const rawEntry =
|
|
1922
|
+
const nodeType = def.type ?? missingInferredType();
|
|
1923
|
+
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 };
|
|
1924
|
+
const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
|
|
1649
1925
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
1650
1926
|
pushCstChild(ctx, built, rawEntry);
|
|
1651
1927
|
}
|
|
@@ -1706,6 +1982,19 @@ function label(name, combinator) {
|
|
|
1706
1982
|
}
|
|
1707
1983
|
};
|
|
1708
1984
|
}
|
|
1985
|
+
function field(name, combinator) {
|
|
1986
|
+
return {
|
|
1987
|
+
_tag: combinator._tag,
|
|
1988
|
+
_meta: combinator._meta,
|
|
1989
|
+
_def: { tag: "field", name, parser: combinator },
|
|
1990
|
+
parse(input, pos, ctx) {
|
|
1991
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1992
|
+
if (!result.ok) return result;
|
|
1993
|
+
ctx._fields?.push({ name, value: result.value, span: result.span });
|
|
1994
|
+
return result;
|
|
1995
|
+
}
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1709
1998
|
|
|
1710
1999
|
// src/compiler/line-index.ts
|
|
1711
2000
|
function buildLineIndex(input) {
|
|
@@ -1892,77 +2181,11 @@ function expect(combinator, label2) {
|
|
|
1892
2181
|
|
|
1893
2182
|
// src/compiler/scannable-run.ts
|
|
1894
2183
|
var BACKSLASH = 92;
|
|
1895
|
-
var CLASS_ESCAPES2 = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
1896
2184
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
1897
|
-
var SPACE_RANGES2 = [
|
|
1898
|
-
[9, 13],
|
|
1899
|
-
[32, 32],
|
|
1900
|
-
[160, 160],
|
|
1901
|
-
[5760, 5760],
|
|
1902
|
-
[8192, 8202],
|
|
1903
|
-
[8232, 8232],
|
|
1904
|
-
[8233, 8233],
|
|
1905
|
-
[8239, 8239],
|
|
1906
|
-
[8287, 8287],
|
|
1907
|
-
[12288, 12288],
|
|
1908
|
-
[65279, 65279]
|
|
1909
|
-
];
|
|
1910
|
-
function shorthandRanges2(ch) {
|
|
1911
|
-
if (ch === "d") return [[48, 57]];
|
|
1912
|
-
if (ch === "s") return SPACE_RANGES2;
|
|
1913
|
-
return [[48, 57], [65, 90], [97, 122], [95, 95]];
|
|
1914
|
-
}
|
|
1915
|
-
function readUnicodeEscape(body, i) {
|
|
1916
|
-
if (body[i] !== "\\" || body[i + 1] !== "u") return null;
|
|
1917
|
-
const hex = body.slice(i + 2, i + 6);
|
|
1918
|
-
if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
|
|
1919
|
-
return { cp: Number.parseInt(hex, 16), next: i + 6 };
|
|
1920
|
-
}
|
|
1921
|
-
function parseClassRanges(body) {
|
|
1922
|
-
const ranges = [];
|
|
1923
|
-
let i = 0;
|
|
1924
|
-
const readAtom = () => {
|
|
1925
|
-
const ch = body[i];
|
|
1926
|
-
if (ch === void 0) return null;
|
|
1927
|
-
if (ch === "\\") {
|
|
1928
|
-
const uni = readUnicodeEscape(body, i);
|
|
1929
|
-
if (uni) {
|
|
1930
|
-
i = uni.next;
|
|
1931
|
-
return { cp: uni.cp };
|
|
1932
|
-
}
|
|
1933
|
-
const e = body[i + 1];
|
|
1934
|
-
if (e === void 0) return null;
|
|
1935
|
-
i += 2;
|
|
1936
|
-
if (e in CLASS_ESCAPES2) return { cp: CLASS_ESCAPES2[e] };
|
|
1937
|
-
if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges2(e) };
|
|
1938
|
-
if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
|
|
1939
|
-
return { cp: e.codePointAt(0) };
|
|
1940
|
-
}
|
|
1941
|
-
i += ch.length;
|
|
1942
|
-
return { cp: ch.codePointAt(0) };
|
|
1943
|
-
};
|
|
1944
|
-
while (i < body.length) {
|
|
1945
|
-
const lo = readAtom();
|
|
1946
|
-
if (lo === null) return null;
|
|
1947
|
-
if ("set" in lo) {
|
|
1948
|
-
ranges.push(...lo.set);
|
|
1949
|
-
continue;
|
|
1950
|
-
}
|
|
1951
|
-
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
1952
|
-
i += 1;
|
|
1953
|
-
const hi = readAtom();
|
|
1954
|
-
if (hi === null || "set" in hi) return null;
|
|
1955
|
-
ranges.push([lo.cp, hi.cp]);
|
|
1956
|
-
} else {
|
|
1957
|
-
ranges.push([lo.cp, lo.cp]);
|
|
1958
|
-
}
|
|
1959
|
-
}
|
|
1960
|
-
return ranges.length ? ranges : null;
|
|
1961
|
-
}
|
|
1962
2185
|
function classToRanges(cls) {
|
|
1963
|
-
if (cls === "\\d") return
|
|
1964
|
-
if (cls === "\\w") return
|
|
1965
|
-
if (cls === "\\s") return
|
|
2186
|
+
if (cls === "\\d") return shorthandRanges("d");
|
|
2187
|
+
if (cls === "\\w") return shorthandRanges("w");
|
|
2188
|
+
if (cls === "\\s") return shorthandRanges("s");
|
|
1966
2189
|
const body = cls.slice(1, -1);
|
|
1967
2190
|
if (body.startsWith("^")) return null;
|
|
1968
2191
|
return parseClassRanges(body);
|
|
@@ -1980,7 +2203,7 @@ function literalCodePoints(frag) {
|
|
|
1980
2203
|
if (ch === "\\") {
|
|
1981
2204
|
const e = frag[i + 1];
|
|
1982
2205
|
if (e === void 0) return null;
|
|
1983
|
-
out.push(e in
|
|
2206
|
+
out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
|
|
1984
2207
|
i += 2;
|
|
1985
2208
|
continue;
|
|
1986
2209
|
}
|
|
@@ -2073,7 +2296,7 @@ function parseSeqParts(source) {
|
|
|
2073
2296
|
if (e === "d" || e === "w" || e === "s") {
|
|
2074
2297
|
flush();
|
|
2075
2298
|
i += 2;
|
|
2076
|
-
i += runFrom(
|
|
2299
|
+
i += runFrom(shorthandRanges(e), false, source[i]);
|
|
2077
2300
|
continue;
|
|
2078
2301
|
}
|
|
2079
2302
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -2082,8 +2305,8 @@ function parseSeqParts(source) {
|
|
|
2082
2305
|
cp2 = uni.cp;
|
|
2083
2306
|
i = uni.next;
|
|
2084
2307
|
} else if (e === void 0) return null;
|
|
2085
|
-
else if (e in
|
|
2086
|
-
cp2 =
|
|
2308
|
+
else if (e in CLASS_ESCAPES) {
|
|
2309
|
+
cp2 = CLASS_ESCAPES[e];
|
|
2087
2310
|
i += 2;
|
|
2088
2311
|
} else if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
|
|
2089
2312
|
else {
|
|
@@ -2190,7 +2413,7 @@ function rangesSubset(sub, sup) {
|
|
|
2190
2413
|
}
|
|
2191
2414
|
function parseClassOperand(body) {
|
|
2192
2415
|
if (body === "\\d" || body === "\\w" || body === "\\s") {
|
|
2193
|
-
return { ranges:
|
|
2416
|
+
return { ranges: shorthandRanges(body[1]), negated: false };
|
|
2194
2417
|
}
|
|
2195
2418
|
if (body.length >= 2 && body[0] === "[" && body[body.length - 1] === "]") {
|
|
2196
2419
|
let inner = body.slice(1, -1);
|
|
@@ -2623,7 +2846,7 @@ function parseScanShapeCore(source) {
|
|
|
2623
2846
|
}
|
|
2624
2847
|
m = /^\\([dws])([+*])$/.exec(source);
|
|
2625
2848
|
if (m) {
|
|
2626
|
-
return { kind: "chars", ranges:
|
|
2849
|
+
return { kind: "chars", ranges: shorthandRanges(m[1]), minOne: m[2] === "+" };
|
|
2627
2850
|
}
|
|
2628
2851
|
m = /^(\[(?:\\.|[^\]])+\]|\\[dws])(\[(?:\\.|[^\]])+\]|\\[dws])\*$/.exec(source);
|
|
2629
2852
|
if (m) {
|
|
@@ -3165,21 +3388,22 @@ function emitScannableTerminal(shape, c) {
|
|
|
3165
3388
|
}
|
|
3166
3389
|
|
|
3167
3390
|
// src/compiler/inline-build.ts
|
|
3168
|
-
var MK_BUILD_RE = /^\(\s*(
|
|
3391
|
+
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*$/;
|
|
3169
3392
|
function escapeRegExp(s) {
|
|
3170
3393
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3171
3394
|
}
|
|
3172
3395
|
function looseMkBuildRe(type) {
|
|
3173
3396
|
return new RegExp(
|
|
3174
|
-
String.raw`^\(\s*(
|
|
3397
|
+
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*$`
|
|
3175
3398
|
);
|
|
3176
3399
|
}
|
|
3177
3400
|
function analyzeMkInlineBuild(def) {
|
|
3178
3401
|
if (!def.build) return null;
|
|
3402
|
+
if (def.type === void 0) return null;
|
|
3179
3403
|
const src = (def.buildSrc ?? def.build.toString()).trim();
|
|
3180
3404
|
const strict = src.match(MK_BUILD_RE);
|
|
3181
3405
|
if (strict) {
|
|
3182
|
-
const mkType = strict[
|
|
3406
|
+
const mkType = strict[6];
|
|
3183
3407
|
return mkType === def.type ? def.type : null;
|
|
3184
3408
|
}
|
|
3185
3409
|
if (looseMkBuildRe(def.type).test(src)) return def.type;
|
|
@@ -3514,8 +3738,9 @@ function planDisjointDispatch(parsers) {
|
|
|
3514
3738
|
}
|
|
3515
3739
|
return total >= SWITCH_MIN_CASES ? { kind: "switch", cases } : { kind: "if" };
|
|
3516
3740
|
}
|
|
3517
|
-
function captureRestoreBody(mL, mR, mTl, mLg) {
|
|
3518
|
-
const
|
|
3741
|
+
function captureRestoreBody(mL, mR, mTl, mLg, mF = null) {
|
|
3742
|
+
const fieldRestore = mF ? `; if (_ctx._fields) _ctx._fields.length = ${mF}` : "";
|
|
3743
|
+
const base = `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${mL}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${mR}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${mTl}${fieldRestore}`;
|
|
3519
3744
|
return mLg ? `${base}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${mLg}` : base;
|
|
3520
3745
|
}
|
|
3521
3746
|
function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -3563,6 +3788,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
3563
3788
|
// Delegating wrappers: defer to the wrapped parser.
|
|
3564
3789
|
case "transform":
|
|
3565
3790
|
case "label":
|
|
3791
|
+
case "field":
|
|
3566
3792
|
case "expect":
|
|
3567
3793
|
case "withCtx":
|
|
3568
3794
|
case "grammar":
|
|
@@ -3609,6 +3835,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
3609
3835
|
case "optional":
|
|
3610
3836
|
case "transform":
|
|
3611
3837
|
case "label":
|
|
3838
|
+
case "field":
|
|
3612
3839
|
case "expect":
|
|
3613
3840
|
case "withCtx":
|
|
3614
3841
|
case "grammar":
|
|
@@ -3646,22 +3873,25 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
3646
3873
|
ctx.recordFail = savedRecord;
|
|
3647
3874
|
const ind0 = ind(ctx);
|
|
3648
3875
|
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
3876
|
+
const needsFieldRollback = needsRollback && parserHasOwnFields(inner);
|
|
3649
3877
|
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
3650
3878
|
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
3651
3879
|
const mTl = needsRollback ? v(ctx, "_fctl") : null;
|
|
3880
|
+
const mF = needsFieldRollback ? v(ctx, "_fcf") : null;
|
|
3652
3881
|
const stmts = [
|
|
3653
3882
|
`${ind0}let ${okV} = false, ${valV}, ${endV} = ${pos}`,
|
|
3654
3883
|
...mL ? [
|
|
3655
3884
|
`${ind0}const ${mL} = _ctx._cstLeaves?.length ?? 0`,
|
|
3656
3885
|
`${ind0}const ${mR} = _ctx._cstRawChildren?.length ?? 0`,
|
|
3657
|
-
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0
|
|
3886
|
+
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
3887
|
+
...mF ? [`${ind0}const ${mF} = _ctx._fields?.length ?? 0`] : []
|
|
3658
3888
|
] : [],
|
|
3659
3889
|
`${ind0}${lbl}: {`,
|
|
3660
3890
|
...r.stmts,
|
|
3661
3891
|
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
3662
3892
|
`${ind0}}`,
|
|
3663
3893
|
...mL ? [
|
|
3664
|
-
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null)} }`
|
|
3894
|
+
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
|
|
3665
3895
|
] : []
|
|
3666
3896
|
];
|
|
3667
3897
|
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
@@ -3888,6 +4118,7 @@ function failsAtStart(p) {
|
|
|
3888
4118
|
return true;
|
|
3889
4119
|
case "transform":
|
|
3890
4120
|
case "label":
|
|
4121
|
+
case "field":
|
|
3891
4122
|
return failsAtStart(d.parser);
|
|
3892
4123
|
default:
|
|
3893
4124
|
return false;
|
|
@@ -3907,6 +4138,7 @@ function canMatchEmptyAtStart(p) {
|
|
|
3907
4138
|
return true;
|
|
3908
4139
|
case "transform":
|
|
3909
4140
|
case "label":
|
|
4141
|
+
case "field":
|
|
3910
4142
|
return canMatchEmptyAtStart(d.parser);
|
|
3911
4143
|
case "literal":
|
|
3912
4144
|
return d.value.length === 0;
|
|
@@ -4089,11 +4321,13 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4089
4321
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
4090
4322
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
4091
4323
|
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
4324
|
+
const armNeedsFieldRollback = armNeedsRollback && parserHasOwnFields(p);
|
|
4092
4325
|
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
4093
4326
|
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
4094
4327
|
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
4095
4328
|
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
4096
|
-
const
|
|
4329
|
+
const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
|
|
4330
|
+
const rollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
|
|
4097
4331
|
const failSlot = atStart ? staticFx : "_ctx._fx";
|
|
4098
4332
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
4099
4333
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
@@ -4103,7 +4337,8 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4103
4337
|
`${ind(ctx)}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
|
|
4104
4338
|
`${ind(ctx)}const ${markRaw} = _ctx._cstRawChildren?.length ?? 0`,
|
|
4105
4339
|
`${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
4106
|
-
`${ind(ctx)}const ${markLog} = _ctx._triviaLog?.length ?? 0
|
|
4340
|
+
`${ind(ctx)}const ${markLog} = _ctx._triviaLog?.length ?? 0`,
|
|
4341
|
+
...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
|
|
4107
4342
|
);
|
|
4108
4343
|
}
|
|
4109
4344
|
const { stmts: armStmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos, atStart);
|
|
@@ -4496,6 +4731,9 @@ function emitToken(def, ctx, pos) {
|
|
|
4496
4731
|
};
|
|
4497
4732
|
}
|
|
4498
4733
|
function emitNode(def, ctx, pos) {
|
|
4734
|
+
if (def.type === void 0) {
|
|
4735
|
+
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
4736
|
+
}
|
|
4499
4737
|
const structural = def.build === void 0;
|
|
4500
4738
|
const mkType = structural ? null : analyzeMkInlineBuild(def);
|
|
4501
4739
|
let buildIdx = null;
|
|
@@ -4507,25 +4745,36 @@ function emitNode(def, ctx, pos) {
|
|
|
4507
4745
|
const i = ind(ctx);
|
|
4508
4746
|
const capturesTrivia = mkType !== null || !structural && buildReadsTrivia(def);
|
|
4509
4747
|
const clonesState = !structural && buildReadsState(def);
|
|
4748
|
+
const hasFields = parserHasOwnFields(def.parser);
|
|
4749
|
+
const capturesFields = hasFields && !structural && buildReadsFields(def);
|
|
4510
4750
|
const chV = v(ctx, "_ch");
|
|
4511
4751
|
const rawV = v(ctx, "_raw");
|
|
4512
4752
|
const capTLv = structural ? v(ctx, "_ctl") : null;
|
|
4513
4753
|
const capSTv = structural ? v(ctx, "_cst") : null;
|
|
4754
|
+
const capFv = structural && hasFields ? v(ctx, "_cf") : null;
|
|
4514
4755
|
const tlV = capturesTrivia || structural ? v(ctx, "_tl") : "_EMPTY_TL";
|
|
4515
4756
|
if (!capturesTrivia) ctx.needsEmptyTl = true;
|
|
4516
4757
|
const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
|
|
4517
4758
|
if (structural) ctx.needsHostReads = true;
|
|
4518
|
-
const
|
|
4759
|
+
const hostTriviaGate = `_ctx.build !== undefined && (_ctx.build._parsemanCaptureTrivia !== undefined ? _ctx.build._parsemanCaptureTrivia(${JSON.stringify(def.type)}) : (_ctx._pmCapTL ??= _hostReads(_ctx.build, 5)))`;
|
|
4760
|
+
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)` : ""}
|
|
4519
4761
|
${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capturesTrivia ? `${i}const ${chV} = [], ${rawV} = [], ${tlV} = []` : `${i}const ${chV} = [], ${rawV} = []`;
|
|
4520
4762
|
const innerTl = structural ? `${capTLv} ? ${tlV} : undefined` : capturesTrivia ? tlV : "undefined";
|
|
4763
|
+
const fieldsOn = structural ? capFv ?? "false" : capturesFields ? "true" : "false";
|
|
4764
|
+
const sf = hasFields ? v(ctx, "_sf") : null;
|
|
4765
|
+
const fArr = hasFields ? v(ctx, "_fa") : null;
|
|
4766
|
+
const fObj = hasFields ? v(ctx, "_fields") : "undefined";
|
|
4521
4767
|
const stmts = [
|
|
4522
4768
|
allocStmt,
|
|
4523
|
-
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog`,
|
|
4524
|
-
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}`
|
|
4769
|
+
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
4770
|
+
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
|
|
4525
4771
|
];
|
|
4526
4772
|
const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
4527
4773
|
stmts.push(...innerStmts);
|
|
4528
|
-
|
|
4774
|
+
if (sf && fArr) {
|
|
4775
|
+
stmts.push(`${i}const ${fArr} = _ctx._fields`);
|
|
4776
|
+
}
|
|
4777
|
+
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${sf ? `; _ctx._fields = ${sf}` : ""}`);
|
|
4529
4778
|
stmts.push(...emitIfFail(ctx, `!${okVar}`, propagateFailBody(ctx)));
|
|
4530
4779
|
let stV = "undefined";
|
|
4531
4780
|
if (structural) {
|
|
@@ -4535,14 +4784,33 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
4535
4784
|
stV = v(ctx, "_nst");
|
|
4536
4785
|
stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
|
|
4537
4786
|
}
|
|
4787
|
+
if (sf && fArr) {
|
|
4788
|
+
const fe = v(ctx, "_fe");
|
|
4789
|
+
const cur = v(ctx, "_fc");
|
|
4790
|
+
stmts.push(
|
|
4791
|
+
`${i}let ${fObj} = undefined`,
|
|
4792
|
+
`${i}if (${fArr} && ${fArr}.length) {`,
|
|
4793
|
+
`${i} ${fObj} = {}`,
|
|
4794
|
+
`${i} for (const ${fe} of ${fArr}) {`,
|
|
4795
|
+
`${i} const ${cur} = ${fObj}[${fe}.name], _entry = { value: ${fe}.value, span: ${fe}.span }`,
|
|
4796
|
+
`${i} if (${cur} === undefined) ${fObj}[${fe}.name] = _entry`,
|
|
4797
|
+
`${i} else if (Array.isArray(${cur})) ${cur}.push(_entry)`,
|
|
4798
|
+
`${i} else ${fObj}[${fe}.name] = [${cur}, _entry]`,
|
|
4799
|
+
`${i} }`,
|
|
4800
|
+
`${i}}`
|
|
4801
|
+
);
|
|
4802
|
+
}
|
|
4538
4803
|
const ndV = v(ctx, "_nd");
|
|
4539
|
-
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}, ${
|
|
4540
|
-
const ndExpr = ctx.ns || structural ? `_ctx.build !== undefined ? _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${
|
|
4541
|
-
const
|
|
4804
|
+
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})`;
|
|
4805
|
+
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;
|
|
4806
|
+
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;
|
|
4807
|
+
const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
|
|
4808
|
+
const collapseExpr = `${chV}.length === 1 ? ${chV}[0] : (${ndExpr})`;
|
|
4809
|
+
const finalExpr = def.unwrap ? unwrapExpr : def.collapse ? collapseExpr : hostCollapseExpr;
|
|
4542
4810
|
stmts.push(
|
|
4543
4811
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
4544
4812
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
4545
|
-
`${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} } })`
|
|
4813
|
+
`${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} } })`
|
|
4546
4814
|
);
|
|
4547
4815
|
return { stmts, valueVar: ndV, endVar };
|
|
4548
4816
|
}
|
|
@@ -4757,6 +5025,17 @@ function emitDispatch(p, ctx, pos) {
|
|
|
4757
5025
|
endVar: inner.endVar
|
|
4758
5026
|
};
|
|
4759
5027
|
}
|
|
5028
|
+
case "field": {
|
|
5029
|
+
const inner = emit(def.parser, ctx, pos);
|
|
5030
|
+
return {
|
|
5031
|
+
stmts: [
|
|
5032
|
+
...inner.stmts,
|
|
5033
|
+
`${ind(ctx)}if (_ctx._fields) _ctx._fields.push({ name: ${JSON.stringify(def.name)}, value: ${inner.valueVar}, span: { start: ${pos}, end: ${inner.endVar} } })`
|
|
5034
|
+
],
|
|
5035
|
+
valueVar: inner.valueVar,
|
|
5036
|
+
endVar: inner.endVar
|
|
5037
|
+
};
|
|
5038
|
+
}
|
|
4760
5039
|
case "grammar": {
|
|
4761
5040
|
const savedTrivia = ctx.activeTrivia;
|
|
4762
5041
|
const savedKindLabels = ctx.triviaKindLabels;
|
|
@@ -4858,6 +5137,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4858
5137
|
case "trivia":
|
|
4859
5138
|
case "token":
|
|
4860
5139
|
case "label":
|
|
5140
|
+
case "field":
|
|
4861
5141
|
case "optional":
|
|
4862
5142
|
case "many":
|
|
4863
5143
|
case "oneOrMore":
|
|
@@ -4894,6 +5174,7 @@ function childrenOf(def) {
|
|
|
4894
5174
|
case "trivia":
|
|
4895
5175
|
case "token":
|
|
4896
5176
|
case "label":
|
|
5177
|
+
case "field":
|
|
4897
5178
|
case "grammar":
|
|
4898
5179
|
case "not":
|
|
4899
5180
|
case "node":
|
|
@@ -5135,6 +5416,11 @@ function assertRuleName(name) {
|
|
|
5135
5416
|
);
|
|
5136
5417
|
}
|
|
5137
5418
|
}
|
|
5419
|
+
function publicRuleWrapperSource(rule, fnSource) {
|
|
5420
|
+
const labels = rule._meta.triviaKindLabels;
|
|
5421
|
+
if (labels === void 0) return fnSource;
|
|
5422
|
+
return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
|
|
5423
|
+
}
|
|
5138
5424
|
function compileRuleMap(ruleMap) {
|
|
5139
5425
|
for (const [, rule] of ruleMap) markUnusedValues(rule);
|
|
5140
5426
|
const ctx = {
|
|
@@ -5167,7 +5453,7 @@ function compileRuleMap(ruleMap) {
|
|
|
5167
5453
|
ruleNames.set(rule, n === 0 ? base : `${base}$${n}`);
|
|
5168
5454
|
}
|
|
5169
5455
|
ctx.ruleNames = ruleNames;
|
|
5170
|
-
const perEntry = ruleMap.map(([key, rule]) => ({ key, r: emit(rule, ctx, "_pos") }));
|
|
5456
|
+
const perEntry = ruleMap.map(([key, rule]) => ({ key, rule, r: emit(rule, ctx, "_pos") }));
|
|
5171
5457
|
const derivedSrcs = ctx.mapFnSrcs.length === ctx.mapFns.length && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : void 0;
|
|
5172
5458
|
const buildCovered = ctx.buildFns.length === 0 || ctx.buildSrcs.every((s) => s !== null);
|
|
5173
5459
|
const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
|
|
@@ -5197,7 +5483,10 @@ function compileRuleMap(ruleMap) {
|
|
|
5197
5483
|
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
5198
5484
|
`}`
|
|
5199
5485
|
].join("\n");
|
|
5200
|
-
const objBody = perEntry.map(({ key, r }) =>
|
|
5486
|
+
const objBody = perEntry.map(({ key, rule, r }) => {
|
|
5487
|
+
const src = publicRuleWrapperSource(rule, entryFnText(r));
|
|
5488
|
+
return ` ${JSON.stringify(key)}: ${src.split("\n").join("\n ")}`;
|
|
5489
|
+
}).join(",\n");
|
|
5201
5490
|
const replacement = [
|
|
5202
5491
|
`/* @__PURE__ */ (() => {`,
|
|
5203
5492
|
...hoistedDecls,
|
|
@@ -5310,7 +5599,7 @@ function compileLinkable(ruleMapArg, ns) {
|
|
|
5310
5599
|
ctx.recordFail = savedRec;
|
|
5311
5600
|
pushNamedFnDecl(ctx, fn, body.stmts, body.valueVar, body.endVar);
|
|
5312
5601
|
}
|
|
5313
|
-
perEntry.push({ key, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
5602
|
+
perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
5314
5603
|
}
|
|
5315
5604
|
if (ctx.runtimeParsers.length !== 0) return null;
|
|
5316
5605
|
const mfSrcs = ctx.mapFns.length > 0 && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : null;
|
|
@@ -5333,14 +5622,14 @@ function compileLinkable(ruleMapArg, ns) {
|
|
|
5333
5622
|
...privateFns
|
|
5334
5623
|
].filter(Boolean);
|
|
5335
5624
|
const wrappers = /* @__PURE__ */ new Map();
|
|
5336
|
-
for (const { key, r } of perEntry) {
|
|
5337
|
-
wrappers.set(key, [
|
|
5625
|
+
for (const { key, rule, r } of perEntry) {
|
|
5626
|
+
wrappers.set(key, publicRuleWrapperSource(rule, [
|
|
5338
5627
|
`function(input, _pos, _ctx) {`,
|
|
5339
5628
|
` let pos = _pos`,
|
|
5340
5629
|
...r.stmts,
|
|
5341
5630
|
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
5342
5631
|
`}`
|
|
5343
|
-
].join("\n"));
|
|
5632
|
+
].join("\n")));
|
|
5344
5633
|
}
|
|
5345
5634
|
const firstSets = /* @__PURE__ */ new Map();
|
|
5346
5635
|
for (const [key, rule] of ruleMap) {
|
|
@@ -5515,6 +5804,7 @@ function childrenOf2(def) {
|
|
|
5515
5804
|
case "trivia":
|
|
5516
5805
|
case "token":
|
|
5517
5806
|
case "label":
|
|
5807
|
+
case "field":
|
|
5518
5808
|
case "not":
|
|
5519
5809
|
case "node":
|
|
5520
5810
|
case "expect":
|
|
@@ -5600,6 +5890,7 @@ function evalRuleMapIR(ir) {
|
|
|
5600
5890
|
"skip",
|
|
5601
5891
|
"trivia",
|
|
5602
5892
|
"label",
|
|
5893
|
+
"field",
|
|
5603
5894
|
"expect",
|
|
5604
5895
|
"_tf",
|
|
5605
5896
|
"_nd",
|
|
@@ -5626,6 +5917,7 @@ function evalRuleMapIR(ir) {
|
|
|
5626
5917
|
skip,
|
|
5627
5918
|
trivia,
|
|
5628
5919
|
label,
|
|
5920
|
+
field,
|
|
5629
5921
|
expect,
|
|
5630
5922
|
_tf,
|
|
5631
5923
|
_nd
|
|
@@ -5759,6 +6051,8 @@ ${body}
|
|
|
5759
6051
|
return `token(${kid(def.parser)})`;
|
|
5760
6052
|
case "label":
|
|
5761
6053
|
return `label(${JSON.stringify(def.label)}, ${kid(def.parser)})`;
|
|
6054
|
+
case "field":
|
|
6055
|
+
return `field(${JSON.stringify(def.name)}, ${kid(def.parser)})`;
|
|
5762
6056
|
case "expect":
|
|
5763
6057
|
return `expect(${kid(def.parser)}${def.label !== void 0 ? `, ${JSON.stringify(def.label)}` : ""})`;
|
|
5764
6058
|
case "skip":
|
|
@@ -5771,7 +6065,11 @@ ${body}
|
|
|
5771
6065
|
}
|
|
5772
6066
|
case "node": {
|
|
5773
6067
|
if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
|
|
5774
|
-
const opts = def.collapse ? `, { collapse: true }` : "";
|
|
6068
|
+
const opts = def.unwrap || def.collapse ? `, { ${def.unwrap ? "unwrap: true" : "collapse: true"} }` : "";
|
|
6069
|
+
if (def.type === void 0) {
|
|
6070
|
+
if (def.buildSrc !== void 0) throw new Unserializable("inferred node build without inferred type");
|
|
6071
|
+
return opts ? `node(${kid(def.parser)}, undefined${opts})` : `node(${kid(def.parser)})`;
|
|
6072
|
+
}
|
|
5775
6073
|
if (def.buildSrc !== void 0) return `_nd(${JSON.stringify(def.type)}, ${kid(def.parser)}, ${JSON.stringify(def.buildSrc)}${opts})`;
|
|
5776
6074
|
return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
|
|
5777
6075
|
}
|
|
@@ -5798,8 +6096,9 @@ function fusedBody(pieces) {
|
|
|
5798
6096
|
}
|
|
5799
6097
|
}
|
|
5800
6098
|
const contributing = new Set(winner.values());
|
|
5801
|
-
const
|
|
5802
|
-
const
|
|
6099
|
+
const contributingPieces = [...contributing];
|
|
6100
|
+
const needsEmptyTl = contributingPieces.some((p) => p.needsEmptyTl);
|
|
6101
|
+
const needsHostReads = contributingPieces.some((p) => p.needsHostReads);
|
|
5803
6102
|
const lines = [
|
|
5804
6103
|
// Shared sentinel protocol (must match NAMED_FN_FAIL / NAMED_FN_END in codegen).
|
|
5805
6104
|
"const _pfFail = {}",
|
|
@@ -5807,7 +6106,7 @@ function fusedBody(pieces) {
|
|
|
5807
6106
|
...needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [],
|
|
5808
6107
|
...needsHostReads ? [HOST_READS_DECL] : [],
|
|
5809
6108
|
// Each contributing artifact's namespaced private prelude (regexes, _pf, …).
|
|
5810
|
-
...[...
|
|
6109
|
+
...[...new Set(contributingPieces.flatMap((p) => p.prelude))],
|
|
5811
6110
|
// The winning `_r_<Name>` function for each rule (one per name → no redeclare).
|
|
5812
6111
|
...[...winner].map(([k, p]) => p.ruleFns.get(k))
|
|
5813
6112
|
];
|
|
@@ -5830,7 +6129,7 @@ function fusedBody(pieces) {
|
|
|
5830
6129
|
}
|
|
5831
6130
|
);
|
|
5832
6131
|
const env = {};
|
|
5833
|
-
for (const p of
|
|
6132
|
+
for (const p of contributingPieces) {
|
|
5834
6133
|
if (p.mfFns.length) env[`${p.ns}mf`] = p.mfFns;
|
|
5835
6134
|
if (p.buildFns.length) env[`${p.ns}build`] = p.buildFns;
|
|
5836
6135
|
}
|
|
@@ -5878,6 +6177,7 @@ var SUPPORTED = {
|
|
|
5878
6177
|
sepBy: (...a) => sepBy(a[0], a[1]),
|
|
5879
6178
|
trivia: (...a) => trivia(a[0]),
|
|
5880
6179
|
label: (...a) => label(a[0], a[1]),
|
|
6180
|
+
field: (...a) => field(a[0], a[1]),
|
|
5881
6181
|
noTrivia: (...a) => noTrivia(a[0]),
|
|
5882
6182
|
token: (...a) => token(a[0]),
|
|
5883
6183
|
expect: (...a) => expect(a[0], a[1])
|
|
@@ -5898,19 +6198,20 @@ function scopeGet(scope, name, mfs) {
|
|
|
5898
6198
|
if (isCombinator(entry)) return entry;
|
|
5899
6199
|
return null;
|
|
5900
6200
|
}
|
|
5901
|
-
function
|
|
5902
|
-
if (expr.type !== "ObjectExpression") return
|
|
6201
|
+
function staticNodeOptions(expr) {
|
|
6202
|
+
if (expr.type !== "ObjectExpression") return void 0;
|
|
6203
|
+
const opts = {};
|
|
5903
6204
|
for (const prop of expr.properties) {
|
|
5904
6205
|
const p = prop;
|
|
5905
6206
|
if (p.computed) continue;
|
|
5906
6207
|
const key = p.key;
|
|
5907
6208
|
const name = key.type === "Identifier" ? key.name : key.type === "Literal" ? String(key.value) : void 0;
|
|
5908
|
-
if (name === "collapse") {
|
|
6209
|
+
if (name === "unwrap" || name === "collapse") {
|
|
5909
6210
|
const val = p.value;
|
|
5910
|
-
|
|
6211
|
+
if ((val.type === "Literal" || val.type === "BooleanLiteral") && val.value === true) opts[name] = true;
|
|
5911
6212
|
}
|
|
5912
6213
|
}
|
|
5913
|
-
return
|
|
6214
|
+
return opts.unwrap || opts.collapse ? opts : void 0;
|
|
5914
6215
|
}
|
|
5915
6216
|
function exprToCombi(node2, scope, code, mfs) {
|
|
5916
6217
|
if (node2.type === "Identifier") return scopeGet(scope, node2.name, mfs);
|
|
@@ -5960,18 +6261,22 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
5960
6261
|
}
|
|
5961
6262
|
}
|
|
5962
6263
|
if (callee.name === "node" && code !== void 0) {
|
|
5963
|
-
const [
|
|
5964
|
-
if (!
|
|
5965
|
-
const
|
|
5966
|
-
|
|
6264
|
+
const [firstArg, secondArg, thirdArg, fourthArg] = node2.arguments;
|
|
6265
|
+
if (!firstArg || firstArg.type === "SpreadElement") return null;
|
|
6266
|
+
const firstVal = anyValue(firstArg, scope, code, mfs);
|
|
6267
|
+
const explicitType = typeof firstVal === "string" ? firstVal : void 0;
|
|
6268
|
+
const parserArg = explicitType !== void 0 ? secondArg : firstArg;
|
|
6269
|
+
const buildArg = explicitType !== void 0 ? thirdArg : secondArg;
|
|
6270
|
+
const optsArg = explicitType !== void 0 ? fourthArg : thirdArg;
|
|
6271
|
+
if (!parserArg || parserArg.type === "SpreadElement") return null;
|
|
5967
6272
|
const inner = anyValue(parserArg, scope, code, mfs);
|
|
5968
6273
|
if (!isCombinator(inner)) return null;
|
|
5969
6274
|
const be = buildArg;
|
|
5970
6275
|
const hasBuild = be !== void 0 && be.type !== "SpreadElement" && !(be.type === "Identifier" && be.name === "undefined");
|
|
5971
6276
|
const buildSrc = hasBuild ? code.slice(be.start, be.end) : void 0;
|
|
5972
|
-
const
|
|
6277
|
+
const opts = optsArg !== void 0 && optsArg.type !== "SpreadElement" ? staticNodeOptions(optsArg) : void 0;
|
|
5973
6278
|
try {
|
|
5974
|
-
const combi = node(
|
|
6279
|
+
const combi = explicitType !== void 0 ? node(explicitType, inner, hasBuild ? () => null : void 0, opts) : node(inner, hasBuild ? () => null : void 0, opts);
|
|
5975
6280
|
if (combi._def.tag === "node" && buildSrc !== void 0) combi._def.buildSrc = buildSrc;
|
|
5976
6281
|
return combi;
|
|
5977
6282
|
} catch {
|
|
@@ -6237,7 +6542,9 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
6237
6542
|
if (!keys) return null;
|
|
6238
6543
|
const ruleRefs = /* @__PURE__ */ new Map();
|
|
6239
6544
|
const tagRef = (r, name) => {
|
|
6545
|
+
;
|
|
6240
6546
|
r._ruleName = name;
|
|
6547
|
+
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = name;
|
|
6241
6548
|
};
|
|
6242
6549
|
for (const key of keys) {
|
|
6243
6550
|
if (!ruleRefs.has(key)) {
|
|
@@ -6269,6 +6576,7 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
6269
6576
|
for (const [key, e] of finalByKey) {
|
|
6270
6577
|
const val = anyValue(e.value, e.scope, e.code, mapFnSources);
|
|
6271
6578
|
if (!isCombinator(val)) return null;
|
|
6579
|
+
tagRef(val, key);
|
|
6272
6580
|
ruleRefs.get(key).define(val);
|
|
6273
6581
|
}
|
|
6274
6582
|
return ruleRefs;
|