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