parseman 0.43.0 → 0.45.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/analysis/diagnose.d.ts +118 -0
- package/dist/analysis/diagnose.d.ts.map +1 -0
- package/dist/analysis/gating.d.ts +9 -9
- package/dist/analysis/gating.d.ts.map +1 -1
- package/dist/analysis/grammar.d.ts.map +1 -1
- package/dist/combinators/attempt.d.ts.map +1 -1
- package/dist/combinators/choice.d.ts.map +1 -1
- package/dist/combinators/dispatch.d.ts +19 -1
- package/dist/combinators/dispatch.d.ts.map +1 -1
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/first-set.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 +19 -0
- package/dist/combinators/node.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/build-arity.d.ts +28 -0
- package/dist/compiler/build-arity.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts +80 -60
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/degradation.d.ts +123 -0
- package/dist/compiler/degradation.d.ts.map +1 -0
- package/dist/compiler/fields.d.ts.map +1 -1
- package/dist/compiler/grammar-coverage-ids.d.ts.map +1 -1
- package/dist/compiler/inline-build.d.ts.map +1 -1
- package/dist/compiler/ir-serialize.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +1 -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/coverage.d.ts +13 -0
- package/dist/coverage.d.ts.map +1 -1
- package/dist/cst/reflection.d.ts.map +1 -1
- 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/functional/run.d.ts +22 -16
- package/dist/functional/run.d.ts.map +1 -1
- package/dist/index.cjs +2131 -1594
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +6 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2131 -1594
- package/dist/index.js.map +4 -4
- package/dist/language-service/index.cjs +201 -132
- package/dist/language-service/index.cjs.map +4 -4
- package/dist/language-service/index.js +201 -132
- package/dist/language-service/index.js.map +4 -4
- package/dist/oracle/digest.d.ts +132 -6
- package/dist/oracle/digest.d.ts.map +1 -1
- package/dist/oracle/index.cjs +136 -305
- package/dist/oracle/index.cjs.map +4 -4
- package/dist/oracle/index.d.ts +43 -31
- package/dist/oracle/index.d.ts.map +1 -1
- package/dist/oracle/index.js +136 -305
- package/dist/oracle/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts +3 -0
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +2333 -1721
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts +18 -0
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +2333 -1721
- package/dist/plugin/index.js.map +4 -4
- package/dist/plugin/reducer-resolver.d.ts +41 -0
- package/dist/plugin/reducer-resolver.d.ts.map +1 -0
- package/dist/run/index.cjs +185 -132
- 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 +185 -132
- package/dist/run/index.js.map +3 -3
- package/dist/spec/index.cjs +1637 -1322
- package/dist/spec/index.cjs.map +4 -4
- package/dist/spec/index.js +1637 -1322
- package/dist/spec/index.js.map +4 -4
- package/dist/spec/model.d.ts.map +1 -1
- package/dist/types.d.ts +31 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +7 -3
- package/dist/combinators/guard.d.ts +0 -8
- package/dist/combinators/guard.d.ts.map +0 -1
- package/dist/cst/offset-model.d.ts +0 -119
- package/dist/cst/offset-model.d.ts.map +0 -1
- package/dist/oracle/corpus.d.ts +0 -32
- package/dist/oracle/corpus.d.ts.map +0 -1
- package/dist/oracle/identity.d.ts +0 -117
- package/dist/oracle/identity.d.ts.map +0 -1
package/dist/spec/index.cjs
CHANGED
|
@@ -82,8 +82,9 @@ function matchesEmpty(p, seen = /* @__PURE__ */ new Set(), resolve) {
|
|
|
82
82
|
return d.value.length === 0;
|
|
83
83
|
case "keywords":
|
|
84
84
|
return false;
|
|
85
|
+
// The routed token itself is the selector's match, never empty; a fallback can be.
|
|
85
86
|
case "routed":
|
|
86
|
-
return false;
|
|
87
|
+
return d.fallback === void 0 ? false : me(d.fallback);
|
|
87
88
|
case "regex":
|
|
88
89
|
try {
|
|
89
90
|
const m = new RegExp(d.source).exec("");
|
|
@@ -610,1448 +611,1539 @@ function pushTriviaLogEntry(ctx, start, end, kindIndex) {
|
|
|
610
611
|
}
|
|
611
612
|
}
|
|
612
613
|
|
|
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
|
-
}
|
|
614
|
+
// src/cst/trivia-kinds.ts
|
|
615
|
+
var labeledTriviaSpecs = /* @__PURE__ */ new WeakMap();
|
|
616
|
+
function unwrapTrivia(p) {
|
|
617
|
+
let cur = p;
|
|
618
|
+
while (cur._def.tag === "trivia") cur = cur._def.parser;
|
|
619
|
+
return cur;
|
|
654
620
|
}
|
|
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
|
-
};
|
|
621
|
+
function peelLabel(p) {
|
|
622
|
+
if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
|
|
623
|
+
return null;
|
|
667
624
|
}
|
|
668
|
-
function
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
625
|
+
function analyzeLabeledTrivia(trivia2) {
|
|
626
|
+
const cached = labeledTriviaSpecs.get(trivia2);
|
|
627
|
+
if (cached !== void 0) return cached;
|
|
628
|
+
let core = unwrapTrivia(trivia2);
|
|
629
|
+
let minRepeats = 1;
|
|
630
|
+
if (core._def.tag === "oneOrMore") {
|
|
631
|
+
core = core._def.parser;
|
|
632
|
+
minRepeats = 1;
|
|
633
|
+
} else if (core._def.tag === "many") {
|
|
634
|
+
core = core._def.parser;
|
|
635
|
+
minRepeats = 0;
|
|
636
|
+
}
|
|
637
|
+
const arms = [];
|
|
638
|
+
if (core._def.tag === "choice") {
|
|
639
|
+
for (let i = 0; i < core._def.parsers.length; i++) {
|
|
640
|
+
const peeled = peelLabel(core._def.parsers[i]);
|
|
641
|
+
if (!peeled) {
|
|
642
|
+
labeledTriviaSpecs.set(trivia2, null);
|
|
643
|
+
return null;
|
|
681
644
|
}
|
|
682
|
-
|
|
645
|
+
arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
|
|
683
646
|
}
|
|
647
|
+
} else {
|
|
648
|
+
const peeled = peelLabel(core);
|
|
649
|
+
if (!peeled) {
|
|
650
|
+
labeledTriviaSpecs.set(trivia2, null);
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
653
|
+
arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
|
|
654
|
+
}
|
|
655
|
+
const spec = {
|
|
656
|
+
labels: arms.map((a) => a.label),
|
|
657
|
+
arms,
|
|
658
|
+
minRepeats
|
|
684
659
|
};
|
|
660
|
+
labeledTriviaSpecs.set(trivia2, spec);
|
|
661
|
+
return spec;
|
|
685
662
|
}
|
|
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);
|
|
663
|
+
function matchArmAt(input, pos, arm, state) {
|
|
664
|
+
if (!startsFirstSet(arm, input, pos)) return null;
|
|
665
|
+
const r = arm.parse(input, pos, { trackLines: false, state });
|
|
666
|
+
if (!r.ok || r.span.end <= pos) return null;
|
|
667
|
+
return { end: r.span.end };
|
|
697
668
|
}
|
|
698
|
-
function
|
|
699
|
-
|
|
669
|
+
function scanLabeledTriviaChunks(input, cur, spec, state) {
|
|
670
|
+
const chunks = [];
|
|
671
|
+
let pos = cur;
|
|
672
|
+
while (pos < input.length) {
|
|
673
|
+
let matched = null;
|
|
674
|
+
for (const arm of spec.arms) {
|
|
675
|
+
const m = matchArmAt(input, pos, arm.parser, state);
|
|
676
|
+
if (m) {
|
|
677
|
+
matched = { end: m.end, kindIndex: arm.kindIndex };
|
|
678
|
+
break;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (!matched) break;
|
|
682
|
+
chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
|
|
683
|
+
pos = matched.end;
|
|
684
|
+
}
|
|
685
|
+
if (chunks.length < spec.minRepeats) {
|
|
686
|
+
return { end: cur, chunks: [] };
|
|
687
|
+
}
|
|
688
|
+
return { end: pos, chunks };
|
|
700
689
|
}
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
690
|
+
function scanLabeledTriviaEnd(input, cur, spec, state) {
|
|
691
|
+
let pos = cur;
|
|
692
|
+
let count = 0;
|
|
693
|
+
while (pos < input.length) {
|
|
694
|
+
let matched = null;
|
|
695
|
+
for (const arm of spec.arms) {
|
|
696
|
+
matched = matchArmAt(input, pos, arm.parser, state);
|
|
697
|
+
if (matched) break;
|
|
698
|
+
}
|
|
699
|
+
if (!matched) break;
|
|
700
|
+
pos = matched.end;
|
|
701
|
+
count++;
|
|
702
|
+
}
|
|
703
|
+
return count < spec.minRepeats ? cur : pos;
|
|
705
704
|
}
|
|
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;
|
|
705
|
+
function visitLabeledTrivia(input, cur, spec, state, visit) {
|
|
706
|
+
if (spec.minRepeats > 1) return void 0;
|
|
707
|
+
let pos = cur;
|
|
708
|
+
let count = 0;
|
|
709
|
+
while (pos < input.length) {
|
|
710
|
+
let matched = null;
|
|
711
|
+
for (const arm of spec.arms) {
|
|
712
|
+
const match = matchArmAt(input, pos, arm.parser, state);
|
|
713
|
+
if (match) {
|
|
714
|
+
matched = { end: match.end, kindIndex: arm.kindIndex };
|
|
715
|
+
break;
|
|
733
716
|
}
|
|
734
|
-
return out;
|
|
735
717
|
}
|
|
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);
|
|
718
|
+
if (!matched) break;
|
|
719
|
+
visit(pos, matched.end, matched.kindIndex);
|
|
720
|
+
pos = matched.end;
|
|
721
|
+
count++;
|
|
722
|
+
}
|
|
723
|
+
return count < spec.minRepeats ? cur : pos;
|
|
724
|
+
}
|
|
725
|
+
function recordTriviaChunks(ctx, chunks) {
|
|
726
|
+
const kinds = ctx.triviaKindLabels;
|
|
727
|
+
const mask = ctx._triviaCaptureMask;
|
|
728
|
+
const rootLog = ctx._rootTriviaLog;
|
|
729
|
+
const rootKinds = ctx._rootTriviaKindIndex;
|
|
730
|
+
const rootMark = rootLog?.length ?? 0;
|
|
731
|
+
for (const ch of chunks) {
|
|
732
|
+
pushTriviaLogEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
733
|
+
const rootKindIndex = ctx._rootTriviaCapture === false || rootLog === void 0 || rootKinds === void 0 || kinds === void 0 ? -1 : rootKinds[kinds[ch.kindIndex] ?? ""] ?? -1;
|
|
734
|
+
if (rootKindIndex >= 0) {
|
|
735
|
+
rootLog.push(0, 0, ch.start, ch.end, rootKindIndex);
|
|
736
|
+
}
|
|
737
|
+
if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
|
|
738
|
+
if (mask === void 0 || kinds === void 0 || (mask & 1 << ch.kindIndex) !== 0) {
|
|
739
|
+
pushCstTriviaEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
773
740
|
}
|
|
774
741
|
}
|
|
775
|
-
default:
|
|
776
|
-
return [];
|
|
777
742
|
}
|
|
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 } };
|
|
743
|
+
if (rootLog !== void 0 && rootLog.length !== rootMark && chunks.length > 0) {
|
|
744
|
+
const start = chunks[0].start;
|
|
745
|
+
const end = chunks[chunks.length - 1].end;
|
|
746
|
+
for (let offset = rootMark; offset < rootLog.length; offset += 5) {
|
|
747
|
+
rootLog[offset] = start;
|
|
748
|
+
rootLog[offset + 1] = end;
|
|
798
749
|
}
|
|
799
|
-
}
|
|
750
|
+
}
|
|
800
751
|
}
|
|
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
|
-
|
|
752
|
+
function triviaKindMask(labels, keep) {
|
|
753
|
+
if (!labels) return void 0;
|
|
754
|
+
let mask = 0;
|
|
755
|
+
for (const name of keep) {
|
|
756
|
+
const idx = labels.indexOf(name);
|
|
757
|
+
if (idx >= 0) mask |= 1 << idx;
|
|
758
|
+
}
|
|
759
|
+
return mask;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
// src/combinators/grammar.ts
|
|
763
|
+
function annotateResultLines(result, index) {
|
|
764
|
+
const annotated = { ...result, span: annotateSpan(result.span, index) };
|
|
765
|
+
const errors = annotated.errors;
|
|
766
|
+
if (errors) {
|
|
767
|
+
;
|
|
768
|
+
annotated.errors = errors.map((error) => ({
|
|
769
|
+
...error,
|
|
770
|
+
span: annotateSpan(error.span, index)
|
|
771
|
+
}));
|
|
772
|
+
}
|
|
773
|
+
return annotated;
|
|
774
|
+
}
|
|
775
|
+
function createParseLineContext(input, pos) {
|
|
776
|
+
const lineIndex = createLineIndex();
|
|
777
|
+
if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
|
|
778
|
+
return { lineIndex, lineScannedTo: pos };
|
|
779
|
+
}
|
|
780
|
+
function parser(opts, root) {
|
|
781
|
+
const clearTrivia = opts.trivia === null;
|
|
782
|
+
const opaqueRootCapture = opts.rootCapture === "opaque";
|
|
783
|
+
if (opaqueRootCapture && opts.trivia === void 0) {
|
|
784
|
+
throw new TypeError("parser({ rootCapture: 'opaque' }) requires an explicit trivia scope.");
|
|
830
785
|
}
|
|
831
786
|
return {
|
|
832
|
-
_tag: "
|
|
833
|
-
_meta:
|
|
787
|
+
_tag: "grammar",
|
|
788
|
+
_meta: {
|
|
789
|
+
...root._meta,
|
|
790
|
+
// Trivia classification describes this grammar's own active trivia
|
|
791
|
+
// scope. A directly nested grammar may have classified trivia of its
|
|
792
|
+
// own, but that must not advertise classification for this wrapper.
|
|
793
|
+
triviaKindLabels: void 0,
|
|
794
|
+
rootTriviaClassified: void 0,
|
|
795
|
+
...opts.trivia?._meta?.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {},
|
|
796
|
+
...opts.trivia?._meta?.rootTriviaClassified ? { rootTriviaClassified: true } : {}
|
|
797
|
+
},
|
|
834
798
|
_def: {
|
|
835
|
-
tag: "
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
799
|
+
tag: "grammar",
|
|
800
|
+
parser: root,
|
|
801
|
+
triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
|
|
802
|
+
clearTrivia,
|
|
803
|
+
...opaqueRootCapture ? { rootCapture: "opaque" } : {},
|
|
804
|
+
...opts.captureTrivia ? { captureTrivia: true } : {},
|
|
805
|
+
trackLines: opts.trackLines ?? false
|
|
841
806
|
},
|
|
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 } };
|
|
807
|
+
parse(input, pos, _ctx) {
|
|
808
|
+
if (_ctx?._rootTriviaStrictScopes && opts.trivia !== void 0 && opts.trivia !== null && !opts.trivia._meta.rootTriviaClassified && !opaqueRootCapture) {
|
|
809
|
+
throw new TypeError(
|
|
810
|
+
"parser(): selected root trivia requires classifiedTrivia() for every local trivia scope, or rootCapture: 'opaque'."
|
|
811
|
+
);
|
|
894
812
|
}
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
813
|
+
const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
|
|
814
|
+
const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
|
|
815
|
+
const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
|
|
816
|
+
const ctx = {
|
|
817
|
+
..._ctx,
|
|
818
|
+
trackLines,
|
|
819
|
+
...lineIndex ? { _lineIndex: lineIndex } : {},
|
|
820
|
+
...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
|
|
821
|
+
// trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
|
|
822
|
+
...clearTrivia ? {
|
|
823
|
+
trivia: void 0,
|
|
824
|
+
triviaKindLabels: void 0
|
|
825
|
+
} : opts.trivia != null ? {
|
|
826
|
+
trivia: opts.trivia,
|
|
827
|
+
...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
|
|
828
|
+
} : {},
|
|
829
|
+
...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
|
|
830
|
+
// Kind-filter for per-node capture. Resolve against this scope's trivia
|
|
831
|
+
// labels — this parser's own trivia if it declares one, else the INHERITED
|
|
832
|
+
// labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
|
|
833
|
+
// trivia is inherited rather than re-declared here. No labels → undefined
|
|
834
|
+
// (capture all).
|
|
835
|
+
...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {},
|
|
836
|
+
// This is a property of the local trivia scope, not a post-parse filter:
|
|
837
|
+
// nested recognition can still skip its trivia, but selected root rows
|
|
838
|
+
// must never be written for an explicitly opaque region.
|
|
839
|
+
...opaqueRootCapture ? { _rootTriviaCapture: false } : {}
|
|
840
|
+
};
|
|
841
|
+
const result = root.parse(input, pos ?? 0, ctx);
|
|
842
|
+
if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
|
|
843
|
+
_ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
|
|
914
844
|
}
|
|
915
|
-
return
|
|
845
|
+
return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
|
|
916
846
|
}
|
|
917
847
|
};
|
|
918
848
|
}
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
849
|
+
|
|
850
|
+
// src/cst/reflection.ts
|
|
851
|
+
var GRAMMAR_REFLECTION = /* @__PURE__ */ Symbol.for("parseman.grammarReflection");
|
|
852
|
+
function childrenOf(def) {
|
|
853
|
+
switch (def.tag) {
|
|
854
|
+
case "sequence":
|
|
855
|
+
case "choice":
|
|
856
|
+
return def.parsers;
|
|
857
|
+
case "dispatch":
|
|
858
|
+
return [
|
|
859
|
+
def.selector,
|
|
860
|
+
...def.cases.map((c) => c.parser),
|
|
861
|
+
...def.matchers ? def.matchers.map((c) => c.parser) : [],
|
|
862
|
+
...def.otherwise ? [def.otherwise] : []
|
|
863
|
+
];
|
|
864
|
+
case "many":
|
|
865
|
+
case "oneOrMore":
|
|
866
|
+
case "optional":
|
|
867
|
+
case "attempt":
|
|
868
|
+
case "transform":
|
|
869
|
+
case "trivia":
|
|
870
|
+
case "token":
|
|
871
|
+
case "leaf":
|
|
872
|
+
case "label":
|
|
873
|
+
case "field":
|
|
874
|
+
case "not":
|
|
875
|
+
case "peek":
|
|
876
|
+
case "node":
|
|
877
|
+
case "withCtx":
|
|
878
|
+
case "recover":
|
|
879
|
+
case "expect":
|
|
880
|
+
return [def.parser];
|
|
881
|
+
case "grammar":
|
|
882
|
+
return def.triviaParser ? [def.parser, def.triviaParser] : [def.parser];
|
|
883
|
+
case "sepBy":
|
|
884
|
+
return [def.parser, def.separator];
|
|
885
|
+
case "skip":
|
|
886
|
+
return [def.main, def.skipped];
|
|
887
|
+
case "scanTo":
|
|
888
|
+
return [def.sentinel, ...def.skip];
|
|
889
|
+
case "routed":
|
|
890
|
+
return def.fallback ? [def.fallback] : [];
|
|
891
|
+
case "literal":
|
|
892
|
+
case "regex":
|
|
893
|
+
case "keywords":
|
|
894
|
+
case "guard":
|
|
895
|
+
case "lazy":
|
|
896
|
+
case "unknown":
|
|
897
|
+
return [];
|
|
925
898
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
re.lastIndex = 0;
|
|
934
|
-
const m = re.exec(litVal);
|
|
935
|
-
return m !== null && m[0] === litVal;
|
|
936
|
-
});
|
|
937
|
-
if (allSubsumed) return { tag: "greedyClassify", superIndex };
|
|
899
|
+
}
|
|
900
|
+
function addNode(out, def) {
|
|
901
|
+
if (def.type === void 0) return;
|
|
902
|
+
const existing = out.get(def.type);
|
|
903
|
+
if (existing === void 0) {
|
|
904
|
+
out.set(def.type, def.tags === void 0 ? [] : [...def.tags]);
|
|
905
|
+
return;
|
|
938
906
|
}
|
|
939
|
-
if (
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
);
|
|
943
|
-
return { tag: "literalsLongestFirst", sortedIndices };
|
|
907
|
+
if (def.tags === void 0) return;
|
|
908
|
+
for (const tag of def.tags) {
|
|
909
|
+
if (!existing.includes(tag)) existing.push(tag);
|
|
944
910
|
}
|
|
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
911
|
}
|
|
955
|
-
function
|
|
956
|
-
if (
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
prefix = term0;
|
|
968
|
-
} else if (k !== key) return null;
|
|
969
|
-
members.push(i);
|
|
912
|
+
function collectFromCombinator(parser2, out, seen, followLazy = true) {
|
|
913
|
+
if (seen.has(parser2)) return;
|
|
914
|
+
seen.add(parser2);
|
|
915
|
+
const def = parser2._def;
|
|
916
|
+
if (def.tag === "lazy") {
|
|
917
|
+
if (followLazy) {
|
|
918
|
+
try {
|
|
919
|
+
collectFromCombinator(def.thunk(), out, seen, followLazy);
|
|
920
|
+
} catch {
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
return;
|
|
970
924
|
}
|
|
971
|
-
if (
|
|
972
|
-
|
|
925
|
+
if (def.tag === "node") addNode(out, def);
|
|
926
|
+
for (const child of childrenOf(def)) collectFromCombinator(child, out, seen, followLazy);
|
|
973
927
|
}
|
|
974
|
-
function
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
928
|
+
function collectGrammarReflection(ruleMap, opts) {
|
|
929
|
+
const byType = /* @__PURE__ */ new Map();
|
|
930
|
+
const followLazy = opts?.followLazy !== false;
|
|
931
|
+
for (const [, rule] of ruleMap) {
|
|
932
|
+
if (!followLazy && rule._def.tag === "lazy") {
|
|
933
|
+
try {
|
|
934
|
+
const resolved = rule._def.thunk();
|
|
935
|
+
if (resolved._def.tag !== "lazy") collectFromCombinator(resolved, byType, /* @__PURE__ */ new Set(), false);
|
|
936
|
+
} catch {
|
|
937
|
+
}
|
|
979
938
|
continue;
|
|
980
939
|
}
|
|
981
|
-
|
|
940
|
+
collectFromCombinator(rule, byType, /* @__PURE__ */ new Set(), followLazy);
|
|
982
941
|
}
|
|
983
|
-
|
|
984
|
-
return d.parsers[0];
|
|
942
|
+
return { nodes: [...byType].map(([type, tags]) => ({ type, tags })) };
|
|
985
943
|
}
|
|
986
|
-
function
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
944
|
+
function attachGrammarReflection(grammar, reflection) {
|
|
945
|
+
Object.defineProperty(grammar, GRAMMAR_REFLECTION, { value: reflection, enumerable: false, configurable: true });
|
|
946
|
+
return grammar;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// src/combinators/parser.ts
|
|
950
|
+
var RULE_ORDER = "__parsemanRuleOrder";
|
|
951
|
+
function tagRule(r, key) {
|
|
952
|
+
;
|
|
953
|
+
r._ruleName = key;
|
|
954
|
+
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
|
|
955
|
+
}
|
|
956
|
+
function isDefinableRef(v) {
|
|
957
|
+
return !!v && typeof v === "object" && "_def" in v && v._def.tag === "lazy" && typeof v.define === "function";
|
|
958
|
+
}
|
|
959
|
+
function ruleNameOf(r) {
|
|
960
|
+
return r._ruleName;
|
|
961
|
+
}
|
|
962
|
+
function isNamedRuleRefForAnotherRule(r, key) {
|
|
963
|
+
const name = r._def.tag === "lazy" ? ruleNameOf(r) : void 0;
|
|
964
|
+
return name !== void 0 && name !== key;
|
|
965
|
+
}
|
|
966
|
+
function rules(a, b) {
|
|
967
|
+
const factory = typeof a === "function" ? a : b;
|
|
968
|
+
const options = typeof a === "function" ? b : a;
|
|
969
|
+
const cache = {};
|
|
970
|
+
const proxy = new Proxy(cache, {
|
|
971
|
+
get(target, key) {
|
|
972
|
+
if (typeof key !== "string") return void 0;
|
|
973
|
+
const record = target;
|
|
974
|
+
if (!(key in record)) {
|
|
975
|
+
const r = ref();
|
|
976
|
+
tagRule(r, key);
|
|
977
|
+
record[key] = r;
|
|
997
978
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
979
|
+
return record[key];
|
|
980
|
+
}
|
|
981
|
+
});
|
|
982
|
+
const definitions = factory(proxy);
|
|
983
|
+
for (const key of Object.keys(definitions)) {
|
|
984
|
+
const placeholder = cache[key];
|
|
985
|
+
const parser2 = definitions[key];
|
|
986
|
+
if (placeholder === parser2) {
|
|
987
|
+
throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
|
|
988
|
+
}
|
|
989
|
+
if (isDefinableRef(placeholder)) {
|
|
990
|
+
if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
|
|
991
|
+
placeholder.define(parser2);
|
|
992
|
+
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
993
|
+
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
994
|
+
} else if (isNamedRuleRefForAnotherRule(parser2, key)) {
|
|
995
|
+
const alias = ref();
|
|
996
|
+
tagRule(alias, key);
|
|
997
|
+
alias.define(parser2);
|
|
998
|
+
alias._meta.firstSet = parser2._meta.firstSet;
|
|
999
|
+
alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
1000
|
+
cache[key] = alias;
|
|
1001
|
+
} else {
|
|
1002
|
+
tagRule(parser2, key);
|
|
1003
|
+
cache[key] = parser2;
|
|
1004
|
+
}
|
|
1005
|
+
}
|
|
1006
|
+
if (options?.trivia != null) {
|
|
1007
|
+
for (const key of Object.keys(definitions)) {
|
|
1008
|
+
const rule = cache[key];
|
|
1009
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
if (options?.scanSkip != null) {
|
|
1013
|
+
for (const key of Object.keys(definitions)) {
|
|
1014
|
+
const rule = cache[key];
|
|
1015
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarScanSkip = options.scanSkip;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
if (options?.hostMode === "cst") {
|
|
1019
|
+
for (const key of Object.keys(definitions)) {
|
|
1020
|
+
const rule = cache[key];
|
|
1021
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarHostMode = "cst";
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
if (options?.trackLines === true) {
|
|
1025
|
+
for (const key of Object.keys(definitions)) {
|
|
1026
|
+
const rule = cache[key];
|
|
1027
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrackLines = true;
|
|
1028
|
+
}
|
|
1029
|
+
for (const key of Object.keys(definitions)) {
|
|
1030
|
+
const rule = cache[key];
|
|
1031
|
+
if (rule && !rule._meta.isTrivia && rule._def.tag !== "grammar") {
|
|
1032
|
+
const wrapped = parser({ trackLines: true }, rule);
|
|
1033
|
+
tagRule(wrapped, key);
|
|
1034
|
+
wrapped._meta.grammarTrackLines = true;
|
|
1035
|
+
cache[key] = wrapped;
|
|
1002
1036
|
}
|
|
1003
1037
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1038
|
+
}
|
|
1039
|
+
for (const key of Object.keys(definitions)) {
|
|
1040
|
+
markUnusedValues(cache[key]);
|
|
1041
|
+
}
|
|
1042
|
+
Object.defineProperty(cache, RULE_ORDER, {
|
|
1043
|
+
value: Object.keys(definitions),
|
|
1044
|
+
enumerable: false,
|
|
1045
|
+
configurable: true
|
|
1046
|
+
});
|
|
1047
|
+
attachGrammarReflection(cache, collectGrammarReflection(Object.keys(definitions).map((key) => [key, cache[key]])));
|
|
1048
|
+
return cache;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
// src/recovery/scan.ts
|
|
1052
|
+
function probeAt(sentinel, input, pos, ctx) {
|
|
1053
|
+
const s = {
|
|
1054
|
+
_probe: ctx._probe,
|
|
1055
|
+
_errors: ctx._errors,
|
|
1056
|
+
_cstLeaves: ctx._cstLeaves,
|
|
1057
|
+
_cstChildren: ctx._cstChildren,
|
|
1058
|
+
_cstRawChildren: ctx._cstRawChildren,
|
|
1059
|
+
_cstTriviaLog: ctx._cstTriviaLog,
|
|
1060
|
+
_triviaLog: ctx._triviaLog,
|
|
1061
|
+
_rootTriviaLog: ctx._rootTriviaLog,
|
|
1062
|
+
_fields: ctx._fields,
|
|
1063
|
+
_cstBuf: ctx._cstBuf,
|
|
1064
|
+
_tolerant: ctx._tolerant,
|
|
1065
|
+
_sync: ctx._sync
|
|
1066
|
+
};
|
|
1067
|
+
ctx._probe = void 0;
|
|
1068
|
+
ctx._errors = void 0;
|
|
1069
|
+
ctx._cstLeaves = void 0;
|
|
1070
|
+
ctx._cstChildren = void 0;
|
|
1071
|
+
ctx._cstRawChildren = void 0;
|
|
1072
|
+
ctx._cstTriviaLog = void 0;
|
|
1073
|
+
ctx._triviaLog = void 0;
|
|
1074
|
+
ctx._rootTriviaLog = void 0;
|
|
1075
|
+
ctx._fields = void 0;
|
|
1076
|
+
ctx._cstBuf = void 0;
|
|
1077
|
+
ctx._tolerant = void 0;
|
|
1078
|
+
ctx._sync = void 0;
|
|
1079
|
+
try {
|
|
1080
|
+
return sentinel.parse(input, pos, ctx).ok;
|
|
1081
|
+
} finally {
|
|
1082
|
+
ctx._probe = s._probe;
|
|
1083
|
+
ctx._errors = s._errors;
|
|
1084
|
+
ctx._cstLeaves = s._cstLeaves;
|
|
1085
|
+
ctx._cstChildren = s._cstChildren;
|
|
1086
|
+
ctx._cstRawChildren = s._cstRawChildren;
|
|
1087
|
+
ctx._cstTriviaLog = s._cstTriviaLog;
|
|
1088
|
+
ctx._triviaLog = s._triviaLog;
|
|
1089
|
+
ctx._rootTriviaLog = s._rootTriviaLog;
|
|
1090
|
+
ctx._fields = s._fields;
|
|
1091
|
+
ctx._cstBuf = s._cstBuf;
|
|
1092
|
+
ctx._tolerant = s._tolerant;
|
|
1093
|
+
ctx._sync = s._sync;
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
function orSentinel(a, b) {
|
|
1097
|
+
if (b === void 0) return a;
|
|
1098
|
+
return {
|
|
1099
|
+
_tag: "orSentinel",
|
|
1100
|
+
_meta: { firstSet: { kind: "any" }, canMatchNewline: false, isTrivia: false },
|
|
1101
|
+
_def: { tag: "unknown" },
|
|
1102
|
+
parse(input, pos, ctx) {
|
|
1103
|
+
const ra = a.parse(input, pos, ctx);
|
|
1104
|
+
if (ra.ok) return ra;
|
|
1105
|
+
return b.parse(input, pos, ctx);
|
|
1106
|
+
}
|
|
1107
|
+
};
|
|
1006
1108
|
}
|
|
1007
|
-
function
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1109
|
+
function firstSetSentinel(fs) {
|
|
1110
|
+
if (fs.kind !== "ranges" || fs.ranges.length === 0) return null;
|
|
1111
|
+
const ranges = fs.ranges;
|
|
1112
|
+
return {
|
|
1113
|
+
_tag: "firstSetSentinel",
|
|
1114
|
+
_meta: { firstSet: fs, canMatchNewline: false, isTrivia: false },
|
|
1115
|
+
_def: { tag: "unknown" },
|
|
1116
|
+
parse(input, pos) {
|
|
1117
|
+
const code = pos < input.length ? input.codePointAt(pos) : void 0;
|
|
1118
|
+
if (code !== void 0) {
|
|
1119
|
+
for (const r of ranges) {
|
|
1120
|
+
if (code >= r.lo && code <= r.hi) return { ok: true, value: null, span: { start: pos, end: pos } };
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
return { ok: false, expected: [], span: { start: pos, end: pos } };
|
|
1014
1124
|
}
|
|
1015
|
-
}
|
|
1016
|
-
return false;
|
|
1125
|
+
};
|
|
1017
1126
|
}
|
|
1018
|
-
function
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1127
|
+
function recoverScan(input, from, ctx, sync, expected) {
|
|
1128
|
+
let scanPos = from;
|
|
1129
|
+
while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
|
|
1130
|
+
const span = { start: from, end: scanPos };
|
|
1131
|
+
if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
|
|
1132
|
+
const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
|
|
1133
|
+
ctx._errors?.push(error);
|
|
1134
|
+
return { error, end: scanPos };
|
|
1023
1135
|
}
|
|
1024
|
-
function
|
|
1025
|
-
|
|
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;
|
|
1136
|
+
function matchesAt(sentinel, input, pos, ctx) {
|
|
1137
|
+
return probeAt(sentinel, input, pos, ctx);
|
|
1030
1138
|
}
|
|
1031
|
-
function
|
|
1032
|
-
|
|
1033
|
-
if (def.tag === "transform") {
|
|
1034
|
-
const inner = applyTransforms(def.parser, value, span);
|
|
1035
|
-
return def.fn(inner, span);
|
|
1036
|
-
}
|
|
1037
|
-
return value;
|
|
1139
|
+
function captureError(ctx, error) {
|
|
1140
|
+
if (cstCaptureActive(ctx)) pushCstChild(ctx, error, error);
|
|
1038
1141
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
if (!base || base[0] !== lit) return null;
|
|
1044
|
-
const contCodes = [];
|
|
1045
|
-
for (let code = 1; code < 128; code++) {
|
|
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);
|
|
1142
|
+
|
|
1143
|
+
// src/combinators/expect.ts
|
|
1144
|
+
function deriveExpected(c) {
|
|
1145
|
+
return [...new Set(derive(c, /* @__PURE__ */ new Set()))];
|
|
1052
1146
|
}
|
|
1053
|
-
function
|
|
1054
|
-
|
|
1055
|
-
const
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1147
|
+
function derive(c, seen) {
|
|
1148
|
+
const deriveExpected2 = (p) => derive(p, seen);
|
|
1149
|
+
const def = c._def;
|
|
1150
|
+
switch (def.tag) {
|
|
1151
|
+
case "literal":
|
|
1152
|
+
return [JSON.stringify(def.value)];
|
|
1153
|
+
case "regex":
|
|
1154
|
+
return [`/${def.source}/`];
|
|
1155
|
+
case "keywords":
|
|
1156
|
+
return def.words.map((w) => JSON.stringify(w));
|
|
1157
|
+
case "label":
|
|
1158
|
+
return [def.label];
|
|
1159
|
+
case "choice":
|
|
1160
|
+
return def.parsers.flatMap(deriveExpected2);
|
|
1161
|
+
case "dispatch":
|
|
1162
|
+
return deriveExpected2(def.selector);
|
|
1163
|
+
// Union through the NULLABLE prefix, mirroring `sequenceFirstSet`. A leading
|
|
1164
|
+
// `optional(…)`/`many(…)` can match nothing, so the term after it is equally
|
|
1165
|
+
// able to fail first — deriving from term 0 alone named a token the parse
|
|
1166
|
+
// never actually required. A leading `not(…)` is zero-width and contributes
|
|
1167
|
+
// nothing (its own expectation is about what must NOT be here), but it is
|
|
1168
|
+
// nullable, so keep scanning past it. Stop at the first term that must match.
|
|
1169
|
+
case "sequence": {
|
|
1170
|
+
const out = [];
|
|
1171
|
+
for (const term of def.parsers) {
|
|
1172
|
+
if (!isZeroWidthAssertion(term)) out.push(...deriveExpected2(term));
|
|
1173
|
+
if (!matchesEmpty(term)) break;
|
|
1174
|
+
}
|
|
1175
|
+
return out;
|
|
1063
1176
|
}
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1177
|
+
case "attempt":
|
|
1178
|
+
return deriveExpected2(def.parser);
|
|
1179
|
+
// Delegating wrappers whose first-token failure is their inner parser's — must
|
|
1180
|
+
// pass through so a start-failure (and the first-set-miss fast-path in attempt/
|
|
1181
|
+
// node, which reads this) names the real expected token, not the wrapper tag.
|
|
1182
|
+
case "field":
|
|
1183
|
+
case "withCtx":
|
|
1184
|
+
case "recover":
|
|
1185
|
+
return deriveExpected2(def.parser);
|
|
1186
|
+
case "skip":
|
|
1187
|
+
return deriveExpected2(def.main);
|
|
1188
|
+
case "expect":
|
|
1189
|
+
return def.expected;
|
|
1190
|
+
case "node":
|
|
1191
|
+
case "grammar":
|
|
1192
|
+
case "trivia":
|
|
1193
|
+
case "token":
|
|
1194
|
+
case "leaf":
|
|
1195
|
+
case "optional":
|
|
1196
|
+
case "many":
|
|
1197
|
+
case "oneOrMore":
|
|
1198
|
+
case "transform":
|
|
1199
|
+
case "not":
|
|
1200
|
+
case "peek":
|
|
1201
|
+
return deriveExpected2(def.parser);
|
|
1202
|
+
// A bare routed() can only fail as "there is no routed token here". With a
|
|
1203
|
+
// fallback, THAT is the branch that can fail, so its expectations are the useful
|
|
1204
|
+
// ones — the routed path either succeeds or is not taken.
|
|
1205
|
+
case "routed":
|
|
1206
|
+
return def.fallback === void 0 ? ["routed()"] : deriveExpected2(def.fallback);
|
|
1207
|
+
case "lazy": {
|
|
1208
|
+
const name = c._ruleName;
|
|
1209
|
+
if (seen.has(c)) return name ? [name] : [];
|
|
1210
|
+
seen.add(c);
|
|
1211
|
+
try {
|
|
1212
|
+
return deriveExpected2(def.thunk());
|
|
1213
|
+
} catch {
|
|
1214
|
+
return name ? [name] : [];
|
|
1215
|
+
} finally {
|
|
1216
|
+
seen.delete(c);
|
|
1089
1217
|
}
|
|
1090
1218
|
}
|
|
1219
|
+
default:
|
|
1220
|
+
return [];
|
|
1091
1221
|
}
|
|
1092
|
-
return table;
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
// src/cst/trivia-kinds.ts
|
|
1096
|
-
function unwrapTrivia(p) {
|
|
1097
|
-
let cur = p;
|
|
1098
|
-
while (cur._def.tag === "trivia") cur = cur._def.parser;
|
|
1099
|
-
return cur;
|
|
1100
1222
|
}
|
|
1101
|
-
function
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
|
|
1223
|
+
function expect(combinator, label2) {
|
|
1224
|
+
const expected = label2 !== void 0 ? [label2] : deriveExpected(combinator);
|
|
1225
|
+
const meta = {
|
|
1226
|
+
firstSet: combinator._meta.firstSet,
|
|
1227
|
+
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1228
|
+
isTrivia: false
|
|
1229
|
+
};
|
|
1230
|
+
return {
|
|
1231
|
+
_tag: "expect",
|
|
1232
|
+
_meta: meta,
|
|
1233
|
+
_def: { tag: "expect", parser: combinator, label: label2, expected },
|
|
1234
|
+
parse(input, pos, ctx) {
|
|
1235
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1236
|
+
if (result.ok) return result;
|
|
1237
|
+
const span = { start: pos, end: pos };
|
|
1238
|
+
const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
|
|
1239
|
+
ctx._errors?.push(error);
|
|
1240
|
+
if (ctx._tolerant) captureError(ctx, error);
|
|
1241
|
+
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
1121
1242
|
}
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1243
|
+
};
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
// src/regex/classes.ts
|
|
1247
|
+
var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
1248
|
+
var SPACE_RANGES = [
|
|
1249
|
+
[9, 13],
|
|
1250
|
+
[32, 32],
|
|
1251
|
+
[160, 160],
|
|
1252
|
+
[5760, 5760],
|
|
1253
|
+
[8192, 8202],
|
|
1254
|
+
[8232, 8232],
|
|
1255
|
+
[8233, 8233],
|
|
1256
|
+
[8239, 8239],
|
|
1257
|
+
[8287, 8287],
|
|
1258
|
+
[12288, 12288],
|
|
1259
|
+
[65279, 65279]
|
|
1260
|
+
];
|
|
1261
|
+
function shorthandRanges(ch) {
|
|
1262
|
+
if (ch === "d") return [[48, 57]];
|
|
1263
|
+
if (ch === "s") return SPACE_RANGES;
|
|
1264
|
+
return [[48, 57], [65, 90], [97, 122], [95, 95]];
|
|
1128
1265
|
}
|
|
1129
|
-
function
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1266
|
+
function readUnicodeEscape(body, i) {
|
|
1267
|
+
if (body[i] !== "\\" || body[i + 1] !== "u") return null;
|
|
1268
|
+
const hex = body.slice(i + 2, i + 6);
|
|
1269
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
|
|
1270
|
+
return { cp: Number.parseInt(hex, 16), next: i + 6 };
|
|
1133
1271
|
}
|
|
1134
|
-
function
|
|
1135
|
-
const
|
|
1136
|
-
let
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1272
|
+
function parseClassRanges(body) {
|
|
1273
|
+
const ranges = [];
|
|
1274
|
+
let i = 0;
|
|
1275
|
+
const readAtom = () => {
|
|
1276
|
+
const ch = body[i];
|
|
1277
|
+
if (ch === void 0) return null;
|
|
1278
|
+
if (ch === "\\") {
|
|
1279
|
+
const uni = readUnicodeEscape(body, i);
|
|
1280
|
+
if (uni) {
|
|
1281
|
+
i = uni.next;
|
|
1282
|
+
return { cp: uni.cp };
|
|
1144
1283
|
}
|
|
1284
|
+
const e = body[i + 1];
|
|
1285
|
+
if (e === void 0) return null;
|
|
1286
|
+
i += 2;
|
|
1287
|
+
if (e in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[e] };
|
|
1288
|
+
if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges(e) };
|
|
1289
|
+
if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
|
|
1290
|
+
return { cp: e.codePointAt(0) };
|
|
1145
1291
|
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
}
|
|
1155
|
-
function scanFastWsCommentsChunks(input, cur, wsKind, commentKind) {
|
|
1156
|
-
const chunks = [];
|
|
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 });
|
|
1292
|
+
i += ch.length;
|
|
1293
|
+
return { cp: ch.codePointAt(0) };
|
|
1294
|
+
};
|
|
1295
|
+
while (i < body.length) {
|
|
1296
|
+
const lo = readAtom();
|
|
1297
|
+
if (lo === null) return null;
|
|
1298
|
+
if ("set" in lo) {
|
|
1299
|
+
ranges.push(...lo.set);
|
|
1169
1300
|
continue;
|
|
1170
1301
|
}
|
|
1171
|
-
if (
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
if (
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
continue;
|
|
1179
|
-
}
|
|
1180
|
-
break;
|
|
1302
|
+
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
1303
|
+
i += 1;
|
|
1304
|
+
const hi = readAtom();
|
|
1305
|
+
if (hi === null || "set" in hi) return null;
|
|
1306
|
+
ranges.push([lo.cp, hi.cp]);
|
|
1307
|
+
} else {
|
|
1308
|
+
ranges.push([lo.cp, lo.cp]);
|
|
1181
1309
|
}
|
|
1182
|
-
break;
|
|
1183
1310
|
}
|
|
1184
|
-
return
|
|
1311
|
+
return ranges.length ? ranges : null;
|
|
1185
1312
|
}
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
const commentArm = spec.arms.find((a) => {
|
|
1194
|
-
const src = getCoreRegexDef(a.parser)?.source;
|
|
1195
|
-
return src != null && src.includes("\\*");
|
|
1196
|
-
});
|
|
1197
|
-
if (!wsArm || !commentArm) return null;
|
|
1198
|
-
const { chunks } = scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
|
|
1199
|
-
if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
|
|
1200
|
-
return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
|
|
1313
|
+
|
|
1314
|
+
// src/combinators/trivia-skip.ts
|
|
1315
|
+
var NOOP_COMMIT = () => {
|
|
1316
|
+
};
|
|
1317
|
+
var fastTriviaCache = /* @__PURE__ */ new WeakMap();
|
|
1318
|
+
function needsDeferredTriviaCommit(ctx) {
|
|
1319
|
+
return ctx._triviaLog !== void 0 || ctx._rootTriviaLog !== void 0 || ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0;
|
|
1201
1320
|
}
|
|
1202
|
-
function
|
|
1203
|
-
const
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
}
|
|
1321
|
+
function saveTriviaMark(ctx) {
|
|
1322
|
+
const m = saveCstMark(ctx);
|
|
1323
|
+
return {
|
|
1324
|
+
raw: m.raw,
|
|
1325
|
+
tlog: m.tlog,
|
|
1326
|
+
leaves: m.leaves,
|
|
1327
|
+
fields: m.fields,
|
|
1328
|
+
errors: m.errors,
|
|
1329
|
+
log: ctx._triviaLog ? ctx._triviaLog.length : 0,
|
|
1330
|
+
rootLog: ctx._rootTriviaLog ? ctx._rootTriviaLog.length : 0
|
|
1331
|
+
};
|
|
1213
1332
|
}
|
|
1214
|
-
function
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
const idx = labels.indexOf(name);
|
|
1219
|
-
if (idx >= 0) mask |= 1 << idx;
|
|
1220
|
-
}
|
|
1221
|
-
return mask;
|
|
1333
|
+
function rollbackTrivia(ctx, mark) {
|
|
1334
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
|
|
1335
|
+
if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
|
|
1336
|
+
if (ctx._rootTriviaLog && ctx._rootTriviaLog.length !== mark.rootLog) ctx._rootTriviaLog.length = mark.rootLog;
|
|
1222
1337
|
}
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
}
|
|
1235
|
-
return annotated;
|
|
1338
|
+
function parseTriviaNoCapture(triviaP, input, cur, ctx) {
|
|
1339
|
+
const probeCtx = {
|
|
1340
|
+
trackLines: ctx.trackLines,
|
|
1341
|
+
state: ctx.state,
|
|
1342
|
+
...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
|
|
1343
|
+
...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
|
|
1344
|
+
...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
|
|
1345
|
+
};
|
|
1346
|
+
const result = triviaP.parse(input, cur, probeCtx);
|
|
1347
|
+
ctx._lineScannedTo = probeCtx._lineScannedTo;
|
|
1348
|
+
return result;
|
|
1236
1349
|
}
|
|
1237
|
-
function
|
|
1238
|
-
|
|
1239
|
-
if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
|
|
1240
|
-
return { lineIndex, lineScannedTo: pos };
|
|
1350
|
+
function saveLookaheadMark(ctx) {
|
|
1351
|
+
return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
|
|
1241
1352
|
}
|
|
1242
|
-
function
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
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);
|
|
1283
|
-
}
|
|
1284
|
-
return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
|
|
1353
|
+
function rollbackLookahead(ctx, mark) {
|
|
1354
|
+
rollbackTrivia(ctx, mark);
|
|
1355
|
+
if (ctx._probe) ctx._probe.best = mark.probeBest;
|
|
1356
|
+
}
|
|
1357
|
+
function scanWithLabels(input, cur, ctx) {
|
|
1358
|
+
const triviaP = ctx.trivia;
|
|
1359
|
+
const spec = analyzeLabeledTrivia(triviaP);
|
|
1360
|
+
if (!spec) return { end: cur, commit: NOOP_COMMIT };
|
|
1361
|
+
const log = ctx._triviaLog;
|
|
1362
|
+
const rootLog = ctx._rootTriviaLog;
|
|
1363
|
+
const rootKinds = ctx._rootTriviaKindIndex;
|
|
1364
|
+
const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
|
|
1365
|
+
const mask = ctx._triviaCaptureMask;
|
|
1366
|
+
let fullRows;
|
|
1367
|
+
let rootRows;
|
|
1368
|
+
let cstRows;
|
|
1369
|
+
const visitedEnd = visitLabeledTrivia(input, cur, spec, ctx.state, (start, matchEnd, kindIndex) => {
|
|
1370
|
+
if (log !== void 0) (fullRows ??= []).push(start, matchEnd, kindIndex);
|
|
1371
|
+
const selectedKind = rootLog === void 0 || rootKinds === void 0 || ctx._rootTriviaCapture === false ? void 0 : rootKinds[spec.labels[kindIndex] ?? ""];
|
|
1372
|
+
if (selectedKind !== void 0) (rootRows ??= []).push(start, matchEnd, selectedKind);
|
|
1373
|
+
if (captureTl && (mask === void 0 || (mask & 1 << kindIndex) !== 0)) {
|
|
1374
|
+
(cstRows ??= []).push(start, matchEnd, kindIndex);
|
|
1285
1375
|
}
|
|
1376
|
+
});
|
|
1377
|
+
if (visitedEnd !== void 0) {
|
|
1378
|
+
if (visitedEnd === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1379
|
+
return {
|
|
1380
|
+
end: visitedEnd,
|
|
1381
|
+
commit: () => {
|
|
1382
|
+
if (fullRows !== void 0 && log !== void 0) log.push(...fullRows);
|
|
1383
|
+
if (rootRows !== void 0 && rootLog !== void 0) {
|
|
1384
|
+
for (let i = 0; i < rootRows.length; i += 3) {
|
|
1385
|
+
rootLog.push(cur, visitedEnd, rootRows[i], rootRows[i + 1], rootRows[i + 2]);
|
|
1386
|
+
}
|
|
1387
|
+
}
|
|
1388
|
+
if (cstRows !== void 0) {
|
|
1389
|
+
for (let i = 0; i < cstRows.length; i += 3) {
|
|
1390
|
+
pushCstTriviaEntry(ctx, cstRows[i], cstRows[i + 1], cstRows[i + 2]);
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
};
|
|
1395
|
+
}
|
|
1396
|
+
const { end, chunks } = scanLabeledTriviaChunks(input, cur, spec, ctx.state);
|
|
1397
|
+
if (end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1398
|
+
return {
|
|
1399
|
+
end,
|
|
1400
|
+
commit: () => recordTriviaChunks(ctx, chunks)
|
|
1286
1401
|
};
|
|
1287
1402
|
}
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
case "many":
|
|
1304
|
-
case "oneOrMore":
|
|
1305
|
-
case "optional":
|
|
1306
|
-
case "attempt":
|
|
1307
|
-
case "transform":
|
|
1308
|
-
case "trivia":
|
|
1309
|
-
case "token":
|
|
1310
|
-
case "leaf":
|
|
1311
|
-
case "label":
|
|
1312
|
-
case "field":
|
|
1313
|
-
case "not":
|
|
1314
|
-
case "peek":
|
|
1315
|
-
case "node":
|
|
1316
|
-
case "withCtx":
|
|
1317
|
-
case "recover":
|
|
1318
|
-
case "expect":
|
|
1319
|
-
return [def.parser];
|
|
1320
|
-
case "grammar":
|
|
1321
|
-
return def.triviaParser ? [def.parser, def.triviaParser] : [def.parser];
|
|
1322
|
-
case "sepBy":
|
|
1323
|
-
return [def.parser, def.separator];
|
|
1324
|
-
case "skip":
|
|
1325
|
-
return [def.main, def.skipped];
|
|
1326
|
-
case "scanTo":
|
|
1327
|
-
return [def.sentinel, ...def.skip];
|
|
1328
|
-
case "literal":
|
|
1329
|
-
case "regex":
|
|
1330
|
-
case "keywords":
|
|
1331
|
-
case "routed":
|
|
1332
|
-
case "guard":
|
|
1333
|
-
case "lazy":
|
|
1334
|
-
case "unknown":
|
|
1335
|
-
return [];
|
|
1403
|
+
function skipWithLabels(input, cur, ctx) {
|
|
1404
|
+
const spec = analyzeLabeledTrivia(ctx.trivia);
|
|
1405
|
+
if (spec) return scanLabeledTriviaEnd(input, cur, spec, ctx.state);
|
|
1406
|
+
const tr = parseTriviaNoCapture(ctx.trivia, input, cur, ctx);
|
|
1407
|
+
return tr.ok && tr.span.end > cur ? tr.span.end : cur;
|
|
1408
|
+
}
|
|
1409
|
+
function advanceTrivia(input, cur, ctx) {
|
|
1410
|
+
const triviaP = ctx.trivia;
|
|
1411
|
+
if (!triviaP) return cur;
|
|
1412
|
+
if (!ctx.trackLines) {
|
|
1413
|
+
const fast2 = fastTriviaScanner(triviaP);
|
|
1414
|
+
if (fast2) return fast2(input, cur);
|
|
1415
|
+
if (ctx.triviaKindLabels) return skipWithLabels(input, cur, ctx);
|
|
1416
|
+
const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1417
|
+
return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
|
|
1336
1418
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
if (
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
return;
|
|
1419
|
+
const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
|
|
1420
|
+
const fast = fastTriviaScanner(triviaP);
|
|
1421
|
+
if (fast) {
|
|
1422
|
+
const end = fast(input, cur);
|
|
1423
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1424
|
+
return end;
|
|
1344
1425
|
}
|
|
1345
|
-
if (
|
|
1346
|
-
|
|
1347
|
-
if (
|
|
1426
|
+
if (ctx.triviaKindLabels) {
|
|
1427
|
+
const end = skipWithLabels(input, cur, ctx);
|
|
1428
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1429
|
+
return end;
|
|
1348
1430
|
}
|
|
1431
|
+
const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
|
|
1432
|
+
return tr.ok && tr.span.end > cur ? tr.span.end : cur;
|
|
1349
1433
|
}
|
|
1350
|
-
function
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
const
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
}
|
|
1434
|
+
function scanTrivia(input, cur, ctx) {
|
|
1435
|
+
const triviaP = ctx.trivia;
|
|
1436
|
+
if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
|
|
1437
|
+
const log = ctx._triviaLog;
|
|
1438
|
+
const rootLog = ctx._rootTriviaLog;
|
|
1439
|
+
const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
|
|
1440
|
+
if (!ctx.trackLines) {
|
|
1441
|
+
const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
|
|
1442
|
+
if (fast2 && log === void 0 && !captureTl) {
|
|
1443
|
+
return { end: fast2(input, cur), commit: NOOP_COMMIT };
|
|
1360
1444
|
}
|
|
1361
|
-
|
|
1445
|
+
if (ctx.triviaKindLabels && (log !== void 0 || rootLog !== void 0 || captureTl)) {
|
|
1446
|
+
return scanWithLabels(input, cur, ctx);
|
|
1447
|
+
}
|
|
1448
|
+
if (ctx.triviaKindLabels) return { end: skipWithLabels(input, cur, ctx), commit: NOOP_COMMIT };
|
|
1449
|
+
if (log !== void 0 || rootLog !== void 0 || captureTl) {
|
|
1450
|
+
const tr3 = triviaP.parse(input, cur, {
|
|
1451
|
+
trackLines: log !== void 0 ? false : ctx.trackLines,
|
|
1452
|
+
state: ctx.state
|
|
1453
|
+
});
|
|
1454
|
+
if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1455
|
+
const end = tr3.span.end;
|
|
1456
|
+
return {
|
|
1457
|
+
end,
|
|
1458
|
+
commit: () => {
|
|
1459
|
+
pushTriviaLogEntry(ctx, cur, end);
|
|
1460
|
+
if (captureTl) pushCstTriviaEntry(ctx, cur, end);
|
|
1461
|
+
}
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1465
|
+
return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
|
|
1362
1466
|
}
|
|
1363
|
-
|
|
1364
|
-
|
|
1467
|
+
const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
|
|
1468
|
+
const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
|
|
1469
|
+
if (fast && log === void 0 && !captureTl) {
|
|
1470
|
+
const end = fast(input, cur);
|
|
1471
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1472
|
+
return { end, commit: NOOP_COMMIT };
|
|
1473
|
+
}
|
|
1474
|
+
if (ctx.triviaKindLabels && (log !== void 0 || rootLog !== void 0 || captureTl)) {
|
|
1475
|
+
const scan = scanWithLabels(input, cur, ctx);
|
|
1476
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
|
|
1477
|
+
return scan;
|
|
1478
|
+
}
|
|
1479
|
+
if (ctx.triviaKindLabels) {
|
|
1480
|
+
const end = skipWithLabels(input, cur, ctx);
|
|
1481
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1482
|
+
return { end, commit: NOOP_COMMIT };
|
|
1483
|
+
}
|
|
1484
|
+
if (log !== void 0 || rootLog !== void 0 || captureTl) {
|
|
1485
|
+
const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
|
|
1486
|
+
if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1487
|
+
const end = tr2.span.end;
|
|
1488
|
+
return {
|
|
1489
|
+
end,
|
|
1490
|
+
commit: () => {
|
|
1491
|
+
pushTriviaLogEntry(ctx, cur, end);
|
|
1492
|
+
if (captureTl) pushCstTriviaEntry(ctx, cur, end);
|
|
1493
|
+
}
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1496
|
+
const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
|
|
1497
|
+
return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
|
|
1365
1498
|
}
|
|
1366
|
-
function
|
|
1367
|
-
|
|
1368
|
-
const
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1499
|
+
function consumeTrivia(input, cur, ctx) {
|
|
1500
|
+
if (!needsDeferredTriviaCommit(ctx)) return advanceTrivia(input, cur, ctx);
|
|
1501
|
+
const scan = scanTrivia(input, cur, ctx);
|
|
1502
|
+
scan.commit();
|
|
1503
|
+
return scan.end;
|
|
1504
|
+
}
|
|
1505
|
+
function fastTriviaScanner(trivia2) {
|
|
1506
|
+
const cached = fastTriviaCache.get(trivia2);
|
|
1507
|
+
if (cached !== void 0) return cached;
|
|
1508
|
+
const scanner = buildFastTriviaScanner(trivia2);
|
|
1509
|
+
fastTriviaCache.set(trivia2, scanner);
|
|
1510
|
+
return scanner;
|
|
1511
|
+
}
|
|
1512
|
+
function buildFastTriviaScanner(trivia2) {
|
|
1513
|
+
const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
|
|
1514
|
+
const direct = regexTriviaScanner(core);
|
|
1515
|
+
if (direct) return direct;
|
|
1516
|
+
const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
|
|
1517
|
+
if (!repeat) return null;
|
|
1518
|
+
const one = regexTriviaScanner(repeat);
|
|
1519
|
+
if (one) return loopScanner([one]);
|
|
1520
|
+
if (repeat._def.tag !== "choice") return null;
|
|
1521
|
+
const arms = repeat._def.parsers.map(regexTriviaScanner);
|
|
1522
|
+
if (arms.some((s) => s === null)) return null;
|
|
1523
|
+
return loopScanner(arms);
|
|
1524
|
+
}
|
|
1525
|
+
function loopScanner(arms) {
|
|
1526
|
+
return (input, cur) => {
|
|
1527
|
+
let pos = cur;
|
|
1528
|
+
scan: while (pos < input.length) {
|
|
1529
|
+
for (const arm of arms) {
|
|
1530
|
+
const end = arm(input, pos);
|
|
1531
|
+
if (end > pos) {
|
|
1532
|
+
pos = end;
|
|
1533
|
+
continue scan;
|
|
1534
|
+
}
|
|
1375
1535
|
}
|
|
1376
|
-
|
|
1536
|
+
break;
|
|
1377
1537
|
}
|
|
1378
|
-
|
|
1538
|
+
return pos;
|
|
1539
|
+
};
|
|
1540
|
+
}
|
|
1541
|
+
function regexTriviaScanner(parser2) {
|
|
1542
|
+
if (parser2._def.tag !== "regex" || parser2._def.flags) return null;
|
|
1543
|
+
const source = parser2._def.source;
|
|
1544
|
+
return classRunSource(source) ?? altStarSource(source);
|
|
1545
|
+
}
|
|
1546
|
+
function inRanges(cp, ranges) {
|
|
1547
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
1548
|
+
const r = ranges[i];
|
|
1549
|
+
if (cp >= r[0] && cp <= r[1]) return true;
|
|
1379
1550
|
}
|
|
1380
|
-
return
|
|
1551
|
+
return false;
|
|
1381
1552
|
}
|
|
1382
|
-
function
|
|
1383
|
-
|
|
1384
|
-
return
|
|
1553
|
+
function classScanner(classBody) {
|
|
1554
|
+
const ranges = parseClassRanges(classBody);
|
|
1555
|
+
if (!ranges) return null;
|
|
1556
|
+
return (input, cur) => {
|
|
1557
|
+
let pos = cur;
|
|
1558
|
+
while (pos < input.length && inRanges(input.charCodeAt(pos), ranges)) pos++;
|
|
1559
|
+
return pos;
|
|
1560
|
+
};
|
|
1385
1561
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1562
|
+
function untilLineBreakScanner(leaderCode) {
|
|
1563
|
+
return (input, cur) => {
|
|
1564
|
+
if (input.charCodeAt(cur) !== leaderCode) return cur;
|
|
1565
|
+
let pos = cur + 1;
|
|
1566
|
+
while (pos < input.length) {
|
|
1567
|
+
const cc = input.charCodeAt(pos);
|
|
1568
|
+
if (cc === 10 || cc === 13) break;
|
|
1569
|
+
pos++;
|
|
1570
|
+
}
|
|
1571
|
+
return pos;
|
|
1572
|
+
};
|
|
1393
1573
|
}
|
|
1394
|
-
function
|
|
1395
|
-
|
|
1574
|
+
function classRunSource(source) {
|
|
1575
|
+
const m = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]$/.exec(source);
|
|
1576
|
+
return m ? classScanner(m[1]) : null;
|
|
1396
1577
|
}
|
|
1397
|
-
function
|
|
1398
|
-
|
|
1578
|
+
function classifyTriviaArm(arm) {
|
|
1579
|
+
const cls = /^\[([^\]^](?:[^\]]|\\.)*)\][*+]?$/.exec(arm);
|
|
1580
|
+
if (cls) {
|
|
1581
|
+
const ranges = parseClassRanges(cls[1]);
|
|
1582
|
+
return ranges ? { kind: "class", ranges } : null;
|
|
1583
|
+
}
|
|
1584
|
+
const lc = /^(\\?.)\[\^\\n\\r\]\*$/.exec(arm);
|
|
1585
|
+
if (lc) {
|
|
1586
|
+
const marker = lc[1];
|
|
1587
|
+
return { kind: "untilLineBreak", code: (marker.length === 2 ? marker[1] : marker[0]).charCodeAt(0) };
|
|
1588
|
+
}
|
|
1589
|
+
return null;
|
|
1399
1590
|
}
|
|
1400
|
-
function
|
|
1401
|
-
|
|
1402
|
-
|
|
1591
|
+
function armScanner(arm) {
|
|
1592
|
+
if (arm.kind === "untilLineBreak") return untilLineBreakScanner(arm.code);
|
|
1593
|
+
const ranges = arm.ranges;
|
|
1594
|
+
return (input, cur) => {
|
|
1595
|
+
let pos = cur;
|
|
1596
|
+
while (pos < input.length && inRanges(input.charCodeAt(pos), ranges)) pos++;
|
|
1597
|
+
return pos;
|
|
1598
|
+
};
|
|
1403
1599
|
}
|
|
1404
|
-
function
|
|
1405
|
-
const
|
|
1406
|
-
const
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
const
|
|
1412
|
-
if (
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
record[key] = r;
|
|
1600
|
+
function fusedTriviaScanner(ranges, leaders) {
|
|
1601
|
+
const c0 = leaders[0];
|
|
1602
|
+
const single = leaders.length === 1;
|
|
1603
|
+
return (input, cur) => {
|
|
1604
|
+
let pos = cur;
|
|
1605
|
+
const len = input.length;
|
|
1606
|
+
for (; ; ) {
|
|
1607
|
+
const c = input.charCodeAt(pos);
|
|
1608
|
+
if (pos < len && inRanges(c, ranges)) {
|
|
1609
|
+
pos++;
|
|
1610
|
+
continue;
|
|
1416
1611
|
}
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
if (isDefinableRef(placeholder)) {
|
|
1428
|
-
if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
|
|
1429
|
-
placeholder.define(parser2);
|
|
1430
|
-
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
1431
|
-
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
1432
|
-
} else if (isNamedRuleRefForAnotherRule(parser2, key)) {
|
|
1433
|
-
const alias = ref();
|
|
1434
|
-
tagRule(alias, key);
|
|
1435
|
-
alias.define(parser2);
|
|
1436
|
-
alias._meta.firstSet = parser2._meta.firstSet;
|
|
1437
|
-
alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
1438
|
-
cache[key] = alias;
|
|
1439
|
-
} else {
|
|
1440
|
-
tagRule(parser2, key);
|
|
1441
|
-
cache[key] = parser2;
|
|
1612
|
+
if (single ? c === c0 : leaders.includes(c)) {
|
|
1613
|
+
pos++;
|
|
1614
|
+
while (pos < len) {
|
|
1615
|
+
const cc = input.charCodeAt(pos);
|
|
1616
|
+
if (cc === 10 || cc === 13) break;
|
|
1617
|
+
pos++;
|
|
1618
|
+
}
|
|
1619
|
+
continue;
|
|
1620
|
+
}
|
|
1621
|
+
break;
|
|
1442
1622
|
}
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1623
|
+
return pos;
|
|
1624
|
+
};
|
|
1625
|
+
}
|
|
1626
|
+
function splitTopLevelAlts(body) {
|
|
1627
|
+
const arms = [];
|
|
1628
|
+
let inClass = false;
|
|
1629
|
+
let start = 0;
|
|
1630
|
+
for (let i = 0; i < body.length; i++) {
|
|
1631
|
+
const c = body[i];
|
|
1632
|
+
if (c === "\\") {
|
|
1633
|
+
i++;
|
|
1634
|
+
continue;
|
|
1448
1635
|
}
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
const rule = cache[key];
|
|
1453
|
-
if (rule && !rule._meta.isTrivia) rule._meta.grammarScanSkip = options.scanSkip;
|
|
1636
|
+
if (inClass) {
|
|
1637
|
+
if (c === "]") inClass = false;
|
|
1638
|
+
continue;
|
|
1454
1639
|
}
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1640
|
+
if (c === "[") inClass = true;
|
|
1641
|
+
else if (c === "(") return null;
|
|
1642
|
+
else if (c === "|") {
|
|
1643
|
+
arms.push(body.slice(start, i));
|
|
1644
|
+
start = i + 1;
|
|
1460
1645
|
}
|
|
1461
1646
|
}
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
}
|
|
1647
|
+
arms.push(body.slice(start));
|
|
1648
|
+
return arms;
|
|
1649
|
+
}
|
|
1650
|
+
function altStarSource(source) {
|
|
1651
|
+
const m = /^\(\?:(.*)\)[*+]$/.exec(source);
|
|
1652
|
+
if (!m) return null;
|
|
1653
|
+
const armSrcs = splitTopLevelAlts(m[1]);
|
|
1654
|
+
if (!armSrcs || armSrcs.length < 2) return null;
|
|
1655
|
+
const arms = [];
|
|
1656
|
+
for (const src of armSrcs) {
|
|
1657
|
+
const arm = classifyTriviaArm(src);
|
|
1658
|
+
if (!arm) return null;
|
|
1659
|
+
arms.push(arm);
|
|
1476
1660
|
}
|
|
1477
|
-
|
|
1478
|
-
|
|
1661
|
+
const ranges = [];
|
|
1662
|
+
const leaders = [];
|
|
1663
|
+
for (const arm of arms) {
|
|
1664
|
+
if (arm.kind === "class") ranges.push(...arm.ranges);
|
|
1665
|
+
else leaders.push(arm.code);
|
|
1479
1666
|
}
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
enumerable: false,
|
|
1483
|
-
configurable: true
|
|
1484
|
-
});
|
|
1485
|
-
attachGrammarReflection(cache, collectGrammarReflection(Object.keys(definitions).map((key) => [key, cache[key]])));
|
|
1486
|
-
return cache;
|
|
1487
|
-
}
|
|
1488
|
-
|
|
1489
|
-
// src/analysis/duplication.ts
|
|
1490
|
-
var WORD_RE_SRC = "-?[A-Za-z][A-Za-z0-9_-]*";
|
|
1491
|
-
var WORDS_RE = new RegExp(`^${WORD_RE_SRC}(?:\\|${WORD_RE_SRC})*$`);
|
|
1492
|
-
|
|
1493
|
-
// src/combinators/probe.ts
|
|
1494
|
-
function failAt(ctx, expected, pos) {
|
|
1495
|
-
const r = { ok: false, expected, span: { start: pos, end: pos } };
|
|
1496
|
-
const probe = ctx._probe;
|
|
1497
|
-
if (probe !== void 0 && pos <= probe.offset) {
|
|
1498
|
-
const best = probe.best;
|
|
1499
|
-
if (best === null || pos > best.span.start) {
|
|
1500
|
-
probe.best = r;
|
|
1501
|
-
} else if (pos === best.span.start) {
|
|
1502
|
-
probe.best = { ...best, expected: [...best.expected, ...expected] };
|
|
1503
|
-
}
|
|
1667
|
+
if (leaders.some((code) => inRanges(code, ranges))) {
|
|
1668
|
+
return loopScanner(arms.map(armScanner));
|
|
1504
1669
|
}
|
|
1505
|
-
return
|
|
1670
|
+
if (leaders.length === 0) return armScanner({ kind: "class", ranges });
|
|
1671
|
+
return fusedTriviaScanner(ranges, leaders);
|
|
1506
1672
|
}
|
|
1507
1673
|
|
|
1508
|
-
// src/combinators/
|
|
1509
|
-
function
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
if (ca !== cb) return false;
|
|
1517
|
-
}
|
|
1518
|
-
return true;
|
|
1519
|
-
}
|
|
1520
|
-
function literal(value, opts = {}) {
|
|
1521
|
-
const caseInsensitive = opts.caseInsensitive ?? false;
|
|
1522
|
-
const firstSet = value.length > 0 ? fromChar(value.codePointAt(0)) : empty();
|
|
1674
|
+
// src/combinators/choice.ts
|
|
1675
|
+
function choice(...args) {
|
|
1676
|
+
const parsers = args.map((a) => "gate" in a ? a.combinator : a);
|
|
1677
|
+
const gates = args.map((a) => "gate" in a ? a.gate : null);
|
|
1678
|
+
const hasGates = gates.some((g) => g !== null);
|
|
1679
|
+
const disjoint = areDisjoint(parsers.map((p) => p._meta.firstSet)) && parsers.every((p) => !matchesEmpty(p));
|
|
1680
|
+
let combined = { kind: "empty" };
|
|
1681
|
+
for (const p of parsers) combined = union(combined, p._meta.firstSet);
|
|
1523
1682
|
const meta = {
|
|
1524
|
-
firstSet,
|
|
1525
|
-
canMatchNewline:
|
|
1526
|
-
isTrivia: false
|
|
1683
|
+
firstSet: combined,
|
|
1684
|
+
canMatchNewline: parsers.some((p) => p._meta.canMatchNewline),
|
|
1685
|
+
isTrivia: false,
|
|
1686
|
+
disjoint
|
|
1527
1687
|
};
|
|
1528
|
-
const
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
const expected = [JSON.stringify(value)];
|
|
1540
|
-
const parse = !caseInsensitive && value.length === 1 ? (() => {
|
|
1541
|
-
const code = value.charCodeAt(0);
|
|
1542
|
-
return function parse2(input, pos, ctx) {
|
|
1543
|
-
if (input.charCodeAt(pos) === code) {
|
|
1544
|
-
const span = { start: pos, end: pos + 1 };
|
|
1545
|
-
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
|
|
1546
|
-
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
|
|
1547
|
-
return { ok: true, value, span };
|
|
1548
|
-
}
|
|
1549
|
-
return failAt(ctx, expected, pos);
|
|
1550
|
-
};
|
|
1551
|
-
})() : function parse2(input, pos, ctx) {
|
|
1552
|
-
const end = pos + value.length;
|
|
1553
|
-
if (end > input.length) {
|
|
1554
|
-
return failAt(ctx, expected, pos);
|
|
1555
|
-
}
|
|
1556
|
-
const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
|
|
1557
|
-
if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
|
|
1558
|
-
const span = { start: pos, end };
|
|
1559
|
-
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
|
|
1560
|
-
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
|
|
1561
|
-
return { ok: true, value: matchedValue, span };
|
|
1688
|
+
const strategy = disjoint || hasGates ? null : detectStrategy(parsers);
|
|
1689
|
+
const autoNot = !disjoint && !hasGates && (strategy?.tag === "firstMatch" || strategy?.tag === "sharedPrefix") ? computeAutoNot(parsers) : parsers.map(() => null);
|
|
1690
|
+
let greedyLitMap = null;
|
|
1691
|
+
let sortedParsers = null;
|
|
1692
|
+
const asciiDispatch = disjoint ? buildAsciiDispatch(parsers) : null;
|
|
1693
|
+
if (strategy?.tag === "greedyClassify") {
|
|
1694
|
+
greedyLitMap = /* @__PURE__ */ new Map();
|
|
1695
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1696
|
+
if (i === strategy.superIndex) continue;
|
|
1697
|
+
const litVal = getCoreLiteralValue(parsers[i]);
|
|
1698
|
+
if (litVal !== null) greedyLitMap.set(litVal, i);
|
|
1562
1699
|
}
|
|
1563
|
-
|
|
1564
|
-
|
|
1700
|
+
} else if (strategy?.tag === "literalsLongestFirst") {
|
|
1701
|
+
sortedParsers = strategy.sortedIndices.map((i) => parsers[i]);
|
|
1702
|
+
}
|
|
1565
1703
|
return {
|
|
1566
|
-
_tag: "
|
|
1704
|
+
_tag: "choice",
|
|
1567
1705
|
_meta: meta,
|
|
1568
|
-
_def: {
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
}
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
i = uni.next;
|
|
1609
|
-
return { cp: uni.cp };
|
|
1706
|
+
_def: {
|
|
1707
|
+
tag: "choice",
|
|
1708
|
+
parsers,
|
|
1709
|
+
gates,
|
|
1710
|
+
disjoint,
|
|
1711
|
+
strategy: strategy ?? { tag: "firstMatch" },
|
|
1712
|
+
autoNot
|
|
1713
|
+
},
|
|
1714
|
+
parse(input, pos, ctx) {
|
|
1715
|
+
const expected = [];
|
|
1716
|
+
if (disjoint && pos < input.length) {
|
|
1717
|
+
const code = input.codePointAt(pos);
|
|
1718
|
+
let idx = code < 128 ? asciiDispatch[code] : -1;
|
|
1719
|
+
if (idx < 0) {
|
|
1720
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1721
|
+
if (inFirstSet(code, parsers[i]._meta.firstSet)) {
|
|
1722
|
+
idx = i;
|
|
1723
|
+
break;
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
if (idx >= 0) {
|
|
1728
|
+
const gate = gates[idx];
|
|
1729
|
+
if (gate && !gate(ctx.state)) {
|
|
1730
|
+
return { ok: false, expected: deriveExpected(parsers[idx]), span: { start: pos, end: pos } };
|
|
1731
|
+
}
|
|
1732
|
+
const result = parsers[idx].parse(input, pos, ctx);
|
|
1733
|
+
if (result.ok) return result;
|
|
1734
|
+
expected.push(...result.expected);
|
|
1735
|
+
if (result.committed) return { ok: false, expected, span: { start: pos, end: pos }, committed: true };
|
|
1736
|
+
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1737
|
+
}
|
|
1738
|
+
return {
|
|
1739
|
+
ok: false,
|
|
1740
|
+
expected: parsers.flatMap((p) => {
|
|
1741
|
+
const r = p.parse(input, pos, ctx);
|
|
1742
|
+
return r.ok ? [] : r.expected;
|
|
1743
|
+
}),
|
|
1744
|
+
span: { start: pos, end: pos }
|
|
1745
|
+
};
|
|
1610
1746
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1747
|
+
if (strategy?.tag === "greedyClassify") {
|
|
1748
|
+
const superResult = parsers[strategy.superIndex].parse(input, pos, ctx);
|
|
1749
|
+
if (!superResult.ok) return superResult;
|
|
1750
|
+
const end = superResult.span.end;
|
|
1751
|
+
const litIdx = greedyLitMap.get(input.slice(pos, end));
|
|
1752
|
+
if (litIdx !== void 0) {
|
|
1753
|
+
const litVal = getCoreLiteralValue(parsers[litIdx]);
|
|
1754
|
+
const value = applyTransforms(parsers[litIdx], litVal, { start: pos, end });
|
|
1755
|
+
return { ok: true, value, span: { start: pos, end } };
|
|
1756
|
+
}
|
|
1757
|
+
return superResult;
|
|
1758
|
+
}
|
|
1759
|
+
if (strategy?.tag === "literalsLongestFirst") {
|
|
1760
|
+
for (const p of sortedParsers) {
|
|
1761
|
+
const r = p.parse(input, pos, ctx);
|
|
1762
|
+
if (r.ok) return r;
|
|
1763
|
+
expected.push(...r.expected);
|
|
1764
|
+
}
|
|
1765
|
+
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1766
|
+
}
|
|
1767
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1768
|
+
if (gates[i] && !gates[i](ctx.state)) continue;
|
|
1769
|
+
const mark = saveTriviaMark(ctx);
|
|
1770
|
+
const result = parsers[i].parse(input, pos, ctx);
|
|
1771
|
+
if (!result.ok) {
|
|
1772
|
+
rollbackTrivia(ctx, mark);
|
|
1773
|
+
expected.push(...result.expected);
|
|
1774
|
+
if (result.committed) return { ok: false, expected, span: result.span, committed: true };
|
|
1775
|
+
continue;
|
|
1776
|
+
}
|
|
1777
|
+
const checks = autoNot[i];
|
|
1778
|
+
if (checks && autoNotFires(input, result.span.end, checks)) {
|
|
1779
|
+
rollbackTrivia(ctx, mark);
|
|
1780
|
+
continue;
|
|
1781
|
+
}
|
|
1782
|
+
return result;
|
|
1783
|
+
}
|
|
1784
|
+
return { ok: false, expected, span: { start: pos, end: pos } };
|
|
1618
1785
|
}
|
|
1619
|
-
i += ch.length;
|
|
1620
|
-
return { cp: ch.codePointAt(0) };
|
|
1621
1786
|
};
|
|
1622
|
-
while (i < body.length) {
|
|
1623
|
-
const lo = readAtom();
|
|
1624
|
-
if (lo === null) return null;
|
|
1625
|
-
if ("set" in lo) {
|
|
1626
|
-
ranges.push(...lo.set);
|
|
1627
|
-
continue;
|
|
1628
|
-
}
|
|
1629
|
-
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
1630
|
-
i += 1;
|
|
1631
|
-
const hi = readAtom();
|
|
1632
|
-
if (hi === null || "set" in hi) return null;
|
|
1633
|
-
ranges.push([lo.cp, hi.cp]);
|
|
1634
|
-
} else {
|
|
1635
|
-
ranges.push([lo.cp, lo.cp]);
|
|
1636
|
-
}
|
|
1637
|
-
}
|
|
1638
|
-
return ranges.length ? ranges : null;
|
|
1639
1787
|
}
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
for (let i = 0; i < ranges.length; i++) {
|
|
1647
|
-
const [lo, hi] = ranges[i];
|
|
1648
|
-
if (cp >= lo && cp <= hi) return true;
|
|
1788
|
+
function detectStrategy(parsers) {
|
|
1789
|
+
const regexIndices = [];
|
|
1790
|
+
const literalIndices = [];
|
|
1791
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1792
|
+
if (getCoreRegexDef(parsers[i]) !== null) regexIndices.push(i);
|
|
1793
|
+
else if (getCoreLiteralValue(parsers[i]) !== null) literalIndices.push(i);
|
|
1649
1794
|
}
|
|
1650
|
-
|
|
1795
|
+
if (regexIndices.length === 1 && literalIndices.length === parsers.length - 1 && literalIndices.length > 0) {
|
|
1796
|
+
const superIndex = regexIndices[0];
|
|
1797
|
+
const regexDef = getCoreRegexDef(parsers[superIndex]);
|
|
1798
|
+
const flags = "y" + regexDef.flags.replace(/[gy]/g, "");
|
|
1799
|
+
const re = new RegExp(regexDef.source, flags);
|
|
1800
|
+
const allSubsumed = literalIndices.every((i) => {
|
|
1801
|
+
const litVal = getCoreLiteralValue(parsers[i]);
|
|
1802
|
+
re.lastIndex = 0;
|
|
1803
|
+
const m = re.exec(litVal);
|
|
1804
|
+
return m !== null && m[0] === litVal;
|
|
1805
|
+
});
|
|
1806
|
+
if (allSubsumed) return { tag: "greedyClassify", superIndex };
|
|
1807
|
+
}
|
|
1808
|
+
if (parsers.length === literalIndices.length) {
|
|
1809
|
+
const sortedIndices = [...literalIndices].sort(
|
|
1810
|
+
(a, b) => getCoreLiteralValue(parsers[b]).length - getCoreLiteralValue(parsers[a]).length
|
|
1811
|
+
);
|
|
1812
|
+
return { tag: "literalsLongestFirst", sortedIndices };
|
|
1813
|
+
}
|
|
1814
|
+
const shared = detectSharedPrefix(parsers);
|
|
1815
|
+
if (shared !== null) return shared;
|
|
1816
|
+
return { tag: "firstMatch" };
|
|
1651
1817
|
}
|
|
1652
|
-
function
|
|
1653
|
-
|
|
1654
|
-
|
|
1818
|
+
function bareLeadingTermKey(term) {
|
|
1819
|
+
const d = term._def;
|
|
1820
|
+
if (d.tag === "literal" && !d.caseInsensitive) return `L:${d.value}`;
|
|
1821
|
+
if (d.tag === "regex") return `R:${JSON.stringify([d.source, d.flags])}`;
|
|
1822
|
+
return null;
|
|
1655
1823
|
}
|
|
1656
|
-
function
|
|
1657
|
-
if (
|
|
1658
|
-
let
|
|
1659
|
-
let
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
if (
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
quant = source.slice(2);
|
|
1824
|
+
function detectSharedPrefix(parsers) {
|
|
1825
|
+
if (parsers.length < 2) return null;
|
|
1826
|
+
let key = null;
|
|
1827
|
+
let prefix = null;
|
|
1828
|
+
const members = [];
|
|
1829
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1830
|
+
const term0 = leadingTermOfArm(parsers[i]);
|
|
1831
|
+
if (term0 === null) return null;
|
|
1832
|
+
const k = bareLeadingTermKey(term0);
|
|
1833
|
+
if (k === null) return null;
|
|
1834
|
+
if (key === null) {
|
|
1835
|
+
key = k;
|
|
1836
|
+
prefix = term0;
|
|
1837
|
+
} else if (k !== key) return null;
|
|
1838
|
+
members.push(i);
|
|
1672
1839
|
}
|
|
1673
|
-
if (
|
|
1674
|
-
|
|
1675
|
-
return (input, pos) => {
|
|
1676
|
-
let end = pos;
|
|
1677
|
-
while (end < input.length && inRanges(input.charCodeAt(end), ranges)) {
|
|
1678
|
-
end++;
|
|
1679
|
-
if (end - pos >= SCAN_BAIL_AT) return void 0;
|
|
1680
|
-
}
|
|
1681
|
-
return minOne && end === pos ? null : end;
|
|
1682
|
-
};
|
|
1840
|
+
if (prefix === null || members.length < 2) return null;
|
|
1841
|
+
return { tag: "sharedPrefix", prefix, members };
|
|
1683
1842
|
}
|
|
1684
|
-
function
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
add(uLo + 32, uHi + 32);
|
|
1693
|
-
const lLo = Math.max(r.lo, 97), lHi = Math.min(r.hi, 122);
|
|
1694
|
-
add(lLo - 32, lHi - 32);
|
|
1695
|
-
}
|
|
1696
|
-
ranges.sort((a, b) => a.lo - b.lo);
|
|
1697
|
-
const merged = [];
|
|
1698
|
-
for (const r of ranges) {
|
|
1699
|
-
const last = merged[merged.length - 1];
|
|
1700
|
-
if (last && r.lo <= last.hi + 1) last.hi = Math.max(last.hi, r.hi);
|
|
1701
|
-
else merged.push({ lo: r.lo, hi: r.hi });
|
|
1843
|
+
function leadingTermOfArm(arm) {
|
|
1844
|
+
let d = arm._def;
|
|
1845
|
+
for (; ; ) {
|
|
1846
|
+
if (d.tag === "node" || d.tag === "grammar" || d.tag === "transform" || d.tag === "label") {
|
|
1847
|
+
d = d.parser._def;
|
|
1848
|
+
continue;
|
|
1849
|
+
}
|
|
1850
|
+
break;
|
|
1702
1851
|
}
|
|
1703
|
-
|
|
1852
|
+
if (d.tag !== "sequence" || d.parsers.length < 2) return null;
|
|
1853
|
+
return d.parsers[0];
|
|
1704
1854
|
}
|
|
1705
|
-
function
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
_meta: meta,
|
|
1717
|
-
_def: { tag: "regex", source, flags: resolvedFlags },
|
|
1718
|
-
parse(input, pos, ctx) {
|
|
1719
|
-
const scanEnd = scan?.(input, pos);
|
|
1720
|
-
if (scanEnd !== void 0) {
|
|
1721
|
-
if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
|
|
1722
|
-
const value = input.slice(pos, scanEnd);
|
|
1723
|
-
const span2 = { start: pos, end: scanEnd };
|
|
1724
|
-
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, scanEnd);
|
|
1725
|
-
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span: span2 });
|
|
1726
|
-
return { ok: true, value, span: span2 };
|
|
1855
|
+
function computeAutoNot(parsers) {
|
|
1856
|
+
return parsers.map((p, i) => {
|
|
1857
|
+
const litVal = getCoreLiteralValue(p);
|
|
1858
|
+
if (litVal === null) return null;
|
|
1859
|
+
const checks = [];
|
|
1860
|
+
for (let j2 = i + 1; j2 < parsers.length; j2++) {
|
|
1861
|
+
const other = parsers[j2];
|
|
1862
|
+
const otherLit = getCoreLiteralValue(other);
|
|
1863
|
+
if (otherLit !== null && otherLit.startsWith(litVal) && otherLit.length > litVal.length) {
|
|
1864
|
+
checks.push({ kind: "startsWith", value: otherLit.slice(litVal.length) });
|
|
1865
|
+
continue;
|
|
1727
1866
|
}
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1867
|
+
const regexDef = getCoreRegexDef(other);
|
|
1868
|
+
if (regexDef !== null) {
|
|
1869
|
+
const contSet = continuationFirstSet(litVal, regexDef.source, regexDef.flags);
|
|
1870
|
+
if (contSet !== null) checks.push({ kind: "firstSet", set: contSet });
|
|
1732
1871
|
}
|
|
1733
|
-
const span = { start: pos, end: pos + m[0].length };
|
|
1734
|
-
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
|
|
1735
|
-
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: m[0], span });
|
|
1736
|
-
return { ok: true, value: m[0], span };
|
|
1737
1872
|
}
|
|
1738
|
-
|
|
1873
|
+
return checks.length > 0 ? checks : null;
|
|
1874
|
+
});
|
|
1739
1875
|
}
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1876
|
+
function autoNotFires(input, end, checks) {
|
|
1877
|
+
for (const check of checks) {
|
|
1878
|
+
if (check.kind === "firstSet") {
|
|
1879
|
+
const code = end < input.length ? input.codePointAt(end) ?? -1 : -1;
|
|
1880
|
+
if (inFirstSet(code, check.set)) return true;
|
|
1881
|
+
} else {
|
|
1882
|
+
if (input.startsWith(check.value, end)) return true;
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
return false;
|
|
1747
1886
|
}
|
|
1748
|
-
function
|
|
1749
|
-
const
|
|
1750
|
-
|
|
1887
|
+
function getCoreLiteralValue(p) {
|
|
1888
|
+
const def = p._def;
|
|
1889
|
+
if (def.tag === "literal" && !def.caseInsensitive) return def.value;
|
|
1890
|
+
if (def.tag === "transform") return getCoreLiteralValue(def.parser);
|
|
1891
|
+
return null;
|
|
1892
|
+
}
|
|
1893
|
+
function getCoreRegexDef(p) {
|
|
1894
|
+
const def = p._def;
|
|
1895
|
+
if (def.tag === "regex") return { source: def.source, flags: def.flags };
|
|
1896
|
+
if (def.tag === "transform") return getCoreRegexDef(def.parser);
|
|
1897
|
+
if (def.tag === "label") return getCoreRegexDef(def.parser);
|
|
1898
|
+
return null;
|
|
1751
1899
|
}
|
|
1752
|
-
function
|
|
1753
|
-
|
|
1754
|
-
if (
|
|
1900
|
+
function applyTransforms(p, value, span) {
|
|
1901
|
+
const def = p._def;
|
|
1902
|
+
if (def.tag === "transform") {
|
|
1903
|
+
const inner = applyTransforms(def.parser, value, span);
|
|
1904
|
+
return def.fn(inner, span);
|
|
1905
|
+
}
|
|
1906
|
+
return value;
|
|
1755
1907
|
}
|
|
1756
|
-
function
|
|
1757
|
-
const
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1908
|
+
function continuationFirstSet(lit, source, flags) {
|
|
1909
|
+
const re = new RegExp(source, "y" + flags.replace(/[gy]/g, ""));
|
|
1910
|
+
re.lastIndex = 0;
|
|
1911
|
+
const base = re.exec(lit);
|
|
1912
|
+
if (!base || base[0] !== lit) return null;
|
|
1913
|
+
const contCodes = [];
|
|
1914
|
+
for (let code = 1; code < 128; code++) {
|
|
1915
|
+
re.lastIndex = 0;
|
|
1916
|
+
const m = re.exec(lit + String.fromCharCode(code));
|
|
1917
|
+
if (m && m[0].length > lit.length) contCodes.push(code);
|
|
1918
|
+
}
|
|
1919
|
+
if (contCodes.length === 0) return null;
|
|
1920
|
+
return codesToFirstSet(contCodes);
|
|
1767
1921
|
}
|
|
1768
|
-
function
|
|
1769
|
-
|
|
1922
|
+
function codesToFirstSet(codes) {
|
|
1923
|
+
codes.sort((a, b) => a - b);
|
|
1924
|
+
const ranges = [];
|
|
1925
|
+
let lo = codes[0], hi = codes[0];
|
|
1926
|
+
for (let i = 1; i < codes.length; i++) {
|
|
1927
|
+
if (codes[i] === hi + 1) {
|
|
1928
|
+
hi = codes[i];
|
|
1929
|
+
} else {
|
|
1930
|
+
ranges.push({ lo, hi });
|
|
1931
|
+
lo = hi = codes[i];
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
ranges.push({ lo, hi });
|
|
1935
|
+
return { kind: "ranges", ranges };
|
|
1770
1936
|
}
|
|
1771
|
-
function
|
|
1772
|
-
|
|
1773
|
-
if (
|
|
1937
|
+
function inFirstSet(code, fs) {
|
|
1938
|
+
if (fs.kind === "any") return true;
|
|
1939
|
+
if (fs.kind === "empty") return false;
|
|
1940
|
+
for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
1941
|
+
return false;
|
|
1774
1942
|
}
|
|
1775
|
-
function
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
if (end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1782
|
-
return {
|
|
1783
|
-
end,
|
|
1784
|
-
commit: () => recordTriviaChunks(ctx, chunks)
|
|
1785
|
-
};
|
|
1943
|
+
function areDisjoint(sets) {
|
|
1944
|
+
if (sets.some((s) => s.kind === "any")) return false;
|
|
1945
|
+
for (let i = 0; i < sets.length; i++)
|
|
1946
|
+
for (let j2 = i + 1; j2 < sets.length; j2++)
|
|
1947
|
+
if (intersects(sets[i], sets[j2])) return false;
|
|
1948
|
+
return true;
|
|
1786
1949
|
}
|
|
1787
|
-
function
|
|
1788
|
-
const
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1950
|
+
function buildAsciiDispatch(parsers) {
|
|
1951
|
+
const table = Array(128).fill(-1);
|
|
1952
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1953
|
+
const fs = parsers[i]._meta.firstSet;
|
|
1954
|
+
if (fs.kind !== "ranges") continue;
|
|
1955
|
+
for (const { lo, hi } of fs.ranges) {
|
|
1956
|
+
for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
|
|
1957
|
+
table[code] = i;
|
|
1958
|
+
}
|
|
1796
1959
|
}
|
|
1797
|
-
const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1798
|
-
return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
|
|
1799
|
-
}
|
|
1800
|
-
const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
|
|
1801
|
-
const fast = fastTriviaScanner(triviaP);
|
|
1802
|
-
if (fast) {
|
|
1803
|
-
const end = fast(input, cur);
|
|
1804
|
-
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1805
|
-
return end;
|
|
1806
|
-
}
|
|
1807
|
-
if (ctx.triviaKindLabels) {
|
|
1808
|
-
const scan = scanWithLabels(input, cur, ctx);
|
|
1809
|
-
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
|
|
1810
|
-
return scan.end;
|
|
1811
1960
|
}
|
|
1812
|
-
|
|
1813
|
-
return tr.ok && tr.span.end > cur ? tr.span.end : cur;
|
|
1961
|
+
return table;
|
|
1814
1962
|
}
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
if (
|
|
1829
|
-
|
|
1830
|
-
trackLines: log !== void 0 ? false : ctx.trackLines,
|
|
1831
|
-
state: ctx.state
|
|
1832
|
-
});
|
|
1833
|
-
if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1834
|
-
const end = tr3.span.end;
|
|
1835
|
-
return {
|
|
1836
|
-
end,
|
|
1837
|
-
commit: () => {
|
|
1838
|
-
pushTriviaLogEntry(ctx, cur, end);
|
|
1839
|
-
if (captureTl) pushCstTriviaEntry(ctx, cur, end);
|
|
1840
|
-
}
|
|
1841
|
-
};
|
|
1963
|
+
|
|
1964
|
+
// src/analysis/duplication.ts
|
|
1965
|
+
var WORD_RE_SRC = "-?[A-Za-z][A-Za-z0-9_-]*";
|
|
1966
|
+
var WORDS_RE = new RegExp(`^${WORD_RE_SRC}(?:\\|${WORD_RE_SRC})*$`);
|
|
1967
|
+
|
|
1968
|
+
// src/combinators/probe.ts
|
|
1969
|
+
function failAt(ctx, expected, pos) {
|
|
1970
|
+
const r = { ok: false, expected, span: { start: pos, end: pos } };
|
|
1971
|
+
const probe = ctx._probe;
|
|
1972
|
+
if (probe !== void 0 && pos <= probe.offset) {
|
|
1973
|
+
const best = probe.best;
|
|
1974
|
+
if (best === null || pos > best.span.start) {
|
|
1975
|
+
probe.best = r;
|
|
1976
|
+
} else if (pos === best.span.start) {
|
|
1977
|
+
probe.best = { ...best, expected: [...best.expected, ...expected] };
|
|
1842
1978
|
}
|
|
1843
|
-
const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1844
|
-
return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
|
|
1845
1979
|
}
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1980
|
+
return r;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
// src/combinators/literal.ts
|
|
1984
|
+
function asciiFoldEq(a, b) {
|
|
1985
|
+
if (a.length !== b.length) return false;
|
|
1986
|
+
for (let i = 0; i < a.length; i++) {
|
|
1987
|
+
let ca = a.charCodeAt(i);
|
|
1988
|
+
let cb = b.charCodeAt(i);
|
|
1989
|
+
if (ca >= 65 && ca <= 90) ca += 32;
|
|
1990
|
+
if (cb >= 65 && cb <= 90) cb += 32;
|
|
1991
|
+
if (ca !== cb) return false;
|
|
1852
1992
|
}
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1993
|
+
return true;
|
|
1994
|
+
}
|
|
1995
|
+
function literal(value, opts = {}) {
|
|
1996
|
+
const caseInsensitive = opts.caseInsensitive ?? false;
|
|
1997
|
+
const firstSet = value.length > 0 ? fromChar(value.codePointAt(0)) : empty();
|
|
1998
|
+
const meta = {
|
|
1999
|
+
firstSet,
|
|
2000
|
+
canMatchNewline: value.includes("\n"),
|
|
2001
|
+
isTrivia: false
|
|
2002
|
+
};
|
|
2003
|
+
const canMatchNewline = meta.canMatchNewline;
|
|
2004
|
+
if (caseInsensitive) {
|
|
2005
|
+
const upper = value.toUpperCase();
|
|
2006
|
+
const lower = value.toLowerCase();
|
|
2007
|
+
const firstUpper = upper.codePointAt(0);
|
|
2008
|
+
const firstLower = lower.codePointAt(0);
|
|
2009
|
+
meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? firstLower === firstUpper ? { kind: "ranges", ranges: [{ lo: firstLower, hi: firstLower }] } : { kind: "ranges", ranges: [
|
|
2010
|
+
{ lo: firstLower, hi: firstLower },
|
|
2011
|
+
{ lo: firstUpper, hi: firstUpper }
|
|
2012
|
+
] } : firstSet;
|
|
1857
2013
|
}
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
2014
|
+
const expected = [JSON.stringify(value)];
|
|
2015
|
+
const parse = !caseInsensitive && value.length === 1 ? (() => {
|
|
2016
|
+
const code = value.charCodeAt(0);
|
|
2017
|
+
return function parse2(input, pos, ctx) {
|
|
2018
|
+
if (input.charCodeAt(pos) === code) {
|
|
2019
|
+
const span = { start: pos, end: pos + 1 };
|
|
2020
|
+
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
|
|
2021
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
|
|
2022
|
+
return { ok: true, value, span };
|
|
1867
2023
|
}
|
|
2024
|
+
return failAt(ctx, expected, pos);
|
|
1868
2025
|
};
|
|
1869
|
-
}
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
}
|
|
1879
|
-
|
|
1880
|
-
const cached = fastTriviaCache.get(trivia2);
|
|
1881
|
-
if (cached !== void 0) return cached;
|
|
1882
|
-
const scanner = buildFastTriviaScanner(trivia2);
|
|
1883
|
-
fastTriviaCache.set(trivia2, scanner);
|
|
1884
|
-
return scanner;
|
|
1885
|
-
}
|
|
1886
|
-
function buildFastTriviaScanner(trivia2) {
|
|
1887
|
-
const core = trivia2._def.tag === "trivia" ? trivia2._def.parser : trivia2;
|
|
1888
|
-
const direct = regexTriviaScanner(core);
|
|
1889
|
-
if (direct) return direct;
|
|
1890
|
-
const repeat = core._def.tag === "oneOrMore" || core._def.tag === "many" && core._def.min >= 1 ? core._def.parser : null;
|
|
1891
|
-
if (!repeat) return null;
|
|
1892
|
-
const one = regexTriviaScanner(repeat);
|
|
1893
|
-
if (one) return loopScanner([one]);
|
|
1894
|
-
if (repeat._def.tag !== "choice") return null;
|
|
1895
|
-
const arms = repeat._def.parsers.map(regexTriviaScanner);
|
|
1896
|
-
if (arms.some((s) => s === null)) return null;
|
|
1897
|
-
return loopScanner(arms);
|
|
1898
|
-
}
|
|
1899
|
-
function loopScanner(arms) {
|
|
1900
|
-
return (input, cur) => {
|
|
1901
|
-
let pos = cur;
|
|
1902
|
-
scan: while (pos < input.length) {
|
|
1903
|
-
for (const arm of arms) {
|
|
1904
|
-
const end = arm(input, pos);
|
|
1905
|
-
if (end > pos) {
|
|
1906
|
-
pos = end;
|
|
1907
|
-
continue scan;
|
|
1908
|
-
}
|
|
1909
|
-
}
|
|
1910
|
-
break;
|
|
2026
|
+
})() : function parse2(input, pos, ctx) {
|
|
2027
|
+
const end = pos + value.length;
|
|
2028
|
+
if (end > input.length) {
|
|
2029
|
+
return failAt(ctx, expected, pos);
|
|
2030
|
+
}
|
|
2031
|
+
const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
|
|
2032
|
+
if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
|
|
2033
|
+
const span = { start: pos, end };
|
|
2034
|
+
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
|
|
2035
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
|
|
2036
|
+
return { ok: true, value: matchedValue, span };
|
|
1911
2037
|
}
|
|
1912
|
-
return pos;
|
|
2038
|
+
return failAt(ctx, expected, pos);
|
|
2039
|
+
};
|
|
2040
|
+
return {
|
|
2041
|
+
_tag: "literal",
|
|
2042
|
+
_meta: meta,
|
|
2043
|
+
_def: { tag: "literal", value, caseInsensitive },
|
|
2044
|
+
parse
|
|
1913
2045
|
};
|
|
1914
2046
|
}
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
2047
|
+
|
|
2048
|
+
// src/combinators/regex.ts
|
|
2049
|
+
var firstSetAnalyzer = null;
|
|
2050
|
+
var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
|
|
2051
|
+
var SCAN_BAIL_AT = 64;
|
|
1920
2052
|
function inRanges2(cp, ranges) {
|
|
1921
2053
|
for (let i = 0; i < ranges.length; i++) {
|
|
1922
|
-
const
|
|
1923
|
-
if (cp >=
|
|
2054
|
+
const [lo, hi] = ranges[i];
|
|
2055
|
+
if (cp >= lo && cp <= hi) return true;
|
|
1924
2056
|
}
|
|
1925
2057
|
return false;
|
|
1926
2058
|
}
|
|
1927
|
-
function
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
return (input, cur) => {
|
|
1931
|
-
let pos = cur;
|
|
1932
|
-
while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
|
|
1933
|
-
return pos;
|
|
1934
|
-
};
|
|
2059
|
+
function readClassRanges(body) {
|
|
2060
|
+
if (body.startsWith("^")) return null;
|
|
2061
|
+
return parseClassRanges(body);
|
|
1935
2062
|
}
|
|
1936
|
-
function
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
2063
|
+
function shortScanner(source, flags) {
|
|
2064
|
+
if (/[imsuvy]/.test(flags)) return null;
|
|
2065
|
+
let ranges = null;
|
|
2066
|
+
let quant = "";
|
|
2067
|
+
if (source[0] === "[") {
|
|
2068
|
+
let end = 1;
|
|
2069
|
+
while (end < source.length && source[end] !== "]") {
|
|
2070
|
+
if (source[end] === "\\") end += 2;
|
|
2071
|
+
else end++;
|
|
1944
2072
|
}
|
|
1945
|
-
return
|
|
2073
|
+
if (source[end] !== "]") return null;
|
|
2074
|
+
ranges = readClassRanges(source.slice(1, end));
|
|
2075
|
+
quant = source.slice(end + 1);
|
|
2076
|
+
} else if (source[0] === "\\" && (source[1] === "d" || source[1] === "w" || source[1] === "s")) {
|
|
2077
|
+
ranges = shorthandRanges(source[1]);
|
|
2078
|
+
quant = source.slice(2);
|
|
2079
|
+
}
|
|
2080
|
+
if (!ranges || quant !== "+" && quant !== "*") return null;
|
|
2081
|
+
const minOne = quant === "+";
|
|
2082
|
+
return (input, pos) => {
|
|
2083
|
+
let end = pos;
|
|
2084
|
+
while (end < input.length && inRanges2(input.charCodeAt(end), ranges)) {
|
|
2085
|
+
end++;
|
|
2086
|
+
if (end - pos >= SCAN_BAIL_AT) return void 0;
|
|
2087
|
+
}
|
|
2088
|
+
return minOne && end === pos ? null : end;
|
|
1946
2089
|
};
|
|
1947
2090
|
}
|
|
1948
|
-
function
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
const
|
|
1956
|
-
|
|
2091
|
+
function asciiCaseFold(fs) {
|
|
2092
|
+
if (fs.kind !== "ranges") return fs;
|
|
2093
|
+
const ranges = fs.ranges.map((r) => ({ lo: r.lo, hi: r.hi }));
|
|
2094
|
+
const add = (lo, hi) => {
|
|
2095
|
+
if (lo <= hi) ranges.push({ lo, hi });
|
|
2096
|
+
};
|
|
2097
|
+
for (const r of fs.ranges) {
|
|
2098
|
+
const uLo = Math.max(r.lo, 65), uHi = Math.min(r.hi, 90);
|
|
2099
|
+
add(uLo + 32, uHi + 32);
|
|
2100
|
+
const lLo = Math.max(r.lo, 97), lHi = Math.min(r.hi, 122);
|
|
2101
|
+
add(lLo - 32, lHi - 32);
|
|
1957
2102
|
}
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
2103
|
+
ranges.sort((a, b) => a.lo - b.lo);
|
|
2104
|
+
const merged = [];
|
|
2105
|
+
for (const r of ranges) {
|
|
2106
|
+
const last = merged[merged.length - 1];
|
|
2107
|
+
if (last && r.lo <= last.hi + 1) last.hi = Math.max(last.hi, r.hi);
|
|
2108
|
+
else merged.push({ lo: r.lo, hi: r.hi });
|
|
1962
2109
|
}
|
|
1963
|
-
return
|
|
1964
|
-
}
|
|
1965
|
-
function armScanner(arm) {
|
|
1966
|
-
if (arm.kind === "comment") return lineCommentScanner(arm.code);
|
|
1967
|
-
const ranges = arm.ranges;
|
|
1968
|
-
return (input, cur) => {
|
|
1969
|
-
let pos = cur;
|
|
1970
|
-
while (pos < input.length && inRanges2(input.charCodeAt(pos), ranges)) pos++;
|
|
1971
|
-
return pos;
|
|
1972
|
-
};
|
|
2110
|
+
return { kind: "ranges", ranges: merged };
|
|
1973
2111
|
}
|
|
1974
|
-
function
|
|
1975
|
-
const
|
|
1976
|
-
const
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
2112
|
+
function regex(pattern, flags = "") {
|
|
2113
|
+
const source = typeof pattern === "string" ? pattern : pattern.source;
|
|
2114
|
+
const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
|
|
2115
|
+
const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
|
|
2116
|
+
const scan = shortScanner(source, resolvedFlags);
|
|
2117
|
+
const raw = (firstSetAnalyzer ?? permissiveFirstSet)(source);
|
|
2118
|
+
const firstSet = !resolvedFlags.includes("i") ? raw.firstSet : resolvedFlags.includes("u") || resolvedFlags.includes("v") ? any() : asciiCaseFold(raw.firstSet);
|
|
2119
|
+
const canMatchNewline = raw.canMatchNewline;
|
|
2120
|
+
const meta = { firstSet, canMatchNewline, isTrivia: false };
|
|
2121
|
+
return {
|
|
2122
|
+
_tag: "regex",
|
|
2123
|
+
_meta: meta,
|
|
2124
|
+
_def: { tag: "regex", source, flags: resolvedFlags },
|
|
2125
|
+
parse(input, pos, ctx) {
|
|
2126
|
+
const scanEnd = scan?.(input, pos);
|
|
2127
|
+
if (scanEnd !== void 0) {
|
|
2128
|
+
if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
|
|
2129
|
+
const value = input.slice(pos, scanEnd);
|
|
2130
|
+
const span2 = { start: pos, end: scanEnd };
|
|
2131
|
+
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, scanEnd);
|
|
2132
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span: span2 });
|
|
2133
|
+
return { ok: true, value, span: span2 };
|
|
1985
2134
|
}
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
if (cc === 10 || cc === 13) break;
|
|
1991
|
-
pos++;
|
|
1992
|
-
}
|
|
1993
|
-
continue;
|
|
2135
|
+
anchored.lastIndex = pos;
|
|
2136
|
+
const m = anchored.exec(input);
|
|
2137
|
+
if (m === null) {
|
|
2138
|
+
return failAt(ctx, [`/${source}/`], pos);
|
|
1994
2139
|
}
|
|
1995
|
-
|
|
2140
|
+
const span = { start: pos, end: pos + m[0].length };
|
|
2141
|
+
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
|
|
2142
|
+
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: m[0], span });
|
|
2143
|
+
return { ok: true, value: m[0], span };
|
|
1996
2144
|
}
|
|
1997
|
-
return pos;
|
|
1998
2145
|
};
|
|
1999
2146
|
}
|
|
2000
|
-
function splitTopLevelAlts(body) {
|
|
2001
|
-
const arms = [];
|
|
2002
|
-
let inClass = false;
|
|
2003
|
-
let start = 0;
|
|
2004
|
-
for (let i = 0; i < body.length; i++) {
|
|
2005
|
-
const c = body[i];
|
|
2006
|
-
if (c === "\\") {
|
|
2007
|
-
i++;
|
|
2008
|
-
continue;
|
|
2009
|
-
}
|
|
2010
|
-
if (inClass) {
|
|
2011
|
-
if (c === "]") inClass = false;
|
|
2012
|
-
continue;
|
|
2013
|
-
}
|
|
2014
|
-
if (c === "[") inClass = true;
|
|
2015
|
-
else if (c === "(") return null;
|
|
2016
|
-
else if (c === "|") {
|
|
2017
|
-
arms.push(body.slice(start, i));
|
|
2018
|
-
start = i + 1;
|
|
2019
|
-
}
|
|
2020
|
-
}
|
|
2021
|
-
arms.push(body.slice(start));
|
|
2022
|
-
return arms;
|
|
2023
|
-
}
|
|
2024
|
-
function altStarSource(source) {
|
|
2025
|
-
const m = /^\(\?:(.*)\)[*+]$/.exec(source);
|
|
2026
|
-
if (!m) return null;
|
|
2027
|
-
const armSrcs = splitTopLevelAlts(m[1]);
|
|
2028
|
-
if (!armSrcs || armSrcs.length < 2) return null;
|
|
2029
|
-
const arms = [];
|
|
2030
|
-
for (const src of armSrcs) {
|
|
2031
|
-
const arm = classifyTriviaArm(src);
|
|
2032
|
-
if (!arm) return null;
|
|
2033
|
-
arms.push(arm);
|
|
2034
|
-
}
|
|
2035
|
-
const ranges = [];
|
|
2036
|
-
const commentCodes = [];
|
|
2037
|
-
for (const arm of arms) {
|
|
2038
|
-
if (arm.kind === "class") ranges.push(...arm.ranges);
|
|
2039
|
-
else commentCodes.push(arm.code);
|
|
2040
|
-
}
|
|
2041
|
-
if (commentCodes.some((code) => inRanges2(code, ranges))) {
|
|
2042
|
-
return loopScanner(arms.map(armScanner));
|
|
2043
|
-
}
|
|
2044
|
-
if (commentCodes.length === 0) return armScanner({ kind: "class", ranges });
|
|
2045
|
-
return fusedTriviaScanner(ranges, commentCodes);
|
|
2046
|
-
}
|
|
2047
|
-
function blockCommentSource(source) {
|
|
2048
|
-
return source === "\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/" || source === "\\/\\*[^]*?\\*\\/";
|
|
2049
|
-
}
|
|
2050
|
-
function scanBlockComment(input, cur) {
|
|
2051
|
-
if (input.charCodeAt(cur) !== 47 || input.charCodeAt(cur + 1) !== 42) return cur;
|
|
2052
|
-
const close = input.indexOf("*/", cur + 2);
|
|
2053
|
-
return close === -1 ? cur : close + 2;
|
|
2054
|
-
}
|
|
2055
2147
|
|
|
2056
2148
|
// src/combinators/sequence.ts
|
|
2057
2149
|
function sequence(...parsers) {
|
|
@@ -2467,6 +2559,25 @@ function trivia(combinator) {
|
|
|
2467
2559
|
parse: combinator.parse.bind(combinator)
|
|
2468
2560
|
};
|
|
2469
2561
|
}
|
|
2562
|
+
function classifiedTrivia(arms) {
|
|
2563
|
+
const entries = Object.entries(arms);
|
|
2564
|
+
if (entries.length === 0) {
|
|
2565
|
+
throw new TypeError("classifiedTrivia() requires at least one named trivia arm.");
|
|
2566
|
+
}
|
|
2567
|
+
for (let i = 0; i < entries.length; i++) {
|
|
2568
|
+
const [name, arm] = entries[i];
|
|
2569
|
+
const first = arm._meta.firstSet;
|
|
2570
|
+
if (matchesEmpty(arm) || first.kind !== "ranges" || first.ranges.length === 0) {
|
|
2571
|
+
throw new TypeError(
|
|
2572
|
+
`classifiedTrivia(): ${JSON.stringify(name)} must be non-nullable with a concrete finite first set.`
|
|
2573
|
+
);
|
|
2574
|
+
}
|
|
2575
|
+
}
|
|
2576
|
+
const labeledArms = entries.map(([name, arm]) => label(name, arm));
|
|
2577
|
+
const result = trivia(oneOrMore(choice(...labeledArms)));
|
|
2578
|
+
result._meta.rootTriviaClassified = true;
|
|
2579
|
+
return result;
|
|
2580
|
+
}
|
|
2470
2581
|
function label(name, combinator) {
|
|
2471
2582
|
return {
|
|
2472
2583
|
_tag: combinator._tag,
|
|
@@ -2560,8 +2671,48 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
|
|
|
2560
2671
|
};
|
|
2561
2672
|
}
|
|
2562
2673
|
|
|
2674
|
+
// src/compiler/degradation.ts
|
|
2675
|
+
function formatDegradation(d) {
|
|
2676
|
+
return `[parseman] degraded [${d.code}] ${d.where}: ${d.subject} \u2014 ${d.fellBackTo}; otherwise ${d.otherwise}`;
|
|
2677
|
+
}
|
|
2678
|
+
var _sinks = [];
|
|
2679
|
+
function resolveDegradationLevel(explicit) {
|
|
2680
|
+
if (explicit !== void 0) return explicit;
|
|
2681
|
+
const env = typeof process !== "undefined" ? process.env?.PARSEMAN_DEGRADATION : void 0;
|
|
2682
|
+
if (env === "off" || env === "warn" || env === "error") return env;
|
|
2683
|
+
return "warn";
|
|
2684
|
+
}
|
|
2685
|
+
function degradationKey(d) {
|
|
2686
|
+
return JSON.stringify([d.code, d.where, d.subject]);
|
|
2687
|
+
}
|
|
2688
|
+
function recordDegradation(d) {
|
|
2689
|
+
const level = resolveDegradationLevel();
|
|
2690
|
+
if (level === "off") return;
|
|
2691
|
+
const key = degradationKey(d);
|
|
2692
|
+
const sink = _sinks[_sinks.length - 1];
|
|
2693
|
+
if (sink) {
|
|
2694
|
+
if (!sink.has(key)) sink.set(key, d);
|
|
2695
|
+
return;
|
|
2696
|
+
}
|
|
2697
|
+
if (_immediate.has(key)) return;
|
|
2698
|
+
_immediate.add(key);
|
|
2699
|
+
if (level === "error") throw new Error(`parseman: degraded compilation path
|
|
2700
|
+
${formatDegradation(d)}`);
|
|
2701
|
+
console.warn(formatDegradation(d));
|
|
2702
|
+
}
|
|
2703
|
+
var _immediate = /* @__PURE__ */ new Set();
|
|
2704
|
+
|
|
2705
|
+
// src/cst/trivia-entries.ts
|
|
2706
|
+
var EMPTY_INDICES = Object.freeze([]);
|
|
2707
|
+
var EMPTY_GAPS = Object.freeze([]);
|
|
2708
|
+
var SELECTED_ROOT_STRIDE = 5;
|
|
2709
|
+
|
|
2563
2710
|
// src/compiler/scannable-run.ts
|
|
2564
2711
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
2712
|
+
var SELECTED_ROOT_OWNED_RANGE_PLACEHOLDER = Array.from(
|
|
2713
|
+
{ length: SELECTED_ROOT_STRIDE - 3 },
|
|
2714
|
+
() => "0"
|
|
2715
|
+
).join(", ");
|
|
2565
2716
|
|
|
2566
2717
|
// src/compiler/trivia-fast-path.ts
|
|
2567
2718
|
var CAP_RECORD = [
|
|
@@ -2570,50 +2721,193 @@ var CAP_RECORD = [
|
|
|
2570
2721
|
` if (_cap === 1 && _ctx._cstTriviaLog !== undefined && _ctx.captureTrivia) _ctx._cstTriviaLog.push(_pos, _e, _ctx._cstRawChildren ? _ctx._cstRawChildren.length : 0)`,
|
|
2571
2722
|
` }`
|
|
2572
2723
|
].join("\n");
|
|
2724
|
+
var SELECTED_ROOT_FINISH = [
|
|
2725
|
+
` if (_cap && _ctx._rootTriviaCapture !== false && _ctx._rootTriviaLog !== undefined && _ctx._rootTriviaLog.length !== _rootMark) {`,
|
|
2726
|
+
` for (let _ri = _rootMark; _ri < _ctx._rootTriviaLog.length; _ri += ${SELECTED_ROOT_STRIDE}) { _ctx._rootTriviaLog[_ri] = _pos; _ctx._rootTriviaLog[_ri + 1] = _e }`,
|
|
2727
|
+
` }`
|
|
2728
|
+
].join("\n");
|
|
2573
2729
|
|
|
2574
2730
|
// src/compiler/build-arity.ts
|
|
2575
2731
|
function cstOutputHost(build) {
|
|
2576
2732
|
return build?._parsemanCstOutput === true;
|
|
2577
2733
|
}
|
|
2578
|
-
var
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
var CONFIRMABLE_PARAM_RE = /^[A-Za-z_$][\w$]*\s*\??\s*(?::[^,=]+)?$/;
|
|
2734
|
+
var SINGLE_IDENT_ARROW_RE = /^[A-Za-z_$][\w$]*\s*=>/;
|
|
2735
|
+
var PARAM_LIST_OPEN_RE = /^(?:function\b[^(]*)?\(/;
|
|
2736
|
+
var NATIVE_CODE_RE = /\{\s*\[native code\]\s*\}/;
|
|
2737
|
+
var PARAM_HEAD_RE = /^[A-Za-z_$][\w$]*\s*\??\s*/;
|
|
2583
2738
|
function confirmedBuildArity(src) {
|
|
2584
2739
|
const s = src.trim();
|
|
2585
|
-
|
|
2586
|
-
if (
|
|
2587
|
-
if (
|
|
2588
|
-
const inner = (
|
|
2589
|
-
if (inner ===
|
|
2590
|
-
|
|
2740
|
+
if (NATIVE_CODE_RE.test(s)) return null;
|
|
2741
|
+
if (/\barguments\b/.test(s)) return null;
|
|
2742
|
+
if (SINGLE_IDENT_ARROW_RE.test(s)) return 1;
|
|
2743
|
+
const inner = paramListText(s);
|
|
2744
|
+
if (inner === null) return null;
|
|
2745
|
+
if (inner.trim() === "") return 0;
|
|
2746
|
+
const parts = splitTopLevel(inner);
|
|
2747
|
+
if (parts === null) return null;
|
|
2591
2748
|
for (const part of parts) {
|
|
2592
|
-
if (!
|
|
2749
|
+
if (!isConfirmableParam(part.trim())) return null;
|
|
2593
2750
|
}
|
|
2594
|
-
if (/\barguments\b/.test(s)) return null;
|
|
2595
2751
|
return parts.length;
|
|
2596
2752
|
}
|
|
2753
|
+
function paramListText(s) {
|
|
2754
|
+
const open = PARAM_LIST_OPEN_RE.exec(s);
|
|
2755
|
+
if (!open) return null;
|
|
2756
|
+
const start = open[0].length;
|
|
2757
|
+
const end = matchingParen(s, start);
|
|
2758
|
+
if (end === null) return null;
|
|
2759
|
+
if (!s.startsWith("function") && !/^\s*=>/.test(s.slice(end + 1))) return null;
|
|
2760
|
+
return s.slice(start, end);
|
|
2761
|
+
}
|
|
2762
|
+
function matchingParen(s, start) {
|
|
2763
|
+
let depth = 0;
|
|
2764
|
+
for (let i = start; i < s.length; i++) {
|
|
2765
|
+
const c = s[i];
|
|
2766
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
2767
|
+
const close = skipString(s, i);
|
|
2768
|
+
if (close === null) return null;
|
|
2769
|
+
i = close;
|
|
2770
|
+
continue;
|
|
2771
|
+
}
|
|
2772
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
2773
|
+
else if (c === "]" || c === "}") {
|
|
2774
|
+
if (--depth < 0) return null;
|
|
2775
|
+
} else if (c === ")") {
|
|
2776
|
+
if (depth === 0) return i;
|
|
2777
|
+
depth--;
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
return null;
|
|
2781
|
+
}
|
|
2782
|
+
function skipString(s, open) {
|
|
2783
|
+
const quote2 = s[open];
|
|
2784
|
+
for (let i = open + 1; i < s.length; i++) {
|
|
2785
|
+
if (s[i] === "\\") {
|
|
2786
|
+
i++;
|
|
2787
|
+
continue;
|
|
2788
|
+
}
|
|
2789
|
+
if (s[i] === quote2) return i;
|
|
2790
|
+
}
|
|
2791
|
+
return null;
|
|
2792
|
+
}
|
|
2793
|
+
function splitTopLevel(inner) {
|
|
2794
|
+
const parts = [];
|
|
2795
|
+
let depth = 0;
|
|
2796
|
+
let angle = 0;
|
|
2797
|
+
let last = 0;
|
|
2798
|
+
for (let i = 0; i < inner.length; i++) {
|
|
2799
|
+
const c = inner[i];
|
|
2800
|
+
if (c === "=" && inner[i + 1] === ">") {
|
|
2801
|
+
i++;
|
|
2802
|
+
continue;
|
|
2803
|
+
}
|
|
2804
|
+
if (c === '"' || c === "'" || c === "`") {
|
|
2805
|
+
const close = skipString(inner, i);
|
|
2806
|
+
if (close === null) return null;
|
|
2807
|
+
i = close;
|
|
2808
|
+
continue;
|
|
2809
|
+
}
|
|
2810
|
+
if (c === "(" || c === "[" || c === "{") depth++;
|
|
2811
|
+
else if (c === ")" || c === "]" || c === "}") {
|
|
2812
|
+
if (--depth < 0) return null;
|
|
2813
|
+
} else if (c === "<") angle++;
|
|
2814
|
+
else if (c === ">") {
|
|
2815
|
+
if (--angle < 0) return null;
|
|
2816
|
+
} else if (c === "," && depth === 0 && angle === 0) {
|
|
2817
|
+
parts.push(inner.slice(last, i));
|
|
2818
|
+
last = i + 1;
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
if (depth !== 0 || angle !== 0) return null;
|
|
2822
|
+
parts.push(inner.slice(last));
|
|
2823
|
+
return parts;
|
|
2824
|
+
}
|
|
2825
|
+
function isConfirmableParam(part) {
|
|
2826
|
+
const head = PARAM_HEAD_RE.exec(part);
|
|
2827
|
+
if (!head) return false;
|
|
2828
|
+
const rest = part.slice(head[0].length);
|
|
2829
|
+
if (rest === "") return true;
|
|
2830
|
+
if (rest[0] !== ":") return false;
|
|
2831
|
+
return !hasDefaultAssign(rest.slice(1));
|
|
2832
|
+
}
|
|
2833
|
+
function hasDefaultAssign(annotation) {
|
|
2834
|
+
for (let i = 0; i < annotation.length; i++) {
|
|
2835
|
+
if (annotation[i] !== "=") continue;
|
|
2836
|
+
if (annotation[i + 1] === ">" || annotation[i + 1] === "=") {
|
|
2837
|
+
i++;
|
|
2838
|
+
continue;
|
|
2839
|
+
}
|
|
2840
|
+
const prev = annotation[i - 1];
|
|
2841
|
+
if (prev === "<" || prev === ">" || prev === "!" || prev === "=") continue;
|
|
2842
|
+
return true;
|
|
2843
|
+
}
|
|
2844
|
+
return false;
|
|
2845
|
+
}
|
|
2846
|
+
function buildAnalysisSrc(def) {
|
|
2847
|
+
return def.buildSigSrc ?? def.buildSrc ?? def.build.toString();
|
|
2848
|
+
}
|
|
2849
|
+
var RESOLVER_REASONS = {
|
|
2850
|
+
"rest-parameter": "its parameter list uses a rest parameter, so the declared arity is unbounded",
|
|
2851
|
+
"arguments": "its body references `arguments`",
|
|
2852
|
+
"reassigned": "the binding it names is reassigned, so the function read here is not decidable",
|
|
2853
|
+
"not-a-function": "the binding it names is not a function declaration",
|
|
2854
|
+
"unresolved-import": "its module could not be resolved or parsed",
|
|
2855
|
+
"not-found": "the name did not resolve to any binding",
|
|
2856
|
+
"computed": "it is a computed expression",
|
|
2857
|
+
"foreign-source": "it is named inside an imported factory, whose offsets the entry-file resolver cannot index"
|
|
2858
|
+
};
|
|
2859
|
+
function unconfirmableReason(def, src) {
|
|
2860
|
+
const declared = def.buildArityUnresolved;
|
|
2861
|
+
if (declared !== void 0 && RESOLVER_REASONS[declared]) return RESOLVER_REASONS[declared];
|
|
2862
|
+
const s = src.trim();
|
|
2863
|
+
const params = s.slice(0, s.indexOf(")") + 1);
|
|
2864
|
+
if (params.includes("...")) return RESOLVER_REASONS["rest-parameter"];
|
|
2865
|
+
if (/\barguments\b/.test(s)) return RESOLVER_REASONS["arguments"];
|
|
2866
|
+
if (/^[A-Za-z_$][\w$]*(\s*\.\s*[A-Za-z_$][\w$]*)?$/.test(s)) {
|
|
2867
|
+
return "it names a binding this build could not resolve to a function declaration";
|
|
2868
|
+
}
|
|
2869
|
+
return "its parameter list could not be parsed";
|
|
2870
|
+
}
|
|
2871
|
+
function confirmedArityForDef(def) {
|
|
2872
|
+
if (def.buildArity !== void 0) return def.buildArity;
|
|
2873
|
+
const src = buildAnalysisSrc(def);
|
|
2874
|
+
const arity = confirmedBuildArity(src);
|
|
2875
|
+
if (arity !== null) return arity;
|
|
2876
|
+
const subject = `build reducer \`${(def.buildSrc ?? "<runtime fn>").trim().split("\n")[0].slice(0, 60)}\``;
|
|
2877
|
+
recordDegradation({
|
|
2878
|
+
code: "build-arity-unconfirmed",
|
|
2879
|
+
severity: "warn",
|
|
2880
|
+
where: `node("${def.type ?? "<inferred>"}")`,
|
|
2881
|
+
subject,
|
|
2882
|
+
fellBackTo: `could not confirm its declared arity \u2014 ${unconfirmableReason(def, src)} \u2014 so this node captures children, fields and raw children, logs trivia, and clones \`_ctx.state\` on every match`,
|
|
2883
|
+
otherwise: "only the tiers the reducer actually declares would be captured (arity >= 1 children, >= 2 fields, >= 4 raw, >= 5 trivia, >= 6 state). Declare it with `node(..., { buildArity: n })` if it cannot be derived"
|
|
2884
|
+
});
|
|
2885
|
+
return null;
|
|
2886
|
+
}
|
|
2597
2887
|
function buildReadsTrivia(def) {
|
|
2598
2888
|
if (!def.build) return true;
|
|
2599
|
-
const
|
|
2600
|
-
const arity = confirmedBuildArity(src);
|
|
2889
|
+
const arity = confirmedArityForDef(def);
|
|
2601
2890
|
if (arity === null) return true;
|
|
2602
2891
|
return arity >= 5;
|
|
2603
2892
|
}
|
|
2604
2893
|
function buildReadsState(def) {
|
|
2605
2894
|
if (!def.build) return true;
|
|
2606
|
-
const
|
|
2607
|
-
const arity = confirmedBuildArity(src);
|
|
2895
|
+
const arity = confirmedArityForDef(def);
|
|
2608
2896
|
if (arity === null) return true;
|
|
2609
2897
|
return arity >= 6;
|
|
2610
2898
|
}
|
|
2611
2899
|
|
|
2900
|
+
// src/compiler/inline-build.ts
|
|
2901
|
+
var ANN = String.raw`\s*\??\s*(?::[^,)=]+)?`;
|
|
2902
|
+
var ANY_P = String.raw`\w+${ANN}`;
|
|
2903
|
+
var MK_BUILD_RE = new RegExp(
|
|
2904
|
+
String.raw`^\(\s*(\w+)${ANN}\s*,\s*${ANY_P}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*,\s*(\w+)${ANN}\s*\)\s*=>\s*mk\s*\(\s*(['"])([^'"]+)\5\s*,\s*\1\s*,\s*\3\s*,\s*\2\s*,\s*\4\s*\)\s*$`
|
|
2905
|
+
);
|
|
2906
|
+
|
|
2612
2907
|
// src/compiler/fields.ts
|
|
2613
2908
|
function buildReadsFields(def) {
|
|
2614
2909
|
if (!def.build) return true;
|
|
2615
|
-
const
|
|
2616
|
-
const arity = confirmedBuildArity(src);
|
|
2910
|
+
const arity = confirmedArityForDef(def);
|
|
2617
2911
|
if (arity === null) return true;
|
|
2618
2912
|
return arity >= 2;
|
|
2619
2913
|
}
|
|
@@ -2864,17 +3158,21 @@ function when(key, parser2, opts = {}) {
|
|
|
2864
3158
|
function otherwise(parser2) {
|
|
2865
3159
|
return { kind: "otherwise", parser: parser2, usesRouted: parserUsesRouted(parser2) };
|
|
2866
3160
|
}
|
|
2867
|
-
function routed() {
|
|
3161
|
+
function routed(fallback) {
|
|
2868
3162
|
return {
|
|
2869
3163
|
_tag: "routed",
|
|
2870
|
-
_meta: {
|
|
2871
|
-
|
|
3164
|
+
_meta: {
|
|
3165
|
+
// The routed token is whatever the selector matched, so the first set stays
|
|
3166
|
+
// `any` even with a fallback — `any` already subsumes the fallback's.
|
|
3167
|
+
firstSet: { kind: "any" },
|
|
3168
|
+
canMatchNewline: fallback?._meta.canMatchNewline ?? false,
|
|
3169
|
+
isTrivia: false
|
|
3170
|
+
},
|
|
3171
|
+
_def: fallback === void 0 ? { tag: "routed" } : { tag: "routed", fallback },
|
|
2872
3172
|
parse(_input, pos, ctx) {
|
|
2873
3173
|
const item = ctx._routed;
|
|
2874
|
-
if (item === void 0) {
|
|
2875
|
-
|
|
2876
|
-
}
|
|
2877
|
-
if (pos !== item.span.start) {
|
|
3174
|
+
if (item === void 0 || pos !== item.span.start) {
|
|
3175
|
+
if (fallback !== void 0) return fallback.parse(_input, pos, ctx);
|
|
2878
3176
|
return { ok: false, expected: ["routed()"], span: { start: pos, end: pos } };
|
|
2879
3177
|
}
|
|
2880
3178
|
if (cstCaptureActive(ctx)) {
|
|
@@ -3009,10 +3307,12 @@ function attempt(parser2) {
|
|
|
3009
3307
|
}
|
|
3010
3308
|
const mark = saveCstMark(ctx);
|
|
3011
3309
|
const log = ctx._triviaLog?.length;
|
|
3310
|
+
const rootLog = ctx._rootTriviaLog?.length;
|
|
3012
3311
|
const result = parser2.parse(input, pos, ctx);
|
|
3013
3312
|
if (result.ok) return result;
|
|
3014
3313
|
rollbackCstCapture(ctx, mark);
|
|
3015
3314
|
if (log !== void 0 && ctx._triviaLog && ctx._triviaLog.length !== log) ctx._triviaLog.length = log;
|
|
3315
|
+
if (rootLog !== void 0 && ctx._rootTriviaLog && ctx._rootTriviaLog.length !== rootLog) ctx._rootTriviaLog.length = rootLog;
|
|
3016
3316
|
if (result.committed) return result;
|
|
3017
3317
|
return { ok: false, expected: result.expected, span: { start: pos, end: pos } };
|
|
3018
3318
|
}
|
|
@@ -3075,6 +3375,13 @@ function isCstChild(value) {
|
|
|
3075
3375
|
function missingInferredType() {
|
|
3076
3376
|
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
3077
3377
|
}
|
|
3378
|
+
function normalizeBuildArity(arity) {
|
|
3379
|
+
if (arity === void 0) return void 0;
|
|
3380
|
+
if (!Number.isInteger(arity) || arity < 0 || arity > 6) {
|
|
3381
|
+
throw new Error("node() buildArity must be an integer 0..6 (children, fields, span, rawChildren, triviaLog, state)");
|
|
3382
|
+
}
|
|
3383
|
+
return arity;
|
|
3384
|
+
}
|
|
3078
3385
|
function normalizeProject(project) {
|
|
3079
3386
|
if (project === void 0) return void 0;
|
|
3080
3387
|
if (!Number.isInteger(project) || project < 0) {
|
|
@@ -3110,13 +3417,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
3110
3417
|
const captureTrivia = opts?.captureTrivia === true;
|
|
3111
3418
|
const trailingTrivia = opts?.trailingTrivia === true;
|
|
3112
3419
|
const tags = opts?.tags;
|
|
3420
|
+
const buildArity = normalizeBuildArity(opts?.buildArity);
|
|
3113
3421
|
if (unwrap && collapse) {
|
|
3114
3422
|
throw new Error("node() options cannot set both unwrap and collapse");
|
|
3115
3423
|
}
|
|
3116
3424
|
if (project !== void 0 && (unwrap || collapse)) {
|
|
3117
3425
|
throw new Error("node() options cannot combine project with unwrap or collapse");
|
|
3118
3426
|
}
|
|
3119
|
-
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;
|
|
3427
|
+
const def = unwrap || collapse || project !== void 0 || captureTrivia || trailingTrivia || buildArity !== void 0 || tags !== void 0 && tags.length > 0 ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {}, ...project !== void 0 ? { project } : {}, ...captureTrivia ? { captureTrivia: true } : {}, ...trailingTrivia ? { trailingTrivia: true } : {}, ...buildArity !== void 0 ? { buildArity } : {}, ...tags !== void 0 && tags.length > 0 ? { tags } : {} } : baseDef;
|
|
3120
3428
|
const capturesTrivia = captureTrivia || trailingTrivia || (build ? buildReadsTrivia(def) : project === void 0);
|
|
3121
3429
|
const clonesState = build ? buildReadsState(def) : project === void 0;
|
|
3122
3430
|
const hasOwnFields = parserHasOwnFields(combinator);
|
|
@@ -3162,7 +3470,7 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
3162
3470
|
const cstOutput = cstOutputHost(ctx.build);
|
|
3163
3471
|
const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
|
|
3164
3472
|
const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
3165
|
-
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 };
|
|
3473
|
+
const built = unwrap && children.length === 1 ? unwrapChild(children[0]) : collapse && children.length === 1 ? children[0] : (cstOutput || !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 };
|
|
3166
3474
|
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 };
|
|
3167
3475
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
3168
3476
|
pushCstChild(ctx, built, rawEntry);
|
|
@@ -3192,6 +3500,7 @@ function token(root) {
|
|
|
3192
3500
|
const savedRaw = ctx._cstRawChildren;
|
|
3193
3501
|
const savedTriviaLog = ctx._cstTriviaLog;
|
|
3194
3502
|
const savedOuterTriviaLog = ctx._triviaLog;
|
|
3503
|
+
const savedRootTriviaLog = ctx._rootTriviaLog;
|
|
3195
3504
|
const wasCapturing = cstCaptureActive(ctx);
|
|
3196
3505
|
ctx.trivia = void 0;
|
|
3197
3506
|
ctx.triviaKindLabels = void 0;
|
|
@@ -3201,6 +3510,7 @@ function token(root) {
|
|
|
3201
3510
|
ctx._cstRawChildren = void 0;
|
|
3202
3511
|
ctx._cstTriviaLog = void 0;
|
|
3203
3512
|
delete ctx._triviaLog;
|
|
3513
|
+
delete ctx._rootTriviaLog;
|
|
3204
3514
|
let result;
|
|
3205
3515
|
try {
|
|
3206
3516
|
result = root.parse(input, pos, ctx);
|
|
@@ -3214,6 +3524,8 @@ function token(root) {
|
|
|
3214
3524
|
ctx._cstTriviaLog = savedTriviaLog;
|
|
3215
3525
|
if (savedOuterTriviaLog === void 0) delete ctx._triviaLog;
|
|
3216
3526
|
else ctx._triviaLog = savedOuterTriviaLog;
|
|
3527
|
+
if (savedRootTriviaLog === void 0) delete ctx._rootTriviaLog;
|
|
3528
|
+
else ctx._rootTriviaLog = savedRootTriviaLog;
|
|
3217
3529
|
}
|
|
3218
3530
|
if (!result.ok) return result;
|
|
3219
3531
|
const span = result.span;
|
|
@@ -3313,7 +3625,7 @@ function evalRuleMapIR(ir) {
|
|
|
3313
3625
|
l._def.fnSrc = src;
|
|
3314
3626
|
return l;
|
|
3315
3627
|
};
|
|
3316
|
-
const _nd = (type, child, src, opts, staticError) => {
|
|
3628
|
+
const _nd = (type, child, src, opts, staticError, sigSrc) => {
|
|
3317
3629
|
if (staticError !== void 0 && staticError.length > 0) {
|
|
3318
3630
|
throw new Error(`IR direct node builder for ${type} must be macro-static and self-contained; unsupported binding(s): ${staticError.join(", ")}`);
|
|
3319
3631
|
}
|
|
@@ -3322,6 +3634,7 @@ function evalRuleMapIR(ir) {
|
|
|
3322
3634
|
}), opts);
|
|
3323
3635
|
n._def.buildSrc = src;
|
|
3324
3636
|
if (staticError !== void 0) n._def.buildStaticError = staticError;
|
|
3637
|
+
if (sigSrc !== void 0) n._def.buildSigSrc = sigSrc;
|
|
3325
3638
|
return n;
|
|
3326
3639
|
};
|
|
3327
3640
|
const _gch = (items) => {
|
|
@@ -3393,6 +3706,7 @@ function evalRuleMapIR(ir) {
|
|
|
3393
3706
|
"transform",
|
|
3394
3707
|
"skip",
|
|
3395
3708
|
"trivia",
|
|
3709
|
+
"classifiedTrivia",
|
|
3396
3710
|
"label",
|
|
3397
3711
|
"field",
|
|
3398
3712
|
"expect",
|
|
@@ -3433,6 +3747,7 @@ function evalRuleMapIR(ir) {
|
|
|
3433
3747
|
transform,
|
|
3434
3748
|
skip,
|
|
3435
3749
|
trivia,
|
|
3750
|
+
classifiedTrivia,
|
|
3436
3751
|
label,
|
|
3437
3752
|
field,
|
|
3438
3753
|
expect,
|
|
@@ -3652,7 +3967,7 @@ var Builder = class {
|
|
|
3652
3967
|
case "peek":
|
|
3653
3968
|
return { kind: "peek", item: this.walk(def.parser) };
|
|
3654
3969
|
case "routed":
|
|
3655
|
-
return { kind: "empty" };
|
|
3970
|
+
return def.fallback === void 0 ? { kind: "empty" } : this.walk(def.fallback);
|
|
3656
3971
|
// Transparent semantic wrappers — render the inner syntax.
|
|
3657
3972
|
case "transform":
|
|
3658
3973
|
case "token":
|