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