parseman 0.42.1 → 0.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/combinators/attempt.d.ts.map +1 -1
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/grammar.d.ts +7 -0
- package/dist/combinators/grammar.d.ts.map +1 -1
- package/dist/combinators/map.d.ts +11 -0
- package/dist/combinators/map.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +21 -7
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/combinators/parser.d.ts +17 -2
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/combinators/token.d.ts +3 -2
- package/dist/combinators/token.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/codegen.d.ts +4 -0
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +6 -1
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/compiler/scannable-run.d.ts +1 -1
- package/dist/compiler/scannable-run.d.ts.map +1 -1
- package/dist/compiler/trivia-fast-path.d.ts +4 -3
- package/dist/compiler/trivia-fast-path.d.ts.map +1 -1
- package/dist/cst/reflection.d.ts +24 -0
- package/dist/cst/reflection.d.ts.map +1 -0
- package/dist/cst/trivia-entries.d.ts +15 -9
- package/dist/cst/trivia-entries.d.ts.map +1 -1
- package/dist/cst/trivia-kinds.d.ts +15 -11
- package/dist/cst/trivia-kinds.d.ts.map +1 -1
- package/dist/cst/types.d.ts +2 -0
- package/dist/cst/types.d.ts.map +1 -1
- package/dist/cst/walk.d.ts +27 -62
- package/dist/cst/walk.d.ts.map +1 -1
- package/dist/functional/run.d.ts +22 -16
- package/dist/functional/run.d.ts.map +1 -1
- package/dist/index.cjs +1651 -1207
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +6 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1651 -1207
- package/dist/index.js.map +4 -4
- package/dist/language-service/index.cjs +186 -135
- package/dist/language-service/index.cjs.map +4 -4
- package/dist/language-service/index.d.ts +1 -1
- package/dist/language-service/index.d.ts.map +1 -1
- package/dist/language-service/index.js +186 -135
- package/dist/language-service/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts +1 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +1525 -1048
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +1525 -1048
- package/dist/plugin/index.js.map +4 -4
- package/dist/run/index.cjs +152 -102
- package/dist/run/index.cjs.map +3 -3
- package/dist/run/index.d.ts +1 -1
- package/dist/run/index.d.ts.map +1 -1
- package/dist/run/index.js +152 -102
- package/dist/run/index.js.map +3 -3
- package/dist/spec/index.cjs +1381 -1152
- package/dist/spec/index.cjs.map +4 -4
- package/dist/spec/index.js +1381 -1152
- package/dist/spec/index.js.map +4 -4
- package/dist/types.d.ts +27 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/spec/index.js
CHANGED
|
@@ -576,864 +576,631 @@ function pushTriviaLogEntry(ctx, start, end, kindIndex) {
|
|
|
576
576
|
}
|
|
577
577
|
}
|
|
578
578
|
|
|
579
|
-
// src/
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
_cstChildren: ctx._cstChildren,
|
|
586
|
-
_cstRawChildren: ctx._cstRawChildren,
|
|
587
|
-
_cstTriviaLog: ctx._cstTriviaLog,
|
|
588
|
-
_triviaLog: ctx._triviaLog,
|
|
589
|
-
_fields: ctx._fields,
|
|
590
|
-
_cstBuf: ctx._cstBuf,
|
|
591
|
-
_tolerant: ctx._tolerant,
|
|
592
|
-
_sync: ctx._sync
|
|
593
|
-
};
|
|
594
|
-
ctx._probe = void 0;
|
|
595
|
-
ctx._errors = void 0;
|
|
596
|
-
ctx._cstLeaves = void 0;
|
|
597
|
-
ctx._cstChildren = void 0;
|
|
598
|
-
ctx._cstRawChildren = void 0;
|
|
599
|
-
ctx._cstTriviaLog = void 0;
|
|
600
|
-
ctx._triviaLog = void 0;
|
|
601
|
-
ctx._fields = void 0;
|
|
602
|
-
ctx._cstBuf = void 0;
|
|
603
|
-
ctx._tolerant = void 0;
|
|
604
|
-
ctx._sync = void 0;
|
|
605
|
-
try {
|
|
606
|
-
return sentinel.parse(input, pos, ctx).ok;
|
|
607
|
-
} finally {
|
|
608
|
-
ctx._probe = s._probe;
|
|
609
|
-
ctx._errors = s._errors;
|
|
610
|
-
ctx._cstLeaves = s._cstLeaves;
|
|
611
|
-
ctx._cstChildren = s._cstChildren;
|
|
612
|
-
ctx._cstRawChildren = s._cstRawChildren;
|
|
613
|
-
ctx._cstTriviaLog = s._cstTriviaLog;
|
|
614
|
-
ctx._triviaLog = s._triviaLog;
|
|
615
|
-
ctx._fields = s._fields;
|
|
616
|
-
ctx._cstBuf = s._cstBuf;
|
|
617
|
-
ctx._tolerant = s._tolerant;
|
|
618
|
-
ctx._sync = s._sync;
|
|
619
|
-
}
|
|
579
|
+
// src/cst/trivia-kinds.ts
|
|
580
|
+
var labeledTriviaSpecs = /* @__PURE__ */ new WeakMap();
|
|
581
|
+
function unwrapTrivia(p) {
|
|
582
|
+
let cur = p;
|
|
583
|
+
while (cur._def.tag === "trivia") cur = cur._def.parser;
|
|
584
|
+
return cur;
|
|
620
585
|
}
|
|
621
|
-
function
|
|
622
|
-
if (
|
|
623
|
-
return
|
|
624
|
-
_tag: "orSentinel",
|
|
625
|
-
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
626
|
-
_def: { tag: "unknown" },
|
|
627
|
-
parse(input, pos, ctx) {
|
|
628
|
-
const ra = a.parse(input, pos, ctx);
|
|
629
|
-
if (ra.ok) return ra;
|
|
630
|
-
return b.parse(input, pos, ctx);
|
|
631
|
-
}
|
|
632
|
-
};
|
|
586
|
+
function peelLabel(p) {
|
|
587
|
+
if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
|
|
588
|
+
return null;
|
|
633
589
|
}
|
|
634
|
-
function
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
590
|
+
function analyzeLabeledTrivia(trivia2) {
|
|
591
|
+
const cached = labeledTriviaSpecs.get(trivia2);
|
|
592
|
+
if (cached !== void 0) return cached;
|
|
593
|
+
let core = unwrapTrivia(trivia2);
|
|
594
|
+
let minRepeats = 1;
|
|
595
|
+
if (core._def.tag === "oneOrMore") {
|
|
596
|
+
core = core._def.parser;
|
|
597
|
+
minRepeats = 1;
|
|
598
|
+
} else if (core._def.tag === "many") {
|
|
599
|
+
core = core._def.parser;
|
|
600
|
+
minRepeats = 0;
|
|
601
|
+
}
|
|
602
|
+
const arms = [];
|
|
603
|
+
if (core._def.tag === "choice") {
|
|
604
|
+
for (let i = 0; i < core._def.parsers.length; i++) {
|
|
605
|
+
const peeled = peelLabel(core._def.parsers[i]);
|
|
606
|
+
if (!peeled) {
|
|
607
|
+
labeledTriviaSpecs.set(trivia2, null);
|
|
608
|
+
return null;
|
|
647
609
|
}
|
|
648
|
-
|
|
610
|
+
arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
|
|
611
|
+
}
|
|
612
|
+
} else {
|
|
613
|
+
const peeled = peelLabel(core);
|
|
614
|
+
if (!peeled) {
|
|
615
|
+
labeledTriviaSpecs.set(trivia2, null);
|
|
616
|
+
return null;
|
|
649
617
|
}
|
|
618
|
+
arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
|
|
619
|
+
}
|
|
620
|
+
const spec = {
|
|
621
|
+
labels: arms.map((a) => a.label),
|
|
622
|
+
arms,
|
|
623
|
+
minRepeats
|
|
650
624
|
};
|
|
625
|
+
labeledTriviaSpecs.set(trivia2, spec);
|
|
626
|
+
return spec;
|
|
651
627
|
}
|
|
652
|
-
function
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
|
|
658
|
-
ctx._errors?.push(error);
|
|
659
|
-
return { error, end: scanPos };
|
|
660
|
-
}
|
|
661
|
-
function matchesAt(sentinel, input, pos, ctx) {
|
|
662
|
-
return probeAt(sentinel, input, pos, ctx);
|
|
628
|
+
function matchArmAt(input, pos, arm, state) {
|
|
629
|
+
if (!startsFirstSet(arm, input, pos)) return null;
|
|
630
|
+
const r = arm.parse(input, pos, { trackLines: false, state });
|
|
631
|
+
if (!r.ok || r.span.end <= pos) return null;
|
|
632
|
+
return { end: r.span.end };
|
|
663
633
|
}
|
|
664
|
-
function
|
|
665
|
-
|
|
634
|
+
function scanLabeledTriviaChunks(input, cur, spec, state) {
|
|
635
|
+
const chunks = [];
|
|
636
|
+
let pos = cur;
|
|
637
|
+
while (pos < input.length) {
|
|
638
|
+
let matched = null;
|
|
639
|
+
for (const arm of spec.arms) {
|
|
640
|
+
const m = matchArmAt(input, pos, arm.parser, state);
|
|
641
|
+
if (m) {
|
|
642
|
+
matched = { end: m.end, kindIndex: arm.kindIndex };
|
|
643
|
+
break;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
if (!matched) break;
|
|
647
|
+
chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
|
|
648
|
+
pos = matched.end;
|
|
649
|
+
}
|
|
650
|
+
if (chunks.length < spec.minRepeats) {
|
|
651
|
+
return { end: cur, chunks: [] };
|
|
652
|
+
}
|
|
653
|
+
return { end: pos, chunks };
|
|
666
654
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
655
|
+
function scanLabeledTriviaEnd(input, cur, spec, state) {
|
|
656
|
+
let pos = cur;
|
|
657
|
+
let count = 0;
|
|
658
|
+
while (pos < input.length) {
|
|
659
|
+
let matched = null;
|
|
660
|
+
for (const arm of spec.arms) {
|
|
661
|
+
matched = matchArmAt(input, pos, arm.parser, state);
|
|
662
|
+
if (matched) break;
|
|
663
|
+
}
|
|
664
|
+
if (!matched) break;
|
|
665
|
+
pos = matched.end;
|
|
666
|
+
count++;
|
|
667
|
+
}
|
|
668
|
+
return count < spec.minRepeats ? cur : pos;
|
|
671
669
|
}
|
|
672
|
-
function
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
return [def.label];
|
|
684
|
-
case "choice":
|
|
685
|
-
return def.parsers.flatMap(deriveExpected2);
|
|
686
|
-
case "dispatch":
|
|
687
|
-
return deriveExpected2(def.selector);
|
|
688
|
-
// Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
|
|
689
|
-
// `optional(…)`/`many(…)` can match nothing, so the term after it is equally
|
|
690
|
-
// able to fail first — deriving from term 0 alone named a token the parse
|
|
691
|
-
// never actually required. A leading `not(…)` is zero-width and contributes
|
|
692
|
-
// nothing (its own expectation is about what must NOT be here), but it is
|
|
693
|
-
// nullable, so keep scanning past it. Stop at the first term that must match.
|
|
694
|
-
case "sequence": {
|
|
695
|
-
const out = [];
|
|
696
|
-
for (const term of def.parsers) {
|
|
697
|
-
if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
|
|
698
|
-
if (!matchesEmpty(term)) break;
|
|
670
|
+
function visitLabeledTrivia(input, cur, spec, state, visit) {
|
|
671
|
+
if (spec.minRepeats > 1) return void 0;
|
|
672
|
+
let pos = cur;
|
|
673
|
+
let count = 0;
|
|
674
|
+
while (pos < input.length) {
|
|
675
|
+
let matched = null;
|
|
676
|
+
for (const arm of spec.arms) {
|
|
677
|
+
const match = matchArmAt(input, pos, arm.parser, state);
|
|
678
|
+
if (match) {
|
|
679
|
+
matched = { end: match.end, kindIndex: arm.kindIndex };
|
|
680
|
+
break;
|
|
699
681
|
}
|
|
700
|
-
return out;
|
|
701
682
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
case "not":
|
|
725
|
-
case "peek":
|
|
726
|
-
return deriveExpected2(def.parser);
|
|
727
|
-
case "routed":
|
|
728
|
-
return ["routed()"];
|
|
729
|
-
case "lazy": {
|
|
730
|
-
const name = c._ruleName;
|
|
731
|
-
if (seen.has(c)) return name ? [name] : [];
|
|
732
|
-
seen.add(c);
|
|
733
|
-
try {
|
|
734
|
-
return deriveExpected2(def.thunk());
|
|
735
|
-
} catch {
|
|
736
|
-
return name ? [name] : [];
|
|
737
|
-
} finally {
|
|
738
|
-
seen.delete(c);
|
|
683
|
+
if (!matched) break;
|
|
684
|
+
visit(pos, matched.end, matched.kindIndex);
|
|
685
|
+
pos = matched.end;
|
|
686
|
+
count++;
|
|
687
|
+
}
|
|
688
|
+
return count < spec.minRepeats ? cur : pos;
|
|
689
|
+
}
|
|
690
|
+
function recordTriviaChunks(ctx, chunks) {
|
|
691
|
+
const kinds = ctx.triviaKindLabels;
|
|
692
|
+
const mask = ctx._triviaCaptureMask;
|
|
693
|
+
const rootLog = ctx._rootTriviaLog;
|
|
694
|
+
const rootKinds = ctx._rootTriviaKindIndex;
|
|
695
|
+
const rootMark = rootLog?.length ?? 0;
|
|
696
|
+
for (const ch of chunks) {
|
|
697
|
+
pushTriviaLogEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
698
|
+
const rootKindIndex = ctx._rootTriviaCapture === false || rootLog === void 0 || rootKinds === void 0 || kinds === void 0 ? -1 : rootKinds[kinds[ch.kindIndex] ?? ""] ?? -1;
|
|
699
|
+
if (rootKindIndex >= 0) {
|
|
700
|
+
rootLog.push(0, 0, ch.start, ch.end, rootKindIndex);
|
|
701
|
+
}
|
|
702
|
+
if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
|
|
703
|
+
if (mask === void 0 || kinds === void 0 || (mask & 1 << ch.kindIndex) !== 0) {
|
|
704
|
+
pushCstTriviaEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
739
705
|
}
|
|
740
706
|
}
|
|
741
|
-
default:
|
|
742
|
-
return [];
|
|
743
707
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
isTrivia: false
|
|
751
|
-
};
|
|
752
|
-
return {
|
|
753
|
-
_tag: "expect",
|
|
754
|
-
_meta: meta,
|
|
755
|
-
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
756
|
-
parse(input, pos, ctx) {
|
|
757
|
-
const result = combinator.parse(input, pos, ctx);
|
|
758
|
-
if (result.ok) return result;
|
|
759
|
-
const span = { start: pos, end: pos };
|
|
760
|
-
const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
|
|
761
|
-
ctx._errors?.push(error);
|
|
762
|
-
if (ctx._tolerant) captureError(ctx, error);
|
|
763
|
-
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
708
|
+
if (rootLog !== void 0 && rootLog.length !== rootMark && chunks.length > 0) {
|
|
709
|
+
const start = chunks[0].start;
|
|
710
|
+
const end = chunks[chunks.length - 1].end;
|
|
711
|
+
for (let offset = rootMark; offset < rootLog.length; offset += 5) {
|
|
712
|
+
rootLog[offset] = start;
|
|
713
|
+
rootLog[offset + 1] = end;
|
|
764
714
|
}
|
|
765
|
-
}
|
|
715
|
+
}
|
|
766
716
|
}
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
const
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
717
|
+
function triviaKindMask(labels, keep) {
|
|
718
|
+
if (!labels) return void 0;
|
|
719
|
+
let mask = 0;
|
|
720
|
+
for (const name of keep) {
|
|
721
|
+
const idx = labels.indexOf(name);
|
|
722
|
+
if (idx >= 0) mask |= 1 << idx;
|
|
723
|
+
}
|
|
724
|
+
return mask;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// src/combinators/grammar.ts
|
|
728
|
+
function annotateResultLines(result, index) {
|
|
729
|
+
const annotated = { ...result, span: annotateSpan(result.span, index) };
|
|
730
|
+
const errors = annotated.errors;
|
|
731
|
+
if (errors) {
|
|
732
|
+
;
|
|
733
|
+
annotated.errors = errors.map((error) => ({
|
|
734
|
+
...error,
|
|
735
|
+
span: annotateSpan(error.span, index)
|
|
736
|
+
}));
|
|
737
|
+
}
|
|
738
|
+
return annotated;
|
|
739
|
+
}
|
|
740
|
+
function createParseLineContext(input, pos) {
|
|
741
|
+
const lineIndex = createLineIndex();
|
|
742
|
+
if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
|
|
743
|
+
return { lineIndex, lineScannedTo: pos };
|
|
744
|
+
}
|
|
745
|
+
function parser(opts, root) {
|
|
746
|
+
const clearTrivia = opts.trivia === null;
|
|
747
|
+
const opaqueRootCapture = opts.rootCapture === "opaque";
|
|
748
|
+
if (opaqueRootCapture && opts.trivia === void 0) {
|
|
749
|
+
throw new TypeError("parser({ rootCapture: 'opaque' }) requires an explicit trivia scope.");
|
|
796
750
|
}
|
|
797
751
|
return {
|
|
798
|
-
_tag: "
|
|
799
|
-
_meta:
|
|
752
|
+
_tag: "grammar",
|
|
753
|
+
_meta: {
|
|
754
|
+
...root._meta,
|
|
755
|
+
// Trivia classification describes this grammar's own active trivia
|
|
756
|
+
// scope. A directly nested grammar may have classified trivia of its
|
|
757
|
+
// own, but that must not advertise classification for this wrapper.
|
|
758
|
+
triviaKindLabels: void 0,
|
|
759
|
+
rootTriviaClassified: void 0,
|
|
760
|
+
...opts.trivia?._meta?.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {},
|
|
761
|
+
...opts.trivia?._meta?.rootTriviaClassified ? { rootTriviaClassified: true } : {}
|
|
762
|
+
},
|
|
800
763
|
_def: {
|
|
801
|
-
tag: "
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
764
|
+
tag: "grammar",
|
|
765
|
+
parser: root,
|
|
766
|
+
triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
|
|
767
|
+
clearTrivia,
|
|
768
|
+
...opaqueRootCapture ? { rootCapture: "opaque" } : {},
|
|
769
|
+
...opts.captureTrivia ? { captureTrivia: true } : {},
|
|
770
|
+
trackLines: opts.trackLines ?? false
|
|
807
771
|
},
|
|
808
|
-
parse(input, pos,
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
if (idx < 0) {
|
|
814
|
-
for (let i = 0; i < parsers.length; i++) {
|
|
815
|
-
if (inFirstSet(code, parsers[i]._meta.firstSet)) {
|
|
816
|
-
idx = i;
|
|
817
|
-
break;
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
if (idx >= 0) {
|
|
822
|
-
const gate = gates[idx];
|
|
823
|
-
if (gate && !gate(ctx.state)) {
|
|
824
|
-
return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
|
|
825
|
-
}
|
|
826
|
-
const result = parsers[idx].parse(input, pos, ctx);
|
|
827
|
-
if (result.ok) return result;
|
|
828
|
-
expected.push(...result.expected);
|
|
829
|
-
if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
|
|
830
|
-
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
831
|
-
}
|
|
832
|
-
return {
|
|
833
|
-
ok: false,
|
|
834
|
-
expected: parsers.flatMap((p) => {
|
|
835
|
-
const r = p.parse(input, pos, ctx);
|
|
836
|
-
return r.ok ? [] : r.expected;
|
|
837
|
-
}),
|
|
838
|
-
span: { start: pos, end: pos }
|
|
839
|
-
};
|
|
840
|
-
}
|
|
841
|
-
if (strategy?.tag === "greedyClassify") {
|
|
842
|
-
const superResult = parsers[strategy.superIndex].parse(input, pos, ctx);
|
|
843
|
-
if (!superResult.ok) return superResult;
|
|
844
|
-
const end = superResult.span.end;
|
|
845
|
-
const litIdx = greedyLitMap.get(input.slice(pos, end));
|
|
846
|
-
if (litIdx !== void 0) {
|
|
847
|
-
const litVal = getCoreLiteralValue(parsers[litIdx]);
|
|
848
|
-
const value = applyTransforms(parsers[litIdx], litVal, { start: pos, end });
|
|
849
|
-
return { ok: true, value, span: { start: pos, end } };
|
|
850
|
-
}
|
|
851
|
-
return superResult;
|
|
852
|
-
}
|
|
853
|
-
if (strategy?.tag === "literalsLongestFirst") {
|
|
854
|
-
for (const p of sortedParsers) {
|
|
855
|
-
const r = p.parse(input, pos, ctx);
|
|
856
|
-
if (r.ok) return r;
|
|
857
|
-
expected.push(...r.expected);
|
|
858
|
-
}
|
|
859
|
-
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
772
|
+
parse(input, pos, _ctx) {
|
|
773
|
+
if (_ctx?._rootTriviaStrictScopes && opts.trivia !== void 0 && opts.trivia !== null && !opts.trivia._meta.rootTriviaClassified && !opaqueRootCapture) {
|
|
774
|
+
throw new TypeError(
|
|
775
|
+
"parser(): selected root trivia requires classifiedTrivia() for every local trivia scope, or rootCapture: 'opaque'."
|
|
776
|
+
);
|
|
860
777
|
}
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
778
|
+
const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
|
|
779
|
+
const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
|
|
780
|
+
const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
|
|
781
|
+
const ctx = {
|
|
782
|
+
..._ctx,
|
|
783
|
+
trackLines,
|
|
784
|
+
...lineIndex ? { _lineIndex: lineIndex } : {},
|
|
785
|
+
...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
|
|
786
|
+
// trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
|
|
787
|
+
...clearTrivia ? {
|
|
788
|
+
trivia: void 0,
|
|
789
|
+
triviaKindLabels: void 0
|
|
790
|
+
} : opts.trivia != null ? {
|
|
791
|
+
trivia: opts.trivia,
|
|
792
|
+
...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
|
|
793
|
+
} : {},
|
|
794
|
+
...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
|
|
795
|
+
// Kind-filter for per-node capture. Resolve against this scope's trivia
|
|
796
|
+
// labels — this parser's own trivia if it declares one, else the INHERITED
|
|
797
|
+
// labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
|
|
798
|
+
// trivia is inherited rather than re-declared here. No labels → undefined
|
|
799
|
+
// (capture all).
|
|
800
|
+
...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {},
|
|
801
|
+
// This is a property of the local trivia scope, not a post-parse filter:
|
|
802
|
+
// nested recognition can still skip its trivia, but selected root rows
|
|
803
|
+
// must never be written for an explicitly opaque region.
|
|
804
|
+
...opaqueRootCapture ? { _rootTriviaCapture: false } : {}
|
|
805
|
+
};
|
|
806
|
+
const result = root.parse(input, pos ?? 0, ctx);
|
|
807
|
+
if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
|
|
808
|
+
_ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
|
|
880
809
|
}
|
|
881
|
-
return
|
|
810
|
+
return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
|
|
882
811
|
}
|
|
883
812
|
};
|
|
884
813
|
}
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
814
|
+
|
|
815
|
+
// src/cst/reflection.ts
|
|
816
|
+
var GRAMMAR_REFLECTION = /* @__PURE__ */ Symbol.for("parseman.grammarReflection");
|
|
817
|
+
function childrenOf(def) {
|
|
818
|
+
switch (def.tag) {
|
|
819
|
+
case "sequence":
|
|
820
|
+
case "choice":
|
|
821
|
+
return def.parsers;
|
|
822
|
+
case "dispatch":
|
|
823
|
+
return [
|
|
824
|
+
def.selector,
|
|
825
|
+
...def.cases.map((c) => c.parser),
|
|
826
|
+
...def.matchers ? def.matchers.map((c) => c.parser) : [],
|
|
827
|
+
...def.otherwise ? [def.otherwise] : []
|
|
828
|
+
];
|
|
829
|
+
case "many":
|
|
830
|
+
case "oneOrMore":
|
|
831
|
+
case "optional":
|
|
832
|
+
case "attempt":
|
|
833
|
+
case "transform":
|
|
834
|
+
case "trivia":
|
|
835
|
+
case "token":
|
|
836
|
+
case "leaf":
|
|
837
|
+
case "label":
|
|
838
|
+
case "field":
|
|
839
|
+
case "not":
|
|
840
|
+
case "peek":
|
|
841
|
+
case "node":
|
|
842
|
+
case "withCtx":
|
|
843
|
+
case "recover":
|
|
844
|
+
case "expect":
|
|
845
|
+
return [def.parser];
|
|
846
|
+
case "grammar":
|
|
847
|
+
return def.triviaParser ? [def.parser, def.triviaParser] : [def.parser];
|
|
848
|
+
case "sepBy":
|
|
849
|
+
return [def.parser, def.separator];
|
|
850
|
+
case "skip":
|
|
851
|
+
return [def.main, def.skipped];
|
|
852
|
+
case "scanTo":
|
|
853
|
+
return [def.sentinel, ...def.skip];
|
|
854
|
+
case "literal":
|
|
855
|
+
case "regex":
|
|
856
|
+
case "keywords":
|
|
857
|
+
case "routed":
|
|
858
|
+
case "guard":
|
|
859
|
+
case "lazy":
|
|
860
|
+
case "unknown":
|
|
861
|
+
return [];
|
|
910
862
|
}
|
|
911
|
-
const shared = detectSharedPrefix(parsers);
|
|
912
|
-
if (shared !== null) return shared;
|
|
913
|
-
return { tag: "firstMatch" };
|
|
914
|
-
}
|
|
915
|
-
function bareLeadingTermKey(term) {
|
|
916
|
-
const d = term._def;
|
|
917
|
-
if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
|
|
918
|
-
if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
|
|
919
|
-
return null;
|
|
920
863
|
}
|
|
921
|
-
function
|
|
922
|
-
if (
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
const term0 = leadingTermOfArm(parsers[i]);
|
|
928
|
-
if (term0 === null) return null;
|
|
929
|
-
const k = bareLeadingTermKey(term0);
|
|
930
|
-
if (k === null) return null;
|
|
931
|
-
if (key === null) {
|
|
932
|
-
key = k;
|
|
933
|
-
prefix = term0;
|
|
934
|
-
} else if (k !== key) return null;
|
|
935
|
-
members.push(i);
|
|
864
|
+
function addNode(out, def) {
|
|
865
|
+
if (def.type === void 0) return;
|
|
866
|
+
const existing = out.get(def.type);
|
|
867
|
+
if (existing === void 0) {
|
|
868
|
+
out.set(def.type, def.tags === void 0 ? [] : [...def.tags]);
|
|
869
|
+
return;
|
|
936
870
|
}
|
|
937
|
-
if (
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
function leadingTermOfArm(arm) {
|
|
941
|
-
let d = arm._def;
|
|
942
|
-
for (; ; ) {
|
|
943
|
-
if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
|
|
944
|
-
d = d.parser._def;
|
|
945
|
-
continue;
|
|
946
|
-
}
|
|
947
|
-
break;
|
|
871
|
+
if (def.tags === void 0) return;
|
|
872
|
+
for (const tag of def.tags) {
|
|
873
|
+
if (!existing.includes(tag)) existing.push(tag);
|
|
948
874
|
}
|
|
949
|
-
if (d.tag !== "sequence" || d.parsers.length < 2) return null;
|
|
950
|
-
return d.parsers[0];
|
|
951
875
|
}
|
|
952
|
-
function
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
checks.push({ kind: "startsWith", value: otherLit.slice(litVal.length) });
|
|
962
|
-
continue;
|
|
963
|
-
}
|
|
964
|
-
const regexDef = getCoreRegexDef(other);
|
|
965
|
-
if (regexDef !== null) {
|
|
966
|
-
const contSet = continuationFirstSet(litVal, regexDef.source, regexDef.flags);
|
|
967
|
-
if (contSet !== null) checks.push({ kind: "firstSet", set: contSet });
|
|
876
|
+
function collectFromCombinator(parser2, out, seen, followLazy = true) {
|
|
877
|
+
if (seen.has(parser2)) return;
|
|
878
|
+
seen.add(parser2);
|
|
879
|
+
const def = parser2._def;
|
|
880
|
+
if (def.tag === "lazy") {
|
|
881
|
+
if (followLazy) {
|
|
882
|
+
try {
|
|
883
|
+
collectFromCombinator(def.thunk(), out, seen, followLazy);
|
|
884
|
+
} catch {
|
|
968
885
|
}
|
|
969
886
|
}
|
|
970
|
-
return
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
if (def.tag === "node") addNode(out, def);
|
|
890
|
+
for (const child of childrenOf(def)) collectFromCombinator(child, out, seen, followLazy);
|
|
891
|
+
}
|
|
892
|
+
function collectGrammarReflection(ruleMap, opts) {
|
|
893
|
+
const byType = /* @__PURE__ */ new Map();
|
|
894
|
+
const followLazy = opts?.followLazy !== false;
|
|
895
|
+
for (const [, rule] of ruleMap) {
|
|
896
|
+
if (!followLazy && rule._def.tag === "lazy") {
|
|
897
|
+
try {
|
|
898
|
+
const resolved = rule._def.thunk();
|
|
899
|
+
if (resolved._def.tag !== "lazy") collectFromCombinator(resolved, byType, /* @__PURE__ */ new Set(), false);
|
|
900
|
+
} catch {
|
|
901
|
+
}
|
|
902
|
+
continue;
|
|
980
903
|
}
|
|
904
|
+
collectFromCombinator(rule, byType, /* @__PURE__ */ new Set(), followLazy);
|
|
981
905
|
}
|
|
982
|
-
return
|
|
983
|
-
}
|
|
984
|
-
function getCoreLiteralValue(p) {
|
|
985
|
-
const def = p._def;
|
|
986
|
-
if (def.tag === "literal" && !def.caseInsensitive) return def.value;
|
|
987
|
-
if (def.tag === "transform") return getCoreLiteralValue(def.parser);
|
|
988
|
-
return null;
|
|
989
|
-
}
|
|
990
|
-
function getCoreRegexDef(p) {
|
|
991
|
-
const def = p._def;
|
|
992
|
-
if (def.tag === "regex") return { source: def.source, flags: def.flags };
|
|
993
|
-
if (def.tag === "transform") return getCoreRegexDef(def.parser);
|
|
994
|
-
if (def.tag === "label") return getCoreRegexDef(def.parser);
|
|
995
|
-
return null;
|
|
906
|
+
return { nodes: [...byType].map(([type, tags]) => ({ type, tags })) };
|
|
996
907
|
}
|
|
997
|
-
function
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
const inner = applyTransforms(def.parser, value, span);
|
|
1001
|
-
return def.fn(inner, span);
|
|
1002
|
-
}
|
|
1003
|
-
return value;
|
|
908
|
+
function attachGrammarReflection(grammar, reflection) {
|
|
909
|
+
Object.defineProperty(grammar, GRAMMAR_REFLECTION, { value: reflection, enumerable: false, configurable: true });
|
|
910
|
+
return grammar;
|
|
1004
911
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
re.lastIndex = 0;
|
|
1013
|
-
const m = re.exec(lit + String.fromCharCode(code));
|
|
1014
|
-
if (m && m[0].length > lit.length) contCodes.push(code);
|
|
1015
|
-
}
|
|
1016
|
-
if (contCodes.length === 0) return null;
|
|
1017
|
-
return codesToFirstSet(contCodes);
|
|
912
|
+
|
|
913
|
+
// src/combinators/parser.ts
|
|
914
|
+
var RULE_ORDER = "__parsemanRuleOrder";
|
|
915
|
+
function tagRule(r, key) {
|
|
916
|
+
;
|
|
917
|
+
r._ruleName = key;
|
|
918
|
+
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
|
|
1018
919
|
}
|
|
1019
|
-
function
|
|
1020
|
-
|
|
1021
|
-
const ranges = [];
|
|
1022
|
-
let lo = codes[0], hi = codes[0];
|
|
1023
|
-
for (let i = 1; i < codes.length; i++) {
|
|
1024
|
-
if (codes[i] === hi + 1) {
|
|
1025
|
-
hi = codes[i];
|
|
1026
|
-
} else {
|
|
1027
|
-
ranges.push({ lo, hi });
|
|
1028
|
-
lo = hi = codes[i];
|
|
1029
|
-
}
|
|
1030
|
-
}
|
|
1031
|
-
ranges.push({ lo, hi });
|
|
1032
|
-
return { kind: "ranges", ranges };
|
|
920
|
+
function isDefinableRef(v) {
|
|
921
|
+
return !!v && typeof v === "object" && "_def" in v && v._def.tag === "lazy" && typeof v.define === "function";
|
|
1033
922
|
}
|
|
1034
|
-
function
|
|
1035
|
-
|
|
1036
|
-
if (fs.kind === "empty") return false;
|
|
1037
|
-
for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
1038
|
-
return false;
|
|
923
|
+
function ruleNameOf(r) {
|
|
924
|
+
return r._ruleName;
|
|
1039
925
|
}
|
|
1040
|
-
function
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
for (let j2 = i + 1; j2 < sets.length; j2++)
|
|
1044
|
-
if (intersects(sets[i], sets[j2])) return false;
|
|
1045
|
-
return true;
|
|
926
|
+
function isNamedRuleRefForAnotherRule(r, key) {
|
|
927
|
+
const name = r._def.tag === "lazy" ? ruleNameOf(r) : void 0;
|
|
928
|
+
return name !== void 0 && name !== key;
|
|
1046
929
|
}
|
|
1047
|
-
function
|
|
1048
|
-
const
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
930
|
+
function rules(a, b) {
|
|
931
|
+
const factory = typeof a === "function" ? a : b;
|
|
932
|
+
const options = typeof a === "function" ? b : a;
|
|
933
|
+
const cache = {};
|
|
934
|
+
const proxy = new Proxy(cache, {
|
|
935
|
+
get(target, key) {
|
|
936
|
+
if (typeof key !== "string") return void 0;
|
|
937
|
+
const record = target;
|
|
938
|
+
if (!(key in record)) {
|
|
939
|
+
const r = ref();
|
|
940
|
+
tagRule(r, key);
|
|
941
|
+
record[key] = r;
|
|
1055
942
|
}
|
|
943
|
+
return record[key];
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
const definitions = factory(proxy);
|
|
947
|
+
for (const key of Object.keys(definitions)) {
|
|
948
|
+
const placeholder = cache[key];
|
|
949
|
+
const parser2 = definitions[key];
|
|
950
|
+
if (placeholder === parser2) {
|
|
951
|
+
throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
|
|
952
|
+
}
|
|
953
|
+
if (isDefinableRef(placeholder)) {
|
|
954
|
+
if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
|
|
955
|
+
placeholder.define(parser2);
|
|
956
|
+
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
957
|
+
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
958
|
+
} else if (isNamedRuleRefForAnotherRule(parser2, key)) {
|
|
959
|
+
const alias = ref();
|
|
960
|
+
tagRule(alias, key);
|
|
961
|
+
alias.define(parser2);
|
|
962
|
+
alias._meta.firstSet = parser2._meta.firstSet;
|
|
963
|
+
alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
964
|
+
cache[key] = alias;
|
|
965
|
+
} else {
|
|
966
|
+
tagRule(parser2, key);
|
|
967
|
+
cache[key] = parser2;
|
|
1056
968
|
}
|
|
1057
969
|
}
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
function unwrapTrivia(p) {
|
|
1063
|
-
let cur = p;
|
|
1064
|
-
while (cur._def.tag === "trivia") cur = cur._def.parser;
|
|
1065
|
-
return cur;
|
|
1066
|
-
}
|
|
1067
|
-
function peelLabel(p) {
|
|
1068
|
-
if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
|
|
1069
|
-
return null;
|
|
1070
|
-
}
|
|
1071
|
-
function analyzeLabeledTrivia(trivia2) {
|
|
1072
|
-
let core = unwrapTrivia(trivia2);
|
|
1073
|
-
let minRepeats = 1;
|
|
1074
|
-
if (core._def.tag === "oneOrMore") {
|
|
1075
|
-
core = core._def.parser;
|
|
1076
|
-
minRepeats = 1;
|
|
1077
|
-
} else if (core._def.tag === "many") {
|
|
1078
|
-
core = core._def.parser;
|
|
1079
|
-
minRepeats = 0;
|
|
1080
|
-
}
|
|
1081
|
-
const arms = [];
|
|
1082
|
-
if (core._def.tag === "choice") {
|
|
1083
|
-
for (let i = 0; i < core._def.parsers.length; i++) {
|
|
1084
|
-
const peeled = peelLabel(core._def.parsers[i]);
|
|
1085
|
-
if (!peeled) return null;
|
|
1086
|
-
arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
|
|
970
|
+
if (options?.trivia != null) {
|
|
971
|
+
for (const key of Object.keys(definitions)) {
|
|
972
|
+
const rule = cache[key];
|
|
973
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
1087
974
|
}
|
|
1088
|
-
} else {
|
|
1089
|
-
const peeled = peelLabel(core);
|
|
1090
|
-
if (!peeled) return null;
|
|
1091
|
-
arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
|
|
1092
975
|
}
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
if (!r.ok || r.span.end <= pos) return null;
|
|
1098
|
-
return { end: r.span.end };
|
|
1099
|
-
}
|
|
1100
|
-
function scanLabeledTriviaChunks(input, cur, spec) {
|
|
1101
|
-
const chunks = [];
|
|
1102
|
-
let pos = cur;
|
|
1103
|
-
while (pos < input.length) {
|
|
1104
|
-
let matched = null;
|
|
1105
|
-
for (const arm of spec.arms) {
|
|
1106
|
-
const m = matchArmAt(input, pos, arm.parser);
|
|
1107
|
-
if (m) {
|
|
1108
|
-
matched = { end: m.end, kindIndex: arm.kindIndex };
|
|
1109
|
-
break;
|
|
1110
|
-
}
|
|
976
|
+
if (options?.scanSkip != null) {
|
|
977
|
+
for (const key of Object.keys(definitions)) {
|
|
978
|
+
const rule = cache[key];
|
|
979
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarScanSkip = options.scanSkip;
|
|
1111
980
|
}
|
|
1112
|
-
if (!matched) break;
|
|
1113
|
-
chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
|
|
1114
|
-
pos = matched.end;
|
|
1115
981
|
}
|
|
1116
|
-
if (
|
|
1117
|
-
|
|
982
|
+
if (options?.hostMode === "cst") {
|
|
983
|
+
for (const key of Object.keys(definitions)) {
|
|
984
|
+
const rule = cache[key];
|
|
985
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarHostMode = "cst";
|
|
986
|
+
}
|
|
1118
987
|
}
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
let pos = cur;
|
|
1124
|
-
while (pos < input.length) {
|
|
1125
|
-
const c = input.charCodeAt(pos);
|
|
1126
|
-
if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {
|
|
1127
|
-
const start = pos;
|
|
1128
|
-
pos++;
|
|
1129
|
-
while (pos < input.length) {
|
|
1130
|
-
const c2 = input.charCodeAt(pos);
|
|
1131
|
-
if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) pos++;
|
|
1132
|
-
else break;
|
|
1133
|
-
}
|
|
1134
|
-
chunks.push({ start, end: pos, kindIndex: wsKind });
|
|
1135
|
-
continue;
|
|
988
|
+
if (options?.trackLines === true) {
|
|
989
|
+
for (const key of Object.keys(definitions)) {
|
|
990
|
+
const rule = cache[key];
|
|
991
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrackLines = true;
|
|
1136
992
|
}
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
continue;
|
|
993
|
+
for (const key of Object.keys(definitions)) {
|
|
994
|
+
const rule = cache[key];
|
|
995
|
+
if (rule && !rule._meta.isTrivia && rule._def.tag !== "grammar") {
|
|
996
|
+
const wrapped = parser({ trackLines: true }, rule);
|
|
997
|
+
tagRule(wrapped, key);
|
|
998
|
+
wrapped._meta.grammarTrackLines = true;
|
|
999
|
+
cache[key] = wrapped;
|
|
1145
1000
|
}
|
|
1146
|
-
break;
|
|
1147
1001
|
}
|
|
1148
|
-
break;
|
|
1149
1002
|
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
return src != null && !src.includes("\\*");
|
|
1158
|
-
});
|
|
1159
|
-
const commentArm = spec.arms.find((a) => {
|
|
1160
|
-
const src = getCoreRegexDef(a.parser)?.source;
|
|
1161
|
-
return src != null && src.includes("\\*");
|
|
1003
|
+
for (const key of Object.keys(definitions)) {
|
|
1004
|
+
markUnusedValues(cache[key]);
|
|
1005
|
+
}
|
|
1006
|
+
Object.defineProperty(cache, RULE_ORDER, {
|
|
1007
|
+
value: Object.keys(definitions),
|
|
1008
|
+
enumerable: false,
|
|
1009
|
+
configurable: true
|
|
1162
1010
|
});
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
|
|
1166
|
-
return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
|
|
1167
|
-
}
|
|
1168
|
-
function recordTriviaChunks(ctx, chunks) {
|
|
1169
|
-
const kinds = ctx.triviaKindLabels;
|
|
1170
|
-
const mask = ctx._triviaCaptureMask;
|
|
1171
|
-
for (const ch of chunks) {
|
|
1172
|
-
pushTriviaLogEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
1173
|
-
if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
|
|
1174
|
-
if (mask === void 0 || kinds === void 0 || (mask & 1 << ch.kindIndex) !== 0) {
|
|
1175
|
-
pushCstTriviaEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
}
|
|
1180
|
-
function triviaKindMask(labels, keep) {
|
|
1181
|
-
if (!labels) return void 0;
|
|
1182
|
-
let mask = 0;
|
|
1183
|
-
for (const name of keep) {
|
|
1184
|
-
const idx = labels.indexOf(name);
|
|
1185
|
-
if (idx >= 0) mask |= 1 << idx;
|
|
1186
|
-
}
|
|
1187
|
-
return mask;
|
|
1011
|
+
attachGrammarReflection(cache, collectGrammarReflection(Object.keys(definitions).map((key) => [key, cache[key]])));
|
|
1012
|
+
return cache;
|
|
1188
1013
|
}
|
|
1189
1014
|
|
|
1190
|
-
// src/
|
|
1191
|
-
function
|
|
1192
|
-
const
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1015
|
+
// src/recovery/scan.ts
|
|
1016
|
+
function probeAt(sentinel, input, pos, ctx) {
|
|
1017
|
+
const s = {
|
|
1018
|
+
_probe: ctx._probe,
|
|
1019
|
+
_errors: ctx._errors,
|
|
1020
|
+
_cstLeaves: ctx._cstLeaves,
|
|
1021
|
+
_cstChildren: ctx._cstChildren,
|
|
1022
|
+
_cstRawChildren: ctx._cstRawChildren,
|
|
1023
|
+
_cstTriviaLog: ctx._cstTriviaLog,
|
|
1024
|
+
_triviaLog: ctx._triviaLog,
|
|
1025
|
+
_rootTriviaLog: ctx._rootTriviaLog,
|
|
1026
|
+
_fields: ctx._fields,
|
|
1027
|
+
_cstBuf: ctx._cstBuf,
|
|
1028
|
+
_tolerant: ctx._tolerant,
|
|
1029
|
+
_sync: ctx._sync
|
|
1030
|
+
};
|
|
1031
|
+
ctx._probe = void 0;
|
|
1032
|
+
ctx._errors = void 0;
|
|
1033
|
+
ctx._cstLeaves = void 0;
|
|
1034
|
+
ctx._cstChildren = void 0;
|
|
1035
|
+
ctx._cstRawChildren = void 0;
|
|
1036
|
+
ctx._cstTriviaLog = void 0;
|
|
1037
|
+
ctx._triviaLog = void 0;
|
|
1038
|
+
ctx._rootTriviaLog = void 0;
|
|
1039
|
+
ctx._fields = void 0;
|
|
1040
|
+
ctx._cstBuf = void 0;
|
|
1041
|
+
ctx._tolerant = void 0;
|
|
1042
|
+
ctx._sync = void 0;
|
|
1043
|
+
try {
|
|
1044
|
+
return sentinel.parse(input, pos, ctx).ok;
|
|
1045
|
+
} finally {
|
|
1046
|
+
ctx._probe = s._probe;
|
|
1047
|
+
ctx._errors = s._errors;
|
|
1048
|
+
ctx._cstLeaves = s._cstLeaves;
|
|
1049
|
+
ctx._cstChildren = s._cstChildren;
|
|
1050
|
+
ctx._cstRawChildren = s._cstRawChildren;
|
|
1051
|
+
ctx._cstTriviaLog = s._cstTriviaLog;
|
|
1052
|
+
ctx._triviaLog = s._triviaLog;
|
|
1053
|
+
ctx._rootTriviaLog = s._rootTriviaLog;
|
|
1054
|
+
ctx._fields = s._fields;
|
|
1055
|
+
ctx._cstBuf = s._cstBuf;
|
|
1056
|
+
ctx._tolerant = s._tolerant;
|
|
1057
|
+
ctx._sync = s._sync;
|
|
1200
1058
|
}
|
|
1201
|
-
return annotated;
|
|
1202
1059
|
}
|
|
1203
|
-
function
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1060
|
+
function orSentinel(a, b) {
|
|
1061
|
+
if (b === void 0) return a;
|
|
1062
|
+
return {
|
|
1063
|
+
_tag: "orSentinel",
|
|
1064
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
1065
|
+
_def: { tag: "unknown" },
|
|
1066
|
+
parse(input, pos, ctx) {
|
|
1067
|
+
const ra = a.parse(input, pos, ctx);
|
|
1068
|
+
if (ra.ok) return ra;
|
|
1069
|
+
return b.parse(input, pos, ctx);
|
|
1070
|
+
}
|
|
1071
|
+
};
|
|
1207
1072
|
}
|
|
1208
|
-
function
|
|
1209
|
-
|
|
1073
|
+
function firstSetSentinel(fs) {
|
|
1074
|
+
if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
|
|
1075
|
+
const ranges = fs.ranges;
|
|
1210
1076
|
return {
|
|
1211
|
-
_tag: "
|
|
1212
|
-
_meta:
|
|
1213
|
-
_def: {
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
},
|
|
1221
|
-
parse(input, pos, _ctx) {
|
|
1222
|
-
const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
|
|
1223
|
-
const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
|
|
1224
|
-
const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
|
|
1225
|
-
const ctx = {
|
|
1226
|
-
..._ctx,
|
|
1227
|
-
trackLines,
|
|
1228
|
-
...lineIndex ? { _lineIndex: lineIndex } : {},
|
|
1229
|
-
...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
|
|
1230
|
-
// trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
|
|
1231
|
-
...clearTrivia ? {
|
|
1232
|
-
trivia: void 0,
|
|
1233
|
-
triviaKindLabels: void 0
|
|
1234
|
-
} : opts.trivia != null ? {
|
|
1235
|
-
trivia: opts.trivia,
|
|
1236
|
-
...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
|
|
1237
|
-
} : {},
|
|
1238
|
-
...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
|
|
1239
|
-
// Kind-filter for per-node capture. Resolve against this scope's trivia
|
|
1240
|
-
// labels — this parser's own trivia if it declares one, else the INHERITED
|
|
1241
|
-
// labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
|
|
1242
|
-
// trivia is inherited rather than re-declared here. No labels → undefined
|
|
1243
|
-
// (capture all).
|
|
1244
|
-
...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
|
|
1245
|
-
};
|
|
1246
|
-
const result = root.parse(input, pos ?? 0, ctx);
|
|
1247
|
-
if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
|
|
1248
|
-
_ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
|
|
1077
|
+
_tag: "firstSetSentinel",
|
|
1078
|
+
_meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
|
|
1079
|
+
_def: { tag: "unknown" },
|
|
1080
|
+
parse(input, pos) {
|
|
1081
|
+
const code = pos < input.length ? input.codePointAt(pos) : void 0;
|
|
1082
|
+
if (code !== void 0) {
|
|
1083
|
+
for (const r of ranges) {
|
|
1084
|
+
if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
1085
|
+
}
|
|
1249
1086
|
}
|
|
1250
|
-
return
|
|
1087
|
+
return { ok: false, expected: [], span: { start: pos, end: pos } };
|
|
1251
1088
|
}
|
|
1252
1089
|
};
|
|
1253
1090
|
}
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
;
|
|
1259
|
-
|
|
1260
|
-
|
|
1091
|
+
function recoverScan(input, from, ctx, sync, expected) {
|
|
1092
|
+
let scanPos = from;
|
|
1093
|
+
while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
|
|
1094
|
+
const span = { start: from, end: scanPos };
|
|
1095
|
+
if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
|
|
1096
|
+
const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
|
|
1097
|
+
ctx._errors?.push(error);
|
|
1098
|
+
return { error, end: scanPos };
|
|
1261
1099
|
}
|
|
1262
|
-
function
|
|
1263
|
-
return
|
|
1100
|
+
function matchesAt(sentinel, input, pos, ctx) {
|
|
1101
|
+
return probeAt(sentinel, input, pos, ctx);
|
|
1264
1102
|
}
|
|
1265
|
-
function
|
|
1266
|
-
|
|
1103
|
+
function captureError(ctx, error) {
|
|
1104
|
+
if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
|
|
1267
1105
|
}
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1106
|
+
|
|
1107
|
+
// src/combinators/expect.ts
|
|
1108
|
+
function deriveExpected(c) {
|
|
1109
|
+
return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
|
|
1271
1110
|
}
|
|
1272
|
-
function
|
|
1273
|
-
const
|
|
1274
|
-
const
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1111
|
+
function derive(c, seen) {
|
|
1112
|
+
const deriveExpected2 = (p) => derive(p, seen);
|
|
1113
|
+
const def = c._def;
|
|
1114
|
+
switch (def.tag) {
|
|
1115
|
+
case "literal":
|
|
1116
|
+
return [JSON.stringify(def.value)];
|
|
1117
|
+
case "regex":
|
|
1118
|
+
return [`/${def.source}/`];
|
|
1119
|
+
case "keywords":
|
|
1120
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
1121
|
+
case "label":
|
|
1122
|
+
return [def.label];
|
|
1123
|
+
case "choice":
|
|
1124
|
+
return def.parsers.flatMap(deriveExpected2);
|
|
1125
|
+
case "dispatch":
|
|
1126
|
+
return deriveExpected2(def.selector);
|
|
1127
|
+
// Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
|
|
1128
|
+
// `optional(…)`/`many(…)` can match nothing, so the term after it is equally
|
|
1129
|
+
// able to fail first — deriving from term 0 alone named a token the parse
|
|
1130
|
+
// never actually required. A leading `not(…)` is zero-width and contributes
|
|
1131
|
+
// nothing (its own expectation is about what must NOT be here), but it is
|
|
1132
|
+
// nullable, so keep scanning past it. Stop at the first term that must match.
|
|
1133
|
+
case "sequence": {
|
|
1134
|
+
const out = [];
|
|
1135
|
+
for (const term of def.parsers) {
|
|
1136
|
+
if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
|
|
1137
|
+
if (!matchesEmpty(term)) break;
|
|
1284
1138
|
}
|
|
1285
|
-
return
|
|
1139
|
+
return out;
|
|
1286
1140
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1141
|
+
case "attempt":
|
|
1142
|
+
return deriveExpected2(def.parser);
|
|
1143
|
+
// Delegating wrappers whose first-token failure is their inner parser's — must
|
|
1144
|
+
// pass through so a start-failure (and the first-set-miss fast-path in attempt/
|
|
1145
|
+
// node, which reads this) names the real expected token, not the wrapper tag.
|
|
1146
|
+
case "field":
|
|
1147
|
+
case "withCtx":
|
|
1148
|
+
case "recover":
|
|
1149
|
+
return deriveExpected2(def.parser);
|
|
1150
|
+
case "skip":
|
|
1151
|
+
return deriveExpected2(def.main);
|
|
1152
|
+
case "expect":
|
|
1153
|
+
return def.expected;
|
|
1154
|
+
case "node":
|
|
1155
|
+
case "grammar":
|
|
1156
|
+
case "trivia":
|
|
1157
|
+
case "token":
|
|
1158
|
+
case "leaf":
|
|
1159
|
+
case "optional":
|
|
1160
|
+
case "many":
|
|
1161
|
+
case "oneOrMore":
|
|
1162
|
+
case "transform":
|
|
1163
|
+
case "not":
|
|
1164
|
+
case "peek":
|
|
1165
|
+
return deriveExpected2(def.parser);
|
|
1166
|
+
case "routed":
|
|
1167
|
+
return ["routed()"];
|
|
1168
|
+
case "lazy": {
|
|
1169
|
+
const name = c._ruleName;
|
|
1170
|
+
if (seen.has(c)) return name ? [name] : [];
|
|
1171
|
+
seen.add(c);
|
|
1172
|
+
try {
|
|
1173
|
+
return deriveExpected2(def.thunk());
|
|
1174
|
+
} catch {
|
|
1175
|
+
return name ? [name] : [];
|
|
1176
|
+
} finally {
|
|
1177
|
+
seen.delete(c);
|
|
1178
|
+
}
|
|
1294
1179
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
placeholder.define(parser2);
|
|
1298
|
-
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
1299
|
-
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
1300
|
-
} else if (isNamedRuleRefForAnotherRule(parser2, key)) {
|
|
1301
|
-
const alias = ref();
|
|
1302
|
-
tagRule(alias, key);
|
|
1303
|
-
alias.define(parser2);
|
|
1304
|
-
alias._meta.firstSet = parser2._meta.firstSet;
|
|
1305
|
-
alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
1306
|
-
cache[key] = alias;
|
|
1307
|
-
} else {
|
|
1308
|
-
tagRule(parser2, key);
|
|
1309
|
-
cache[key] = parser2;
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
if (options?.trivia != null) {
|
|
1313
|
-
for (const key of Object.keys(definitions)) {
|
|
1314
|
-
const rule = cache[key];
|
|
1315
|
-
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
1316
|
-
}
|
|
1317
|
-
}
|
|
1318
|
-
if (options?.scanSkip != null) {
|
|
1319
|
-
for (const key of Object.keys(definitions)) {
|
|
1320
|
-
const rule = cache[key];
|
|
1321
|
-
if (rule && !rule._meta.isTrivia) rule._meta.grammarScanSkip = options.scanSkip;
|
|
1322
|
-
}
|
|
1323
|
-
}
|
|
1324
|
-
if (options?.hostMode === "cst") {
|
|
1325
|
-
for (const key of Object.keys(definitions)) {
|
|
1326
|
-
const rule = cache[key];
|
|
1327
|
-
if (rule && !rule._meta.isTrivia) rule._meta.grammarHostMode = "cst";
|
|
1328
|
-
}
|
|
1329
|
-
}
|
|
1330
|
-
if (options?.trackLines === true) {
|
|
1331
|
-
for (const key of Object.keys(definitions)) {
|
|
1332
|
-
const rule = cache[key];
|
|
1333
|
-
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrackLines = true;
|
|
1334
|
-
}
|
|
1335
|
-
for (const key of Object.keys(definitions)) {
|
|
1336
|
-
const rule = cache[key];
|
|
1337
|
-
if (rule && !rule._meta.isTrivia && rule._def.tag !== "grammar") {
|
|
1338
|
-
const wrapped = parser({ trackLines: true }, rule);
|
|
1339
|
-
tagRule(wrapped, key);
|
|
1340
|
-
wrapped._meta.grammarTrackLines = true;
|
|
1341
|
-
cache[key] = wrapped;
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
}
|
|
1345
|
-
for (const key of Object.keys(definitions)) {
|
|
1346
|
-
markUnusedValues(cache[key]);
|
|
1347
|
-
}
|
|
1348
|
-
Object.defineProperty(cache, RULE_ORDER, {
|
|
1349
|
-
value: Object.keys(definitions),
|
|
1350
|
-
enumerable: false,
|
|
1351
|
-
configurable: true
|
|
1352
|
-
});
|
|
1353
|
-
return cache;
|
|
1354
|
-
}
|
|
1355
|
-
|
|
1356
|
-
// src/analysis/duplication.ts
|
|
1357
|
-
var WORD_RE_SRC = "-?[A-Za-z][A-Za-z0-9_-]*";
|
|
1358
|
-
var WORDS_RE = new RegExp(`^${WORD_RE_SRC}(?:\\|${WORD_RE_SRC})*$`);
|
|
1359
|
-
|
|
1360
|
-
// src/combinators/probe.ts
|
|
1361
|
-
function failAt(ctx, expected, pos) {
|
|
1362
|
-
const r = { ok: false, expected, span: { start: pos, end: pos } };
|
|
1363
|
-
const probe = ctx._probe;
|
|
1364
|
-
if (probe !== void 0 && pos <= probe.offset) {
|
|
1365
|
-
const best = probe.best;
|
|
1366
|
-
if (best === null || pos > best.span.start) {
|
|
1367
|
-
probe.best = r;
|
|
1368
|
-
} else if (pos === best.span.start) {
|
|
1369
|
-
probe.best = { ...best, expected: [...best.expected, ...expected] };
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1372
|
-
return r;
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
// src/combinators/literal.ts
|
|
1376
|
-
function asciiFoldEq(a, b) {
|
|
1377
|
-
if (a.length !== b.length) return false;
|
|
1378
|
-
for (let i = 0; i < a.length; i++) {
|
|
1379
|
-
let ca = a.charCodeAt(i);
|
|
1380
|
-
let cb = b.charCodeAt(i);
|
|
1381
|
-
if (ca >= 65 && ca <= 90) ca += 32;
|
|
1382
|
-
if (cb >= 65 && cb <= 90) cb += 32;
|
|
1383
|
-
if (ca !== cb) return false;
|
|
1180
|
+
default:
|
|
1181
|
+
return [];
|
|
1384
1182
|
}
|
|
1385
|
-
return true;
|
|
1386
1183
|
}
|
|
1387
|
-
function
|
|
1388
|
-
const
|
|
1389
|
-
const firstSet = value.length > 0 ? fromChar(value.codePointAt(0)) : empty();
|
|
1184
|
+
function expect(combinator, label2) {
|
|
1185
|
+
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
1390
1186
|
const meta = {
|
|
1391
|
-
firstSet,
|
|
1392
|
-
canMatchNewline:
|
|
1187
|
+
firstSet: combinator._meta.firstSet,
|
|
1188
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1393
1189
|
isTrivia: false
|
|
1394
1190
|
};
|
|
1395
|
-
const canMatchNewline = meta.canMatchNewline;
|
|
1396
|
-
if (caseInsensitive) {
|
|
1397
|
-
const upper = value.toUpperCase();
|
|
1398
|
-
const lower = value.toLowerCase();
|
|
1399
|
-
const firstUpper = upper.codePointAt(0);
|
|
1400
|
-
const firstLower = lower.codePointAt(0);
|
|
1401
|
-
meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? firstLower === firstUpper ? { kind: "ranges", ranges: [{ lo: firstLower, hi: firstLower }] } : { kind: "ranges", ranges: [
|
|
1402
|
-
{ lo: firstLower, hi: firstLower },
|
|
1403
|
-
{ lo: firstUpper, hi: firstUpper }
|
|
1404
|
-
] } : firstSet;
|
|
1405
|
-
}
|
|
1406
|
-
const expected = [JSON.stringify(value)];
|
|
1407
|
-
const parse = !caseInsensitive && value.length === 1 ? (() => {
|
|
1408
|
-
const code = value.charCodeAt(0);
|
|
1409
|
-
return function parse2(input, pos, ctx) {
|
|
1410
|
-
if (input.charCodeAt(pos) === code) {
|
|
1411
|
-
const span = { start: pos, end: pos + 1 };
|
|
1412
|
-
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
|
|
1413
|
-
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
|
|
1414
|
-
return { ok: true, value, span };
|
|
1415
|
-
}
|
|
1416
|
-
return failAt(ctx, expected, pos);
|
|
1417
|
-
};
|
|
1418
|
-
})() : function parse2(input, pos, ctx) {
|
|
1419
|
-
const end = pos + value.length;
|
|
1420
|
-
if (end > input.length) {
|
|
1421
|
-
return failAt(ctx, expected, pos);
|
|
1422
|
-
}
|
|
1423
|
-
const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
|
|
1424
|
-
if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
|
|
1425
|
-
const span = { start: pos, end };
|
|
1426
|
-
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
|
|
1427
|
-
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
|
|
1428
|
-
return { ok: true, value: matchedValue, span };
|
|
1429
|
-
}
|
|
1430
|
-
return failAt(ctx, expected, pos);
|
|
1431
|
-
};
|
|
1432
1191
|
return {
|
|
1433
|
-
_tag: "
|
|
1192
|
+
_tag: "expect",
|
|
1434
1193
|
_meta: meta,
|
|
1435
|
-
_def: { tag: "
|
|
1436
|
-
parse
|
|
1194
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
1195
|
+
parse(input, pos, ctx) {
|
|
1196
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1197
|
+
if (result.ok) return result;
|
|
1198
|
+
const span = { start: pos, end: pos };
|
|
1199
|
+
const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
|
|
1200
|
+
ctx._errors?.push(error);
|
|
1201
|
+
if (ctx._tolerant) captureError(ctx, error);
|
|
1202
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
1203
|
+
}
|
|
1437
1204
|
};
|
|
1438
1205
|
}
|
|
1439
1206
|
|
|
@@ -1505,420 +1272,839 @@ function parseClassRanges(body) {
|
|
|
1505
1272
|
return ranges.length ? ranges : null;
|
|
1506
1273
|
}
|
|
1507
1274
|
|
|
1508
|
-
// src/combinators/
|
|
1509
|
-
var
|
|
1510
|
-
|
|
1511
|
-
var
|
|
1512
|
-
function
|
|
1513
|
-
|
|
1514
|
-
const [lo, hi] = ranges[i];
|
|
1515
|
-
if (cp >= lo && cp <= hi) return true;
|
|
1516
|
-
}
|
|
1517
|
-
return false;
|
|
1275
|
+
// src/combinators/trivia-skip.ts
|
|
1276
|
+
var NOOP_COMMIT = () => {
|
|
1277
|
+
};
|
|
1278
|
+
var fastTriviaCache = /* @__PURE__ */ new WeakMap();
|
|
1279
|
+
function needsDeferredTriviaCommit(ctx) {
|
|
1280
|
+
return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
|
|
1518
1281
|
}
|
|
1519
|
-
function
|
|
1520
|
-
|
|
1521
|
-
return
|
|
1282
|
+
function saveTriviaMark(ctx) {
|
|
1283
|
+
const m = saveCstMark(ctx);
|
|
1284
|
+
return {
|
|
1285
|
+
raw: m.raw,
|
|
1286
|
+
tlog: m.tlog,
|
|
1287
|
+
leaves: m.leaves,
|
|
1288
|
+
fields: m.fields,
|
|
1289
|
+
errors: m.errors,
|
|
1290
|
+
log: ctx._triviaLog ? ctx._triviaLog.length : 0,
|
|
1291
|
+
rootLog: ctx._rootTriviaLog ? ctx._rootTriviaLog.length : 0
|
|
1292
|
+
};
|
|
1522
1293
|
}
|
|
1523
|
-
function
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1294
|
+
function rollbackTrivia(ctx, mark) {
|
|
1295
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
|
|
1296
|
+
if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
|
|
1297
|
+
if (ctx._rootTriviaLog && ctx._rootTriviaLog.length !== mark.rootLog) ctx._rootTriviaLog.length = mark.rootLog;
|
|
1298
|
+
}
|
|
1299
|
+
function parseTriviaNoCapture(triviaP, input, cur, ctx) {
|
|
1300
|
+
const probeCtx = {
|
|
1301
|
+
trackLines: ctx.trackLines,
|
|
1302
|
+
state: ctx.state,
|
|
1303
|
+
...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
|
|
1304
|
+
...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
|
|
1305
|
+
...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
|
|
1306
|
+
};
|
|
1307
|
+
const result = triviaP.parse(input, cur, probeCtx);
|
|
1308
|
+
ctx._lineScannedTo = probeCtx._lineScannedTo;
|
|
1309
|
+
return result;
|
|
1310
|
+
}
|
|
1311
|
+
function saveLookaheadMark(ctx) {
|
|
1312
|
+
return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
|
|
1313
|
+
}
|
|
1314
|
+
function rollbackLookahead(ctx, mark) {
|
|
1315
|
+
rollbackTrivia(ctx, mark);
|
|
1316
|
+
if (ctx._probe) ctx._probe.best = mark.probeBest;
|
|
1317
|
+
}
|
|
1318
|
+
function scanWithLabels(input, cur, ctx) {
|
|
1319
|
+
const triviaP = ctx.trivia;
|
|
1320
|
+
const spec = analyzeLabeledTrivia(triviaP);
|
|
1321
|
+
if (!spec) return { end: cur, commit: NOOP_COMMIT };
|
|
1322
|
+
const log = ctx._triviaLog;
|
|
1323
|
+
const rootLog = ctx._rootTriviaLog;
|
|
1324
|
+
const rootKinds = ctx._rootTriviaKindIndex;
|
|
1325
|
+
const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
|
|
1326
|
+
const mask = ctx._triviaCaptureMask;
|
|
1327
|
+
let fullRows;
|
|
1328
|
+
let rootRows;
|
|
1329
|
+
let cstRows;
|
|
1330
|
+
const visitedEnd = visitLabeledTrivia(input, cur, spec, ctx.state, (start, matchEnd, kindIndex) => {
|
|
1331
|
+
if (log !== void 0) (fullRows ??= []).push(start, matchEnd, kindIndex);
|
|
1332
|
+
const selectedKind = rootLog === void 0 || rootKinds === void 0 || ctx._rootTriviaCapture === false ? void 0 : rootKinds[spec.labels[kindIndex] ?? ""];
|
|
1333
|
+
if (selectedKind !== void 0) (rootRows ??= []).push(start, matchEnd, selectedKind);
|
|
1334
|
+
if (captureTl && (mask === void 0 || (mask & 1 << kindIndex) !== 0)) {
|
|
1335
|
+
(cstRows ??= []).push(start, matchEnd, kindIndex);
|
|
1532
1336
|
}
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1337
|
+
});
|
|
1338
|
+
if (visitedEnd !== void 0) {
|
|
1339
|
+
if (visitedEnd === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1340
|
+
return {
|
|
1341
|
+
end: visitedEnd,
|
|
1342
|
+
commit: () => {
|
|
1343
|
+
if (fullRows !== void 0 && log !== void 0) log.push(...fullRows);
|
|
1344
|
+
if (rootRows !== void 0 && rootLog !== void 0) {
|
|
1345
|
+
for (let i = 0; i < rootRows.length; i += 3) {
|
|
1346
|
+
rootLog.push(cur, visitedEnd, rootRows[i], rootRows[i + 1], rootRows[i + 2]);
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
if (cstRows !== void 0) {
|
|
1350
|
+
for (let i = 0; i < cstRows.length; i += 3) {
|
|
1351
|
+
pushCstTriviaEntry(ctx, cstRows[i], cstRows[i + 1], cstRows[i + 2]);
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1539
1356
|
}
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
return
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
end++;
|
|
1546
|
-
if (end - pos >= SCAN_BAIL_AT) return void 0;
|
|
1547
|
-
}
|
|
1548
|
-
return minOne && end === pos ? null : end;
|
|
1357
|
+
const { end, chunks } = scanLabeledTriviaChunks(input, cur, spec, ctx.state);
|
|
1358
|
+
if (end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1359
|
+
return {
|
|
1360
|
+
end,
|
|
1361
|
+
commit: () => recordTriviaChunks(ctx, chunks)
|
|
1549
1362
|
};
|
|
1550
1363
|
}
|
|
1551
|
-
function
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
const
|
|
1555
|
-
|
|
1556
|
-
};
|
|
1557
|
-
for (const r of fs.ranges) {
|
|
1558
|
-
const uLo = Math.max(r.lo, 65), uHi = Math.min(r.hi, 90);
|
|
1559
|
-
add(uLo + 32, uHi + 32);
|
|
1560
|
-
const lLo = Math.max(r.lo, 97), lHi = Math.min(r.hi, 122);
|
|
1561
|
-
add(lLo - 32, lHi - 32);
|
|
1562
|
-
}
|
|
1563
|
-
ranges.sort((a, b) => a.lo - b.lo);
|
|
1564
|
-
const merged = [];
|
|
1565
|
-
for (const r of ranges) {
|
|
1566
|
-
const last = merged[merged.length - 1];
|
|
1567
|
-
if (last && r.lo <= last.hi + 1) last.hi = Math.max(last.hi, r.hi);
|
|
1568
|
-
else merged.push({ lo: r.lo, hi: r.hi });
|
|
1569
|
-
}
|
|
1570
|
-
return { kind: "ranges", ranges: merged };
|
|
1364
|
+
function skipWithLabels(input, cur, ctx) {
|
|
1365
|
+
const spec = analyzeLabeledTrivia(ctx.trivia);
|
|
1366
|
+
if (spec) return scanLabeledTriviaEnd(input, cur, spec, ctx.state);
|
|
1367
|
+
const tr = parseTriviaNoCapture(ctx.trivia, input, cur, ctx);
|
|
1368
|
+
return tr.ok && tr.span.end > cur ? tr.span.end : cur;
|
|
1571
1369
|
}
|
|
1572
|
-
function
|
|
1573
|
-
const
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1370
|
+
function advanceTrivia(input, cur, ctx) {
|
|
1371
|
+
const triviaP = ctx.trivia;
|
|
1372
|
+
if (!triviaP) return cur;
|
|
1373
|
+
if (!ctx.trackLines) {
|
|
1374
|
+
const fast2 = fastTriviaScanner(triviaP);
|
|
1375
|
+
if (fast2) return fast2(input, cur);
|
|
1376
|
+
if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
|
|
1377
|
+
const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1378
|
+
return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
|
|
1379
|
+
}
|
|
1380
|
+
const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
|
|
1381
|
+
const fast = fastTriviaScanner(triviaP);
|
|
1382
|
+
if (fast) {
|
|
1383
|
+
const end = fast(input, cur);
|
|
1384
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1385
|
+
return end;
|
|
1386
|
+
}
|
|
1387
|
+
if (ctx.triviaKindLabels) {
|
|
1388
|
+
const end = skipWithLabels(input, cur, ctx);
|
|
1389
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1390
|
+
return end;
|
|
1391
|
+
}
|
|
1392
|
+
const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
|
|
1393
|
+
return tr.ok && tr.span.end > cur ? tr.span.end : cur;
|
|
1394
|
+
}
|
|
1395
|
+
function scanTrivia(input, cur, ctx) {
|
|
1396
|
+
const triviaP = ctx.trivia;
|
|
1397
|
+
if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
|
|
1398
|
+
const log = ctx._triviaLog;
|
|
1399
|
+
const rootLog = ctx._rootTriviaLog;
|
|
1400
|
+
const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
|
|
1401
|
+
if (!ctx.trackLines) {
|
|
1402
|
+
const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
|
|
1403
|
+
if (fast2 && log === void 0 && !captureTl) {
|
|
1404
|
+
return { end: fast2(input, cur), commit: NOOP_COMMIT };
|
|
1405
|
+
}
|
|
1406
|
+
if (ctx.triviaKindLabels && (log !== void 0 || rootLog !== void 0 || captureTl)) {
|
|
1407
|
+
return scanWithLabels(input, cur, ctx);
|
|
1408
|
+
}
|
|
1409
|
+
if (ctx.triviaKindLabels) return { end: skipWithLabels(input, cur, ctx), commit: NOOP_COMMIT };
|
|
1410
|
+
if (log !== void 0 || rootLog !== void 0 || captureTl) {
|
|
1411
|
+
const tr3 = triviaP.parse(input, cur, {
|
|
1412
|
+
trackLines: log !== void 0 ? false : ctx.trackLines,
|
|
1413
|
+
state: ctx.state
|
|
1414
|
+
});
|
|
1415
|
+
if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1416
|
+
const end = tr3.span.end;
|
|
1417
|
+
return {
|
|
1418
|
+
end,
|
|
1419
|
+
commit: () => {
|
|
1420
|
+
pushTriviaLogEntry(ctx, cur, end);
|
|
1421
|
+
if (captureTl) pushCstTriviaEntry(ctx, cur, end);
|
|
1422
|
+
}
|
|
1423
|
+
};
|
|
1424
|
+
}
|
|
1425
|
+
const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1426
|
+
return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
|
|
1427
|
+
}
|
|
1428
|
+
const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
|
|
1429
|
+
const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
|
|
1430
|
+
if (fast && log === void 0 && !captureTl) {
|
|
1431
|
+
const end = fast(input, cur);
|
|
1432
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1433
|
+
return { end, commit: NOOP_COMMIT };
|
|
1434
|
+
}
|
|
1435
|
+
if (ctx.triviaKindLabels && (log !== void 0 || rootLog !== void 0 || captureTl)) {
|
|
1436
|
+
const scan = scanWithLabels(input, cur, ctx);
|
|
1437
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
|
|
1438
|
+
return scan;
|
|
1439
|
+
}
|
|
1440
|
+
if (ctx.triviaKindLabels) {
|
|
1441
|
+
const end = skipWithLabels(input, cur, ctx);
|
|
1442
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1443
|
+
return { end, commit: NOOP_COMMIT };
|
|
1444
|
+
}
|
|
1445
|
+
if (log !== void 0 || rootLog !== void 0 || captureTl) {
|
|
1446
|
+
const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
|
|
1447
|
+
if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1448
|
+
const end = tr2.span.end;
|
|
1449
|
+
return {
|
|
1450
|
+
end,
|
|
1451
|
+
commit: () => {
|
|
1452
|
+
pushTriviaLogEntry(ctx, cur, end);
|
|
1453
|
+
if (captureTl) pushCstTriviaEntry(ctx, cur, end);
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1457
|
+
const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
|
|
1458
|
+
return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
|
|
1459
|
+
}
|
|
1460
|
+
function consumeTrivia(input, cur, ctx) {
|
|
1461
|
+
if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
|
|
1462
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1463
|
+
scan.commit();
|
|
1464
|
+
return scan.end;
|
|
1465
|
+
}
|
|
1466
|
+
function fastTriviaScanner(trivia2) {
|
|
1467
|
+
const cached = fastTriviaCache.get(trivia2);
|
|
1468
|
+
if (cached !== void 0) return cached;
|
|
1469
|
+
const scanner = buildFastTriviaScanner(trivia2);
|
|
1470
|
+
fastTriviaCache.set(trivia2, scanner);
|
|
1471
|
+
return scanner;
|
|
1472
|
+
}
|
|
1473
|
+
function buildFastTriviaScanner(trivia2) {
|
|
1474
|
+
const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
|
|
1475
|
+
const direct = regexTriviaScanner(core);
|
|
1476
|
+
if (direct) return direct;
|
|
1477
|
+
const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
|
|
1478
|
+
if (!repeat) return null;
|
|
1479
|
+
const one = regexTriviaScanner(repeat);
|
|
1480
|
+
if (one) return loopScanner([one]);
|
|
1481
|
+
if (repeat._def.tag !== "choice") return null;
|
|
1482
|
+
const arms = repeat._def.parsers.map(regexTriviaScanner);
|
|
1483
|
+
if (arms.some((s) => s === null)) return null;
|
|
1484
|
+
return loopScanner(arms);
|
|
1485
|
+
}
|
|
1486
|
+
function loopScanner(arms) {
|
|
1487
|
+
return (input, cur) => {
|
|
1488
|
+
let pos = cur;
|
|
1489
|
+
scan: while (pos < input.length) {
|
|
1490
|
+
for (const arm of arms) {
|
|
1491
|
+
const end = arm(input, pos);
|
|
1492
|
+
if (end > pos) {
|
|
1493
|
+
pos = end;
|
|
1494
|
+
continue scan;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
break;
|
|
1498
|
+
}
|
|
1499
|
+
return pos;
|
|
1500
|
+
};
|
|
1501
|
+
}
|
|
1502
|
+
function regexTriviaScanner(parser2) {
|
|
1503
|
+
if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
|
|
1504
|
+
const source = parser2._def.source;
|
|
1505
|
+
return classRunSource(source) ?? altStarSource(source);
|
|
1506
|
+
}
|
|
1507
|
+
function inRanges(cp, ranges) {
|
|
1508
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
1509
|
+
const r = ranges[i];
|
|
1510
|
+
if (cp >= r[0] && cp <= r[1]) return true;
|
|
1511
|
+
}
|
|
1512
|
+
return false;
|
|
1513
|
+
}
|
|
1514
|
+
function classScanner(classBody) {
|
|
1515
|
+
const ranges = parseClassRanges(classBody);
|
|
1516
|
+
if (!ranges) return null;
|
|
1517
|
+
return (input, cur) => {
|
|
1518
|
+
let pos = cur;
|
|
1519
|
+
while (pos < input.length && inRanges(input.charCodeAt(pos), ranges)) pos++;
|
|
1520
|
+
return pos;
|
|
1521
|
+
};
|
|
1522
|
+
}
|
|
1523
|
+
function untilLineBreakScanner(leaderCode) {
|
|
1524
|
+
return (input, cur) => {
|
|
1525
|
+
if (input.charCodeAt(cur) !== leaderCode) return cur;
|
|
1526
|
+
let pos = cur + 1;
|
|
1527
|
+
while (pos < input.length) {
|
|
1528
|
+
const cc = input.charCodeAt(pos);
|
|
1529
|
+
if (cc === 10 || cc === 13) break;
|
|
1530
|
+
pos++;
|
|
1531
|
+
}
|
|
1532
|
+
return pos;
|
|
1533
|
+
};
|
|
1534
|
+
}
|
|
1535
|
+
function classRunSource(source) {
|
|
1536
|
+
const m = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]$/.exec(source);
|
|
1537
|
+
return m ? classScanner(m[1]) : null;
|
|
1538
|
+
}
|
|
1539
|
+
function classifyTriviaArm(arm) {
|
|
1540
|
+
const cls = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]?$/.exec(arm);
|
|
1541
|
+
if (cls) {
|
|
1542
|
+
const ranges = parseClassRanges(cls[1]);
|
|
1543
|
+
return ranges ? { kind: "class", ranges } : null;
|
|
1544
|
+
}
|
|
1545
|
+
const lc = /^(\\?.)\[\^\\n\\r\]\*$/.exec(arm);
|
|
1546
|
+
if (lc) {
|
|
1547
|
+
const marker = lc[1];
|
|
1548
|
+
return { kind: "untilLineBreak", code: (marker.length === 2 ? marker[1] : marker[0]).charCodeAt(0) };
|
|
1549
|
+
}
|
|
1550
|
+
return null;
|
|
1551
|
+
}
|
|
1552
|
+
function armScanner(arm) {
|
|
1553
|
+
if (arm.kind === "untilLineBreak") return untilLineBreakScanner(arm.code);
|
|
1554
|
+
const ranges = arm.ranges;
|
|
1555
|
+
return (input, cur) => {
|
|
1556
|
+
let pos = cur;
|
|
1557
|
+
while (pos < input.length && inRanges(input.charCodeAt(pos), ranges)) pos++;
|
|
1558
|
+
return pos;
|
|
1559
|
+
};
|
|
1560
|
+
}
|
|
1561
|
+
function fusedTriviaScanner(ranges, leaders) {
|
|
1562
|
+
const c0 = leaders[0];
|
|
1563
|
+
const single = leaders.length === 1;
|
|
1564
|
+
return (input, cur) => {
|
|
1565
|
+
let pos = cur;
|
|
1566
|
+
const len = input.length;
|
|
1567
|
+
for (; ; ) {
|
|
1568
|
+
const c = input.charCodeAt(pos);
|
|
1569
|
+
if (pos < len && inRanges(c, ranges)) {
|
|
1570
|
+
pos++;
|
|
1571
|
+
continue;
|
|
1572
|
+
}
|
|
1573
|
+
if (single ? c === c0 : leaders.includes(c)) {
|
|
1574
|
+
pos++;
|
|
1575
|
+
while (pos < len) {
|
|
1576
|
+
const cc = input.charCodeAt(pos);
|
|
1577
|
+
if (cc === 10 || cc === 13) break;
|
|
1578
|
+
pos++;
|
|
1579
|
+
}
|
|
1580
|
+
continue;
|
|
1581
|
+
}
|
|
1582
|
+
break;
|
|
1583
|
+
}
|
|
1584
|
+
return pos;
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
function splitTopLevelAlts(body) {
|
|
1588
|
+
const arms = [];
|
|
1589
|
+
let inClass = false;
|
|
1590
|
+
let start = 0;
|
|
1591
|
+
for (let i = 0; i < body.length; i++) {
|
|
1592
|
+
const c = body[i];
|
|
1593
|
+
if (c === "\\") {
|
|
1594
|
+
i++;
|
|
1595
|
+
continue;
|
|
1596
|
+
}
|
|
1597
|
+
if (inClass) {
|
|
1598
|
+
if (c === "]") inClass = false;
|
|
1599
|
+
continue;
|
|
1600
|
+
}
|
|
1601
|
+
if (c === "[") inClass = true;
|
|
1602
|
+
else if (c === "(") return null;
|
|
1603
|
+
else if (c === "|") {
|
|
1604
|
+
arms.push(body.slice(start, i));
|
|
1605
|
+
start = i + 1;
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
arms.push(body.slice(start));
|
|
1609
|
+
return arms;
|
|
1610
|
+
}
|
|
1611
|
+
function altStarSource(source) {
|
|
1612
|
+
const m = /^\(\?:(.*)\)[*+]$/.exec(source);
|
|
1613
|
+
if (!m) return null;
|
|
1614
|
+
const armSrcs = splitTopLevelAlts(m[1]);
|
|
1615
|
+
if (!armSrcs || armSrcs.length < 2) return null;
|
|
1616
|
+
const arms = [];
|
|
1617
|
+
for (const src of armSrcs) {
|
|
1618
|
+
const arm = classifyTriviaArm(src);
|
|
1619
|
+
if (!arm) return null;
|
|
1620
|
+
arms.push(arm);
|
|
1621
|
+
}
|
|
1622
|
+
const ranges = [];
|
|
1623
|
+
const leaders = [];
|
|
1624
|
+
for (const arm of arms) {
|
|
1625
|
+
if (arm.kind === "class") ranges.push(...arm.ranges);
|
|
1626
|
+
else leaders.push(arm.code);
|
|
1627
|
+
}
|
|
1628
|
+
if (leaders.some((code) => inRanges(code, ranges))) {
|
|
1629
|
+
return loopScanner(arms.map(armScanner));
|
|
1630
|
+
}
|
|
1631
|
+
if (leaders.length === 0) return armScanner({ kind: "class", ranges });
|
|
1632
|
+
return fusedTriviaScanner(ranges, leaders);
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
// src/combinators/choice.ts
|
|
1636
|
+
function choice(...args) {
|
|
1637
|
+
const parsers = args.map((a) => "gate" in a ? a.combinator : a);
|
|
1638
|
+
const gates = args.map((a) => "gate" in a ? a.gate : null);
|
|
1639
|
+
const hasGates = gates.some((g) => g !== null);
|
|
1640
|
+
const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
|
|
1641
|
+
let combined = { kind: "empty" };
|
|
1642
|
+
for (const p of parsers) combined = union(combined, p._meta.firstSet);
|
|
1643
|
+
const meta = {
|
|
1644
|
+
firstSet: combined,
|
|
1645
|
+
canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
|
|
1646
|
+
isTrivia: false,
|
|
1647
|
+
disjoint
|
|
1648
|
+
};
|
|
1649
|
+
const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
|
|
1650
|
+
const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
|
|
1651
|
+
let greedyLitMap = null;
|
|
1652
|
+
let sortedParsers = null;
|
|
1653
|
+
const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
|
|
1654
|
+
if (strategy?.tag === "greedyClassify") {
|
|
1655
|
+
greedyLitMap = /* @__PURE__ */ new Map();
|
|
1656
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1657
|
+
if (i === strategy.superIndex) continue;
|
|
1658
|
+
const litVal = getCoreLiteralValue(parsers[i]);
|
|
1659
|
+
if (litVal !== null) greedyLitMap.set(litVal, i);
|
|
1660
|
+
}
|
|
1661
|
+
} else if (strategy?.tag === "literalsLongestFirst") {
|
|
1662
|
+
sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
|
|
1663
|
+
}
|
|
1581
1664
|
return {
|
|
1582
|
-
_tag: "
|
|
1665
|
+
_tag: "choice",
|
|
1583
1666
|
_meta: meta,
|
|
1584
|
-
_def: {
|
|
1667
|
+
_def: {
|
|
1668
|
+
tag: "choice",
|
|
1669
|
+
parsers,
|
|
1670
|
+
gates,
|
|
1671
|
+
disjoint,
|
|
1672
|
+
strategy: strategy ?? { tag: "firstMatch" },
|
|
1673
|
+
autoNot
|
|
1674
|
+
},
|
|
1585
1675
|
parse(input, pos, ctx) {
|
|
1586
|
-
const
|
|
1587
|
-
if (
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1676
|
+
const expected = [];
|
|
1677
|
+
if (disjoint && pos < input.length) {
|
|
1678
|
+
const code = input.codePointAt(pos);
|
|
1679
|
+
let idx = code < 128 ? asciiDispatch[code] : -1;
|
|
1680
|
+
if (idx < 0) {
|
|
1681
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1682
|
+
if (inFirstSet(code, parsers[i]._meta.firstSet)) {
|
|
1683
|
+
idx = i;
|
|
1684
|
+
break;
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
if (idx >= 0) {
|
|
1689
|
+
const gate = gates[idx];
|
|
1690
|
+
if (gate && !gate(ctx.state)) {
|
|
1691
|
+
return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
|
|
1692
|
+
}
|
|
1693
|
+
const result = parsers[idx].parse(input, pos, ctx);
|
|
1694
|
+
if (result.ok) return result;
|
|
1695
|
+
expected.push(...result.expected);
|
|
1696
|
+
if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
|
|
1697
|
+
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1698
|
+
}
|
|
1699
|
+
return {
|
|
1700
|
+
ok: false,
|
|
1701
|
+
expected: parsers.flatMap((p) => {
|
|
1702
|
+
const r = p.parse(input, pos, ctx);
|
|
1703
|
+
return r.ok ? [] : r.expected;
|
|
1704
|
+
}),
|
|
1705
|
+
span: { start: pos, end: pos }
|
|
1706
|
+
};
|
|
1707
|
+
}
|
|
1708
|
+
if (strategy?.tag === "greedyClassify") {
|
|
1709
|
+
const superResult = parsers[strategy.superIndex].parse(input, pos, ctx);
|
|
1710
|
+
if (!superResult.ok) return superResult;
|
|
1711
|
+
const end = superResult.span.end;
|
|
1712
|
+
const litIdx = greedyLitMap.get(input.slice(pos, end));
|
|
1713
|
+
if (litIdx !== void 0) {
|
|
1714
|
+
const litVal = getCoreLiteralValue(parsers[litIdx]);
|
|
1715
|
+
const value = applyTransforms(parsers[litIdx], litVal, { start: pos, end });
|
|
1716
|
+
return { ok: true, value, span: { start: pos, end } };
|
|
1717
|
+
}
|
|
1718
|
+
return superResult;
|
|
1719
|
+
}
|
|
1720
|
+
if (strategy?.tag === "literalsLongestFirst") {
|
|
1721
|
+
for (const p of sortedParsers) {
|
|
1722
|
+
const r = p.parse(input, pos, ctx);
|
|
1723
|
+
if (r.ok) return r;
|
|
1724
|
+
expected.push(...r.expected);
|
|
1725
|
+
}
|
|
1726
|
+
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1727
|
+
}
|
|
1728
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1729
|
+
if (gates[i] && !gates[i](ctx.state)) continue;
|
|
1730
|
+
const mark = saveTriviaMark(ctx);
|
|
1731
|
+
const result = parsers[i].parse(input, pos, ctx);
|
|
1732
|
+
if (!result.ok) {
|
|
1733
|
+
rollbackTrivia(ctx, mark);
|
|
1734
|
+
expected.push(...result.expected);
|
|
1735
|
+
if (result.committed) return { ok: false, expected, span: result.span, committed: true };
|
|
1736
|
+
continue;
|
|
1737
|
+
}
|
|
1738
|
+
const checks = autoNot[i];
|
|
1739
|
+
if (checks && autoNotFires(input, result.span.end, checks)) {
|
|
1740
|
+
rollbackTrivia(ctx, mark);
|
|
1741
|
+
continue;
|
|
1742
|
+
}
|
|
1743
|
+
return result;
|
|
1744
|
+
}
|
|
1745
|
+
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1746
|
+
}
|
|
1747
|
+
};
|
|
1748
|
+
}
|
|
1749
|
+
function detectStrategy(parsers) {
|
|
1750
|
+
const regexIndices = [];
|
|
1751
|
+
const literalIndices = [];
|
|
1752
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1753
|
+
if (getCoreRegexDef(parsers[i]) !== null) regexIndices.push(i);
|
|
1754
|
+
else if (getCoreLiteralValue(parsers[i]) !== null) literalIndices.push(i);
|
|
1755
|
+
}
|
|
1756
|
+
if (regexIndices.length === 1 && literalIndices.length === parsers.length - 1 && literalIndices.length > 0) {
|
|
1757
|
+
const superIndex = regexIndices[0];
|
|
1758
|
+
const regexDef = getCoreRegexDef(parsers[superIndex]);
|
|
1759
|
+
const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
|
|
1760
|
+
const re = new RegExp(regexDef.source, flags);
|
|
1761
|
+
const allSubsumed = literalIndices.every((i) => {
|
|
1762
|
+
const litVal = getCoreLiteralValue(parsers[i]);
|
|
1763
|
+
re.lastIndex = 0;
|
|
1764
|
+
const m = re.exec(litVal);
|
|
1765
|
+
return m !== null && m[0] === litVal;
|
|
1766
|
+
});
|
|
1767
|
+
if (allSubsumed) return { tag: "greedyClassify", superIndex };
|
|
1768
|
+
}
|
|
1769
|
+
if (parsers.length === literalIndices.length) {
|
|
1770
|
+
const sortedIndices = [...literalIndices].sort(
|
|
1771
|
+
(a, b) => getCoreLiteralValue(parsers[b]).length - getCoreLiteralValue(parsers[a]).length
|
|
1772
|
+
);
|
|
1773
|
+
return { tag: "literalsLongestFirst", sortedIndices };
|
|
1774
|
+
}
|
|
1775
|
+
const shared = detectSharedPrefix(parsers);
|
|
1776
|
+
if (shared !== null) return shared;
|
|
1777
|
+
return { tag: "firstMatch" };
|
|
1778
|
+
}
|
|
1779
|
+
function bareLeadingTermKey(term) {
|
|
1780
|
+
const d = term._def;
|
|
1781
|
+
if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
|
|
1782
|
+
if (d.tag === "regex") return `R:${d.source}\0${d.flags}`;
|
|
1783
|
+
return null;
|
|
1784
|
+
}
|
|
1785
|
+
function detectSharedPrefix(parsers) {
|
|
1786
|
+
if (parsers.length < 2) return null;
|
|
1787
|
+
let key = null;
|
|
1788
|
+
let prefix = null;
|
|
1789
|
+
const members = [];
|
|
1790
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1791
|
+
const term0 = leadingTermOfArm(parsers[i]);
|
|
1792
|
+
if (term0 === null) return null;
|
|
1793
|
+
const k = bareLeadingTermKey(term0);
|
|
1794
|
+
if (k === null) return null;
|
|
1795
|
+
if (key === null) {
|
|
1796
|
+
key = k;
|
|
1797
|
+
prefix = term0;
|
|
1798
|
+
} else if (k !== key) return null;
|
|
1799
|
+
members.push(i);
|
|
1800
|
+
}
|
|
1801
|
+
if (prefix === null || members.length < 2) return null;
|
|
1802
|
+
return { tag: "sharedPrefix", prefix, members };
|
|
1803
|
+
}
|
|
1804
|
+
function leadingTermOfArm(arm) {
|
|
1805
|
+
let d = arm._def;
|
|
1806
|
+
for (; ; ) {
|
|
1807
|
+
if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
|
|
1808
|
+
d = d.parser._def;
|
|
1809
|
+
continue;
|
|
1810
|
+
}
|
|
1811
|
+
break;
|
|
1812
|
+
}
|
|
1813
|
+
if (d.tag !== "sequence" || d.parsers.length < 2) return null;
|
|
1814
|
+
return d.parsers[0];
|
|
1815
|
+
}
|
|
1816
|
+
function computeAutoNot(parsers) {
|
|
1817
|
+
return parsers.map((p, i) => {
|
|
1818
|
+
const litVal = getCoreLiteralValue(p);
|
|
1819
|
+
if (litVal === null) return null;
|
|
1820
|
+
const checks = [];
|
|
1821
|
+
for (let j2 = i + 1; j2 < parsers.length; j2++) {
|
|
1822
|
+
const other = parsers[j2];
|
|
1823
|
+
const otherLit = getCoreLiteralValue(other);
|
|
1824
|
+
if (otherLit !== null && otherLit.startsWith(litVal) && otherLit.length > litVal.length) {
|
|
1825
|
+
checks.push({ kind: "startsWith", value: otherLit.slice(litVal.length) });
|
|
1826
|
+
continue;
|
|
1594
1827
|
}
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1828
|
+
const regexDef = getCoreRegexDef(other);
|
|
1829
|
+
if (regexDef !== null) {
|
|
1830
|
+
const contSet = continuationFirstSet(litVal, regexDef.source, regexDef.flags);
|
|
1831
|
+
if (contSet !== null) checks.push({ kind: "firstSet", set: contSet });
|
|
1599
1832
|
}
|
|
1600
|
-
const span = { start: pos, end: pos + m[0].length };
|
|
1601
|
-
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
|
|
1602
|
-
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: m[0], span });
|
|
1603
|
-
return { ok: true, value: m[0], span };
|
|
1604
1833
|
}
|
|
1605
|
-
|
|
1834
|
+
return checks.length > 0 ? checks : null;
|
|
1835
|
+
});
|
|
1606
1836
|
}
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1837
|
+
function autoNotFires(input, end, checks) {
|
|
1838
|
+
for (const check of checks) {
|
|
1839
|
+
if (check.kind === "firstSet") {
|
|
1840
|
+
const code = end < input.length ? input.codePointAt(end) ?? -1 : -1;
|
|
1841
|
+
if (inFirstSet(code, check.set)) return true;
|
|
1842
|
+
} else {
|
|
1843
|
+
if (input.startsWith(check.value, end)) return true;
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
return false;
|
|
1614
1847
|
}
|
|
1615
|
-
function
|
|
1616
|
-
const
|
|
1617
|
-
|
|
1848
|
+
function getCoreLiteralValue(p) {
|
|
1849
|
+
const def = p._def;
|
|
1850
|
+
if (def.tag === "literal" && !def.caseInsensitive) return def.value;
|
|
1851
|
+
if (def.tag === "transform") return getCoreLiteralValue(def.parser);
|
|
1852
|
+
return null;
|
|
1618
1853
|
}
|
|
1619
|
-
function
|
|
1620
|
-
|
|
1621
|
-
if (
|
|
1854
|
+
function getCoreRegexDef(p) {
|
|
1855
|
+
const def = p._def;
|
|
1856
|
+
if (def.tag === "regex") return { source: def.source, flags: def.flags };
|
|
1857
|
+
if (def.tag === "transform") return getCoreRegexDef(def.parser);
|
|
1858
|
+
if (def.tag === "label") return getCoreRegexDef(def.parser);
|
|
1859
|
+
return null;
|
|
1622
1860
|
}
|
|
1623
|
-
function
|
|
1624
|
-
const
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
};
|
|
1631
|
-
const result = triviaP.parse(input, cur, probeCtx);
|
|
1632
|
-
ctx._lineScannedTo = probeCtx._lineScannedTo;
|
|
1633
|
-
return result;
|
|
1861
|
+
function applyTransforms(p, value, span) {
|
|
1862
|
+
const def = p._def;
|
|
1863
|
+
if (def.tag === "transform") {
|
|
1864
|
+
const inner = applyTransforms(def.parser, value, span);
|
|
1865
|
+
return def.fn(inner, span);
|
|
1866
|
+
}
|
|
1867
|
+
return value;
|
|
1634
1868
|
}
|
|
1635
|
-
function
|
|
1636
|
-
|
|
1869
|
+
function continuationFirstSet(lit, source, flags) {
|
|
1870
|
+
const re = new RegExp(source, "y" + flags.replace(/[gy]/g, ""));
|
|
1871
|
+
re.lastIndex = 0;
|
|
1872
|
+
const base = re.exec(lit);
|
|
1873
|
+
if (!base || base[0] !== lit) return null;
|
|
1874
|
+
const contCodes = [];
|
|
1875
|
+
for (let code = 1; code < 128; code++) {
|
|
1876
|
+
re.lastIndex = 0;
|
|
1877
|
+
const m = re.exec(lit + String.fromCharCode(code));
|
|
1878
|
+
if (m && m[0].length > lit.length) contCodes.push(code);
|
|
1879
|
+
}
|
|
1880
|
+
if (contCodes.length === 0) return null;
|
|
1881
|
+
return codesToFirstSet(contCodes);
|
|
1637
1882
|
}
|
|
1638
|
-
function
|
|
1639
|
-
|
|
1640
|
-
|
|
1883
|
+
function codesToFirstSet(codes) {
|
|
1884
|
+
codes.sort((a, b) => a - b);
|
|
1885
|
+
const ranges = [];
|
|
1886
|
+
let lo = codes[0], hi = codes[0];
|
|
1887
|
+
for (let i = 1; i < codes.length; i++) {
|
|
1888
|
+
if (codes[i] === hi + 1) {
|
|
1889
|
+
hi = codes[i];
|
|
1890
|
+
} else {
|
|
1891
|
+
ranges.push({ lo, hi });
|
|
1892
|
+
lo = hi = codes[i];
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
ranges.push({ lo, hi });
|
|
1896
|
+
return { kind: "ranges", ranges };
|
|
1641
1897
|
}
|
|
1642
|
-
function
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
const { end, chunks } = fast ?? scanLabeledTriviaChunks(input, cur, spec);
|
|
1648
|
-
if (end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1649
|
-
return {
|
|
1650
|
-
end,
|
|
1651
|
-
commit: () => recordTriviaChunks(ctx, chunks)
|
|
1652
|
-
};
|
|
1898
|
+
function inFirstSet(code, fs) {
|
|
1899
|
+
if (fs.kind === "any") return true;
|
|
1900
|
+
if (fs.kind === "empty") return false;
|
|
1901
|
+
for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
1902
|
+
return false;
|
|
1653
1903
|
}
|
|
1654
|
-
function
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1904
|
+
function areDisjoint(sets) {
|
|
1905
|
+
if (sets.some((s) => s.kind === "any")) return false;
|
|
1906
|
+
for (let i = 0; i < sets.length; i++)
|
|
1907
|
+
for (let j2 = i + 1; j2 < sets.length; j2++)
|
|
1908
|
+
if (intersects(sets[i], sets[j2])) return false;
|
|
1909
|
+
return true;
|
|
1910
|
+
}
|
|
1911
|
+
function buildAsciiDispatch(parsers) {
|
|
1912
|
+
const table = Array(128).fill(-1);
|
|
1913
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1914
|
+
const fs = parsers[i]._meta.firstSet;
|
|
1915
|
+
if (fs.kind !== "ranges") continue;
|
|
1916
|
+
for (const { lo, hi } of fs.ranges) {
|
|
1917
|
+
for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
|
|
1918
|
+
table[code] = i;
|
|
1919
|
+
}
|
|
1663
1920
|
}
|
|
1664
|
-
const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1665
|
-
return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
|
|
1666
|
-
}
|
|
1667
|
-
const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
|
|
1668
|
-
const fast = fastTriviaScanner(triviaP);
|
|
1669
|
-
if (fast) {
|
|
1670
|
-
const end = fast(input, cur);
|
|
1671
|
-
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1672
|
-
return end;
|
|
1673
|
-
}
|
|
1674
|
-
if (ctx.triviaKindLabels) {
|
|
1675
|
-
const scan = scanWithLabels(input, cur, ctx);
|
|
1676
|
-
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
|
|
1677
|
-
return scan.end;
|
|
1678
1921
|
}
|
|
1679
|
-
|
|
1680
|
-
return tr.ok && tr.span.end > cur ? tr.span.end : cur;
|
|
1922
|
+
return table;
|
|
1681
1923
|
}
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
if (
|
|
1696
|
-
|
|
1697
|
-
trackLines: log !== void 0 ? false : ctx.trackLines,
|
|
1698
|
-
state: ctx.state
|
|
1699
|
-
});
|
|
1700
|
-
if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1701
|
-
const end = tr3.span.end;
|
|
1702
|
-
return {
|
|
1703
|
-
end,
|
|
1704
|
-
commit: () => {
|
|
1705
|
-
pushTriviaLogEntry(ctx, cur, end);
|
|
1706
|
-
if (captureTl) pushCstTriviaEntry(ctx, cur, end);
|
|
1707
|
-
}
|
|
1708
|
-
};
|
|
1924
|
+
|
|
1925
|
+
// src/analysis/duplication.ts
|
|
1926
|
+
var WORD_RE_SRC = "-?[A-Za-z][A-Za-z0-9_-]*";
|
|
1927
|
+
var WORDS_RE = new RegExp(`^${WORD_RE_SRC}(?:\\|${WORD_RE_SRC})*$`);
|
|
1928
|
+
|
|
1929
|
+
// src/combinators/probe.ts
|
|
1930
|
+
function failAt(ctx, expected, pos) {
|
|
1931
|
+
const r = { ok: false, expected, span: { start: pos, end: pos } };
|
|
1932
|
+
const probe = ctx._probe;
|
|
1933
|
+
if (probe !== void 0 && pos <= probe.offset) {
|
|
1934
|
+
const best = probe.best;
|
|
1935
|
+
if (best === null || pos > best.span.start) {
|
|
1936
|
+
probe.best = r;
|
|
1937
|
+
} else if (pos === best.span.start) {
|
|
1938
|
+
probe.best = { ...best, expected: [...best.expected, ...expected] };
|
|
1709
1939
|
}
|
|
1710
|
-
const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1711
|
-
return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
|
|
1712
|
-
}
|
|
1713
|
-
const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
|
|
1714
|
-
const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
|
|
1715
|
-
if (fast && log === void 0 && !captureTl) {
|
|
1716
|
-
const end = fast(input, cur);
|
|
1717
|
-
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1718
|
-
return { end, commit: NOOP_COMMIT };
|
|
1719
|
-
}
|
|
1720
|
-
if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
|
|
1721
|
-
const scan = scanWithLabels(input, cur, ctx);
|
|
1722
|
-
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
|
|
1723
|
-
return scan;
|
|
1724
|
-
}
|
|
1725
|
-
if (log !== void 0 || captureTl) {
|
|
1726
|
-
const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
|
|
1727
|
-
if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1728
|
-
const end = tr2.span.end;
|
|
1729
|
-
return {
|
|
1730
|
-
end,
|
|
1731
|
-
commit: () => {
|
|
1732
|
-
pushTriviaLogEntry(ctx, cur, end);
|
|
1733
|
-
if (captureTl) pushCstTriviaEntry(ctx, cur, end);
|
|
1734
|
-
}
|
|
1735
|
-
};
|
|
1736
1940
|
}
|
|
1737
|
-
|
|
1738
|
-
return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
|
|
1739
|
-
}
|
|
1740
|
-
function consumeTrivia(input, cur, ctx) {
|
|
1741
|
-
if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
|
|
1742
|
-
const scan = scanTrivia(input, cur, ctx);
|
|
1743
|
-
scan.commit();
|
|
1744
|
-
return scan.end;
|
|
1745
|
-
}
|
|
1746
|
-
function fastTriviaScanner(trivia2) {
|
|
1747
|
-
const cached = fastTriviaCache.get(trivia2);
|
|
1748
|
-
if (cached !== void 0) return cached;
|
|
1749
|
-
const scanner = buildFastTriviaScanner(trivia2);
|
|
1750
|
-
fastTriviaCache.set(trivia2, scanner);
|
|
1751
|
-
return scanner;
|
|
1941
|
+
return r;
|
|
1752
1942
|
}
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
if (
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
return
|
|
1943
|
+
|
|
1944
|
+
// src/combinators/literal.ts
|
|
1945
|
+
function asciiFoldEq(a, b) {
|
|
1946
|
+
if (a.length !== b.length) return false;
|
|
1947
|
+
for (let i = 0; i < a.length; i++) {
|
|
1948
|
+
let ca = a.charCodeAt(i);
|
|
1949
|
+
let cb = b.charCodeAt(i);
|
|
1950
|
+
if (ca >= 65 && ca <= 90) ca += 32;
|
|
1951
|
+
if (cb >= 65 && cb <= 90) cb += 32;
|
|
1952
|
+
if (ca !== cb) return false;
|
|
1953
|
+
}
|
|
1954
|
+
return true;
|
|
1765
1955
|
}
|
|
1766
|
-
function
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1956
|
+
function literal(value, opts = {}) {
|
|
1957
|
+
const caseInsensitive = opts.caseInsensitive ?? false;
|
|
1958
|
+
const firstSet = value.length > 0 ? fromChar(value.codePointAt(0)) : empty();
|
|
1959
|
+
const meta = {
|
|
1960
|
+
firstSet,
|
|
1961
|
+
canMatchNewline: value.includes("\n"),
|
|
1962
|
+
isTrivia: false
|
|
1963
|
+
};
|
|
1964
|
+
const canMatchNewline = meta.canMatchNewline;
|
|
1965
|
+
if (caseInsensitive) {
|
|
1966
|
+
const upper = value.toUpperCase();
|
|
1967
|
+
const lower = value.toLowerCase();
|
|
1968
|
+
const firstUpper = upper.codePointAt(0);
|
|
1969
|
+
const firstLower = lower.codePointAt(0);
|
|
1970
|
+
meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? firstLower === firstUpper ? { kind: "ranges", ranges: [{ lo: firstLower, hi: firstLower }] } : { kind: "ranges", ranges: [
|
|
1971
|
+
{ lo: firstLower, hi: firstLower },
|
|
1972
|
+
{ lo: firstUpper, hi: firstUpper }
|
|
1973
|
+
] } : firstSet;
|
|
1974
|
+
}
|
|
1975
|
+
const expected = [JSON.stringify(value)];
|
|
1976
|
+
const parse = !caseInsensitive && value.length === 1 ? (() => {
|
|
1977
|
+
const code = value.charCodeAt(0);
|
|
1978
|
+
return function parse2(input, pos, ctx) {
|
|
1979
|
+
if (input.charCodeAt(pos) === code) {
|
|
1980
|
+
const span = { start: pos, end: pos + 1 };
|
|
1981
|
+
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
|
|
1982
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
|
|
1983
|
+
return { ok: true, value, span };
|
|
1776
1984
|
}
|
|
1777
|
-
|
|
1985
|
+
return failAt(ctx, expected, pos);
|
|
1986
|
+
};
|
|
1987
|
+
})() : function parse2(input, pos, ctx) {
|
|
1988
|
+
const end = pos + value.length;
|
|
1989
|
+
if (end > input.length) {
|
|
1990
|
+
return failAt(ctx, expected, pos);
|
|
1778
1991
|
}
|
|
1779
|
-
|
|
1992
|
+
const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
|
|
1993
|
+
if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
|
|
1994
|
+
const span = { start: pos, end };
|
|
1995
|
+
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
|
|
1996
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
|
|
1997
|
+
return { ok: true, value: matchedValue, span };
|
|
1998
|
+
}
|
|
1999
|
+
return failAt(ctx, expected, pos);
|
|
2000
|
+
};
|
|
2001
|
+
return {
|
|
2002
|
+
_tag: "literal",
|
|
2003
|
+
_meta: meta,
|
|
2004
|
+
_def: { tag: "literal", value, caseInsensitive },
|
|
2005
|
+
parse
|
|
1780
2006
|
};
|
|
1781
2007
|
}
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
2008
|
+
|
|
2009
|
+
// src/combinators/regex.ts
|
|
2010
|
+
var firstSetAnalyzer = null;
|
|
2011
|
+
var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
|
|
2012
|
+
var SCAN_BAIL_AT = 64;
|
|
1787
2013
|
function inRanges2(cp, ranges) {
|
|
1788
2014
|
for (let i = 0; i < ranges.length; i++) {
|
|
1789
|
-
const
|
|
1790
|
-
if (cp >=
|
|
2015
|
+
const [lo, hi] = ranges[i];
|
|
2016
|
+
if (cp >= lo && cp <= hi) return true;
|
|
1791
2017
|
}
|
|
1792
2018
|
return false;
|
|
1793
2019
|
}
|
|
1794
|
-
function
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
return (input, cur) => {
|
|
1798
|
-
let pos = cur;
|
|
1799
|
-
while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
|
|
1800
|
-
return pos;
|
|
1801
|
-
};
|
|
2020
|
+
function readClassRanges(body) {
|
|
2021
|
+
if (body.startsWith("^")) return null;
|
|
2022
|
+
return parseClassRanges(body);
|
|
1802
2023
|
}
|
|
1803
|
-
function
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
2024
|
+
function shortScanner(source, flags) {
|
|
2025
|
+
if (/[imsuvy]/.test(flags)) return null;
|
|
2026
|
+
let ranges = null;
|
|
2027
|
+
let quant = "";
|
|
2028
|
+
if (source[0] === "[") {
|
|
2029
|
+
let end = 1;
|
|
2030
|
+
while (end < source.length && source[end] !== "]") {
|
|
2031
|
+
if (source[end] === "\\") end += 2;
|
|
2032
|
+
else end++;
|
|
1811
2033
|
}
|
|
1812
|
-
return
|
|
2034
|
+
if (source[end] !== "]") return null;
|
|
2035
|
+
ranges = readClassRanges(source.slice(1, end));
|
|
2036
|
+
quant = source.slice(end + 1);
|
|
2037
|
+
} else if (source[0] === "\\" && (source[1] === "d" || source[1] === "w" || source[1] === "s")) {
|
|
2038
|
+
ranges = shorthandRanges(source[1]);
|
|
2039
|
+
quant = source.slice(2);
|
|
2040
|
+
}
|
|
2041
|
+
if (!ranges || quant !== "+" && quant !== "*") return null;
|
|
2042
|
+
const minOne = quant === "+";
|
|
2043
|
+
return (input, pos) => {
|
|
2044
|
+
let end = pos;
|
|
2045
|
+
while (end < input.length && inRanges2(input.charCodeAt(end), ranges)) {
|
|
2046
|
+
end++;
|
|
2047
|
+
if (end - pos >= SCAN_BAIL_AT) return void 0;
|
|
2048
|
+
}
|
|
2049
|
+
return minOne && end === pos ? null : end;
|
|
1813
2050
|
};
|
|
1814
2051
|
}
|
|
1815
|
-
function
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
const
|
|
1823
|
-
|
|
2052
|
+
function asciiCaseFold(fs) {
|
|
2053
|
+
if (fs.kind !== "ranges") return fs;
|
|
2054
|
+
const ranges = fs.ranges.map((r) => ({ lo: r.lo, hi: r.hi }));
|
|
2055
|
+
const add = (lo, hi) => {
|
|
2056
|
+
if (lo <= hi) ranges.push({ lo, hi });
|
|
2057
|
+
};
|
|
2058
|
+
for (const r of fs.ranges) {
|
|
2059
|
+
const uLo = Math.max(r.lo, 65), uHi = Math.min(r.hi, 90);
|
|
2060
|
+
add(uLo + 32, uHi + 32);
|
|
2061
|
+
const lLo = Math.max(r.lo, 97), lHi = Math.min(r.hi, 122);
|
|
2062
|
+
add(lLo - 32, lHi - 32);
|
|
1824
2063
|
}
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
2064
|
+
ranges.sort((a, b) => a.lo - b.lo);
|
|
2065
|
+
const merged = [];
|
|
2066
|
+
for (const r of ranges) {
|
|
2067
|
+
const last = merged[merged.length - 1];
|
|
2068
|
+
if (last && r.lo <= last.hi + 1) last.hi = Math.max(last.hi, r.hi);
|
|
2069
|
+
else merged.push({ lo: r.lo, hi: r.hi });
|
|
1829
2070
|
}
|
|
1830
|
-
return
|
|
1831
|
-
}
|
|
1832
|
-
function armScanner(arm) {
|
|
1833
|
-
if (arm.kind === "comment") return lineCommentScanner(arm.code);
|
|
1834
|
-
const ranges = arm.ranges;
|
|
1835
|
-
return (input, cur) => {
|
|
1836
|
-
let pos = cur;
|
|
1837
|
-
while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
|
|
1838
|
-
return pos;
|
|
1839
|
-
};
|
|
2071
|
+
return { kind: "ranges", ranges: merged };
|
|
1840
2072
|
}
|
|
1841
|
-
function
|
|
1842
|
-
const
|
|
1843
|
-
const
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
2073
|
+
function regex(pattern, flags = "") {
|
|
2074
|
+
const source = typeof pattern === "string" ? pattern : pattern.source;
|
|
2075
|
+
const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
|
|
2076
|
+
const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
|
|
2077
|
+
const scan = shortScanner(source, resolvedFlags);
|
|
2078
|
+
const raw = (firstSetAnalyzer ?? permissiveFirstSet)(source);
|
|
2079
|
+
const firstSet = !resolvedFlags.includes("i") ? raw.firstSet : resolvedFlags.includes("u") || resolvedFlags.includes("v") ? any() : asciiCaseFold(raw.firstSet);
|
|
2080
|
+
const canMatchNewline = raw.canMatchNewline;
|
|
2081
|
+
const meta = { firstSet, canMatchNewline, isTrivia: false };
|
|
2082
|
+
return {
|
|
2083
|
+
_tag: "regex",
|
|
2084
|
+
_meta: meta,
|
|
2085
|
+
_def: { tag: "regex", source, flags: resolvedFlags },
|
|
2086
|
+
parse(input, pos, ctx) {
|
|
2087
|
+
const scanEnd = scan?.(input, pos);
|
|
2088
|
+
if (scanEnd !== void 0) {
|
|
2089
|
+
if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
|
|
2090
|
+
const value = input.slice(pos, scanEnd);
|
|
2091
|
+
const span2 = { start: pos, end: scanEnd };
|
|
2092
|
+
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, scanEnd);
|
|
2093
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span: span2 });
|
|
2094
|
+
return { ok: true, value, span: span2 };
|
|
1852
2095
|
}
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
if (cc === 10 || cc === 13) break;
|
|
1858
|
-
pos++;
|
|
1859
|
-
}
|
|
1860
|
-
continue;
|
|
2096
|
+
anchored.lastIndex = pos;
|
|
2097
|
+
const m = anchored.exec(input);
|
|
2098
|
+
if (m === null) {
|
|
2099
|
+
return failAt(ctx, [`/${source}/`], pos);
|
|
1861
2100
|
}
|
|
1862
|
-
|
|
2101
|
+
const span = { start: pos, end: pos + m[0].length };
|
|
2102
|
+
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
|
|
2103
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: m[0], span });
|
|
2104
|
+
return { ok: true, value: m[0], span };
|
|
1863
2105
|
}
|
|
1864
|
-
return pos;
|
|
1865
2106
|
};
|
|
1866
2107
|
}
|
|
1867
|
-
function splitTopLevelAlts(body) {
|
|
1868
|
-
const arms = [];
|
|
1869
|
-
let inClass = false;
|
|
1870
|
-
let start = 0;
|
|
1871
|
-
for (let i = 0; i < body.length; i++) {
|
|
1872
|
-
const c = body[i];
|
|
1873
|
-
if (c === "\\") {
|
|
1874
|
-
i++;
|
|
1875
|
-
continue;
|
|
1876
|
-
}
|
|
1877
|
-
if (inClass) {
|
|
1878
|
-
if (c === "]") inClass = false;
|
|
1879
|
-
continue;
|
|
1880
|
-
}
|
|
1881
|
-
if (c === "[") inClass = true;
|
|
1882
|
-
else if (c === "(") return null;
|
|
1883
|
-
else if (c === "|") {
|
|
1884
|
-
arms.push(body.slice(start, i));
|
|
1885
|
-
start = i + 1;
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
arms.push(body.slice(start));
|
|
1889
|
-
return arms;
|
|
1890
|
-
}
|
|
1891
|
-
function altStarSource(source) {
|
|
1892
|
-
const m = /^\(\?:(.*)\)[*+]$/.exec(source);
|
|
1893
|
-
if (!m) return null;
|
|
1894
|
-
const armSrcs = splitTopLevelAlts(m[1]);
|
|
1895
|
-
if (!armSrcs || armSrcs.length < 2) return null;
|
|
1896
|
-
const arms = [];
|
|
1897
|
-
for (const src of armSrcs) {
|
|
1898
|
-
const arm = classifyTriviaArm(src);
|
|
1899
|
-
if (!arm) return null;
|
|
1900
|
-
arms.push(arm);
|
|
1901
|
-
}
|
|
1902
|
-
const ranges = [];
|
|
1903
|
-
const commentCodes = [];
|
|
1904
|
-
for (const arm of arms) {
|
|
1905
|
-
if (arm.kind === "class") ranges.push(...arm.ranges);
|
|
1906
|
-
else commentCodes.push(arm.code);
|
|
1907
|
-
}
|
|
1908
|
-
if (commentCodes.some((code) => inRanges2(code, ranges))) {
|
|
1909
|
-
return loopScanner(arms.map(armScanner));
|
|
1910
|
-
}
|
|
1911
|
-
if (commentCodes.length === 0) return armScanner({ kind: "class", ranges });
|
|
1912
|
-
return fusedTriviaScanner(ranges, commentCodes);
|
|
1913
|
-
}
|
|
1914
|
-
function blockCommentSource(source) {
|
|
1915
|
-
return source === "\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/" || source === "\\/\\*[^]*?\\*\\/";
|
|
1916
|
-
}
|
|
1917
|
-
function scanBlockComment(input, cur) {
|
|
1918
|
-
if (input.charCodeAt(cur) !== 47 || input.charCodeAt(cur + 1) !== 42) return cur;
|
|
1919
|
-
const close = input.indexOf("*/", cur + 2);
|
|
1920
|
-
return close === -1 ? cur : close + 2;
|
|
1921
|
-
}
|
|
1922
2108
|
|
|
1923
2109
|
// src/combinators/sequence.ts
|
|
1924
2110
|
function sequence(...parsers) {
|
|
@@ -2334,6 +2520,25 @@ function trivia(combinator) {
|
|
|
2334
2520
|
parse: combinator.parse.bind(combinator)
|
|
2335
2521
|
};
|
|
2336
2522
|
}
|
|
2523
|
+
function classifiedTrivia(arms) {
|
|
2524
|
+
const entries = Object.entries(arms);
|
|
2525
|
+
if (entries.length === 0) {
|
|
2526
|
+
throw new TypeError("classifiedTrivia() requires at least one named trivia arm.");
|
|
2527
|
+
}
|
|
2528
|
+
for (let i = 0; i < entries.length; i++) {
|
|
2529
|
+
const [name, arm] = entries[i];
|
|
2530
|
+
const first = arm._meta.firstSet;
|
|
2531
|
+
if (matchesEmpty(arm) || first.kind !== "ranges" || first.ranges.length === 0) {
|
|
2532
|
+
throw new TypeError(
|
|
2533
|
+
`classifiedTrivia(): ${JSON.stringify(name)} must be non-nullable with a concrete finite first set.`
|
|
2534
|
+
);
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
const labeledArms = entries.map(([name, arm]) => label(name, arm));
|
|
2538
|
+
const result = trivia(oneOrMore(choice(...labeledArms)));
|
|
2539
|
+
result._meta.rootTriviaClassified = true;
|
|
2540
|
+
return result;
|
|
2541
|
+
}
|
|
2337
2542
|
function label(name, combinator) {
|
|
2338
2543
|
return {
|
|
2339
2544
|
_tag: combinator._tag,
|
|
@@ -2427,8 +2632,17 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
|
|
|
2427
2632
|
};
|
|
2428
2633
|
}
|
|
2429
2634
|
|
|
2635
|
+
// src/cst/trivia-entries.ts
|
|
2636
|
+
var EMPTY_INDICES = Object.freeze([]);
|
|
2637
|
+
var EMPTY_GAPS = Object.freeze([]);
|
|
2638
|
+
var SELECTED_ROOT_STRIDE = 5;
|
|
2639
|
+
|
|
2430
2640
|
// src/compiler/scannable-run.ts
|
|
2431
2641
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
2642
|
+
var SELECTED_ROOT_OWNED_RANGE_PLACEHOLDER = Array.from(
|
|
2643
|
+
{ length: SELECTED_ROOT_STRIDE - 3 },
|
|
2644
|
+
() => "0"
|
|
2645
|
+
).join(", ");
|
|
2432
2646
|
|
|
2433
2647
|
// src/compiler/trivia-fast-path.ts
|
|
2434
2648
|
var CAP_RECORD = [
|
|
@@ -2437,6 +2651,11 @@ var CAP_RECORD = [
|
|
|
2437
2651
|
` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
2438
2652
|
` }`
|
|
2439
2653
|
].join("\n");
|
|
2654
|
+
var SELECTED_ROOT_FINISH = [
|
|
2655
|
+
` if (_cap && _ctx._rootTriviaCapture !== false && _ctx._rootTriviaLog !== undefined && _ctx._rootTriviaLog.length !== _rootMark) {`,
|
|
2656
|
+
` for (let _ri = _rootMark; _ri < _ctx._rootTriviaLog.length; _ri += ${SELECTED_ROOT_STRIDE}) { _ctx._rootTriviaLog[_ri] = _pos; _ctx._rootTriviaLog[_ri + 1] = _e }`,
|
|
2657
|
+
` }`
|
|
2658
|
+
].join("\n");
|
|
2440
2659
|
|
|
2441
2660
|
// src/compiler/build-arity.ts
|
|
2442
2661
|
function cstOutputHost(build) {
|
|
@@ -2876,10 +3095,12 @@ function attempt(parser2) {
|
|
|
2876
3095
|
}
|
|
2877
3096
|
const mark = saveCstMark(ctx);
|
|
2878
3097
|
const log = ctx._triviaLog?.length;
|
|
3098
|
+
const rootLog = ctx._rootTriviaLog?.length;
|
|
2879
3099
|
const result = parser2.parse(input, pos, ctx);
|
|
2880
3100
|
if (result.ok) return result;
|
|
2881
3101
|
rollbackCstCapture(ctx, mark);
|
|
2882
3102
|
if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
|
|
3103
|
+
if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
|
|
2883
3104
|
if (result.committed) return result;
|
|
2884
3105
|
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
2885
3106
|
}
|
|
@@ -2976,13 +3197,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2976
3197
|
const collapse = opts?.collapse === true;
|
|
2977
3198
|
const captureTrivia = opts?.captureTrivia === true;
|
|
2978
3199
|
const trailingTrivia = opts?.trailingTrivia === true;
|
|
3200
|
+
const tags = opts?.tags;
|
|
2979
3201
|
if (unwrap && collapse) {
|
|
2980
3202
|
throw new Error("node() options cannot set both unwrap and collapse");
|
|
2981
3203
|
}
|
|
2982
3204
|
if (project !== void 0 && (unwrap || collapse)) {
|
|
2983
3205
|
throw new Error("node() options cannot combine project with unwrap or collapse");
|
|
2984
3206
|
}
|
|
2985
|
-
const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {} } : baseDef;
|
|
3207
|
+
const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
|
|
2986
3208
|
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
|
|
2987
3209
|
const clonesState = build ? buildReadsState(def) : project === void 0;
|
|
2988
3210
|
const hasOwnFields = parserHasOwnFields(combinator);
|
|
@@ -3028,7 +3250,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
3028
3250
|
const cstOutput = cstOutputHost(ctx.build);
|
|
3029
3251
|
const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
|
|
3030
3252
|
const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
3031
|
-
const built = unwrap && children.length === 1 ? unwrapChild(children[0]) : collapse && children.length === 1 ? children[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children[0], children, rawChildren) ? children[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, hostState) : projectChild(children, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, hostState) : build(children, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children };
|
|
3253
|
+
const built = unwrap && children.length === 1 ? unwrapChild(children[0]) : collapse && children.length === 1 ? children[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children[0], children, rawChildren) ? children[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, hostState, tags) : projectChild(children, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, hostState, tags) : build(children, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, st, tags) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children };
|
|
3032
3254
|
const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : typeof built === "object" && built !== null ? input.slice(r.span.start, r.span.end) : "", span };
|
|
3033
3255
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
3034
3256
|
pushCstChild(ctx, built, rawEntry);
|
|
@@ -3058,6 +3280,7 @@ function token(root) {
|
|
|
3058
3280
|
const savedRaw = ctx._cstRawChildren;
|
|
3059
3281
|
const savedTriviaLog = ctx._cstTriviaLog;
|
|
3060
3282
|
const savedOuterTriviaLog = ctx._triviaLog;
|
|
3283
|
+
const savedRootTriviaLog = ctx._rootTriviaLog;
|
|
3061
3284
|
const wasCapturing = cstCaptureActive(ctx);
|
|
3062
3285
|
ctx.trivia = void 0;
|
|
3063
3286
|
ctx.triviaKindLabels = void 0;
|
|
@@ -3067,6 +3290,7 @@ function token(root) {
|
|
|
3067
3290
|
ctx._cstRawChildren = void 0;
|
|
3068
3291
|
ctx._cstTriviaLog = void 0;
|
|
3069
3292
|
delete ctx._triviaLog;
|
|
3293
|
+
delete ctx._rootTriviaLog;
|
|
3070
3294
|
let result;
|
|
3071
3295
|
try {
|
|
3072
3296
|
result = root.parse(input, pos, ctx);
|
|
@@ -3080,6 +3304,8 @@ function token(root) {
|
|
|
3080
3304
|
ctx._cstTriviaLog = savedTriviaLog;
|
|
3081
3305
|
if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
|
|
3082
3306
|
else ctx._triviaLog = savedOuterTriviaLog;
|
|
3307
|
+
if (savedRootTriviaLog === void 0) delete ctx._rootTriviaLog;
|
|
3308
|
+
else ctx._rootTriviaLog = savedRootTriviaLog;
|
|
3083
3309
|
}
|
|
3084
3310
|
if (!result.ok) return result;
|
|
3085
3311
|
const span = result.span;
|
|
@@ -3259,6 +3485,7 @@ function evalRuleMapIR(ir) {
|
|
|
3259
3485
|
"transform",
|
|
3260
3486
|
"skip",
|
|
3261
3487
|
"trivia",
|
|
3488
|
+
"classifiedTrivia",
|
|
3262
3489
|
"label",
|
|
3263
3490
|
"field",
|
|
3264
3491
|
"expect",
|
|
@@ -3299,6 +3526,7 @@ function evalRuleMapIR(ir) {
|
|
|
3299
3526
|
transform,
|
|
3300
3527
|
skip,
|
|
3301
3528
|
trivia,
|
|
3529
|
+
classifiedTrivia,
|
|
3302
3530
|
label,
|
|
3303
3531
|
field,
|
|
3304
3532
|
expect,
|
|
@@ -3320,15 +3548,16 @@ function normalizeCstCollapse(collapse) {
|
|
|
3320
3548
|
}
|
|
3321
3549
|
return typeof collapse === "function" ? collapse : void 0;
|
|
3322
3550
|
}
|
|
3323
|
-
function buildCstNode(type, children, _fields, span, _rawChildren, _triviaLog, state) {
|
|
3324
|
-
return { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children] };
|
|
3551
|
+
function buildCstNode(type, children, _fields, span, _rawChildren, _triviaLog, state, tags) {
|
|
3552
|
+
return tags !== void 0 && tags.length > 0 ? { _tag: "node", type, tags, span: { ...span }, state: state ?? null, children: [...children] } : { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children] };
|
|
3325
3553
|
}
|
|
3326
|
-
function cstBuildHost(typeOrOptions, children, _fields, span, rawChildren, triviaLog, state) {
|
|
3554
|
+
function cstBuildHost(typeOrOptions, children, _fields, span, rawChildren, triviaLog, state, _tags) {
|
|
3327
3555
|
if (typeof typeOrOptions === "string") {
|
|
3328
3556
|
return buildCstNode(typeOrOptions, children ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
|
|
3329
3557
|
}
|
|
3330
3558
|
const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
|
|
3331
|
-
const
|
|
3559
|
+
const materializeTags = typeOrOptions?.tags === true;
|
|
3560
|
+
const host = (type, children2, fields, span2, rawChildren2, triviaLog2, state2, tags) => buildCstNode(type, children2 ?? [], fields, span2, rawChildren2, triviaLog2, state2, materializeTags ? tags : void 0);
|
|
3332
3561
|
host._parsemanCstOutput = true;
|
|
3333
3562
|
if (collapse) host._parsemanCstCollapse = collapse;
|
|
3334
3563
|
return host;
|