parseman 0.41.0 → 0.42.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/combinators/expect.d.ts.map +1 -1
- package/dist/combinators/grammar.d.ts.map +1 -1
- package/dist/combinators/literal.d.ts.map +1 -1
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/combinators/parser.d.ts +6 -0
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/combinators/regex.d.ts.map +1 -1
- package/dist/combinators/scanTo.d.ts.map +1 -1
- package/dist/combinators/trivia-skip.d.ts.map +1 -1
- package/dist/compiler/codegen.d.ts +5 -0
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/inline-build.d.ts +1 -1
- package/dist/compiler/inline-build.d.ts.map +1 -1
- package/dist/compiler/line-index.d.ts +1 -15
- package/dist/compiler/line-index.d.ts.map +1 -1
- package/dist/compiler/linker.d.ts +1 -0
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/cst/capture-buffer.d.ts.map +1 -1
- package/dist/index.cjs +483 -181
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +483 -181
- package/dist/index.js.map +4 -4
- package/dist/language-service/index.cjs +48 -2
- package/dist/language-service/index.cjs.map +3 -3
- package/dist/language-service/index.js +48 -2
- package/dist/language-service/index.js.map +3 -3
- package/dist/line-index.d.ts +41 -0
- package/dist/line-index.d.ts.map +1 -0
- package/dist/plugin/index.cjs +646 -169
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +646 -169
- package/dist/plugin/index.js.map +4 -4
- package/dist/recovery/scan.d.ts.map +1 -1
- package/dist/regex/first-set.d.ts.map +1 -1
- package/dist/run/index.cjs +47 -1
- package/dist/run/index.cjs.map +3 -3
- package/dist/run/index.d.ts +3 -2
- package/dist/run/index.d.ts.map +1 -1
- package/dist/run/index.js +47 -1
- package/dist/run/index.js.map +3 -3
- package/dist/spec/index.cjs +462 -327
- package/dist/spec/index.cjs.map +4 -4
- package/dist/spec/index.js +462 -327
- package/dist/spec/index.js.map +4 -4
- package/dist/types.d.ts +18 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
package/dist/spec/index.cjs
CHANGED
|
@@ -391,90 +391,63 @@ function markUnusedValues(root) {
|
|
|
391
391
|
visit(resolveRoot(root), true);
|
|
392
392
|
}
|
|
393
393
|
|
|
394
|
-
// src/
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
;
|
|
398
|
-
r._ruleName = key;
|
|
399
|
-
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
|
|
400
|
-
}
|
|
401
|
-
function isDefinableRef(v) {
|
|
402
|
-
return !!v && typeof v === "object" && "_def" in v && v._def.tag === "lazy" && typeof v.define === "function";
|
|
403
|
-
}
|
|
404
|
-
function ruleNameOf(r) {
|
|
405
|
-
return r._ruleName;
|
|
394
|
+
// src/line-index.ts
|
|
395
|
+
function createLineIndex() {
|
|
396
|
+
return { lineStarts: [0] };
|
|
406
397
|
}
|
|
407
|
-
function
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
function rules(a, b) {
|
|
412
|
-
const factory = typeof a === "function" ? a : b;
|
|
413
|
-
const options = typeof a === "function" ? b : a;
|
|
414
|
-
const cache = {};
|
|
415
|
-
const proxy = new Proxy(cache, {
|
|
416
|
-
get(target, key) {
|
|
417
|
-
if (typeof key !== "string") return void 0;
|
|
418
|
-
const record = target;
|
|
419
|
-
if (!(key in record)) {
|
|
420
|
-
const r = ref();
|
|
421
|
-
tagRule(r, key);
|
|
422
|
-
record[key] = r;
|
|
423
|
-
}
|
|
424
|
-
return record[key];
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
const definitions = factory(proxy);
|
|
428
|
-
for (const key of Object.keys(definitions)) {
|
|
429
|
-
const placeholder = cache[key];
|
|
430
|
-
const parser2 = definitions[key];
|
|
431
|
-
if (placeholder === parser2) {
|
|
432
|
-
throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
|
|
433
|
-
}
|
|
434
|
-
if (isDefinableRef(placeholder)) {
|
|
435
|
-
if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
|
|
436
|
-
placeholder.define(parser2);
|
|
437
|
-
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
438
|
-
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
439
|
-
} else if (isNamedRuleRefForAnotherRule(parser2, key)) {
|
|
440
|
-
const alias = ref();
|
|
441
|
-
tagRule(alias, key);
|
|
442
|
-
alias.define(parser2);
|
|
443
|
-
alias._meta.firstSet = parser2._meta.firstSet;
|
|
444
|
-
alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
445
|
-
cache[key] = alias;
|
|
446
|
-
} else {
|
|
447
|
-
tagRule(parser2, key);
|
|
448
|
-
cache[key] = parser2;
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
if (options?.trivia != null) {
|
|
452
|
-
for (const key of Object.keys(definitions)) {
|
|
453
|
-
const rule = cache[key];
|
|
454
|
-
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
457
|
-
if (options?.scanSkip != null) {
|
|
458
|
-
for (const key of Object.keys(definitions)) {
|
|
459
|
-
const rule = cache[key];
|
|
460
|
-
if (rule && !rule._meta.isTrivia) rule._meta.grammarScanSkip = options.scanSkip;
|
|
461
|
-
}
|
|
398
|
+
function recordLineRange(index, input, start, end) {
|
|
399
|
+
const lineStarts = index.lineStarts;
|
|
400
|
+
for (let i = start; i < end; i++) {
|
|
401
|
+
if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
|
|
462
402
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
403
|
+
}
|
|
404
|
+
function recordLineRangeFromContext(ctx, input, _startHint, end) {
|
|
405
|
+
if (!ctx.trackLines) return;
|
|
406
|
+
const from = ctx._lineScannedTo ?? 0;
|
|
407
|
+
if (end <= from) return;
|
|
408
|
+
const index = ctx._lineIndex ?? (ctx._lineStarts ? { lineStarts: ctx._lineStarts } : void 0);
|
|
409
|
+
if (!index) return;
|
|
410
|
+
recordLineRange(index, input, from, end);
|
|
411
|
+
ctx._lineScannedTo = end;
|
|
412
|
+
}
|
|
413
|
+
function normalizeLineIndex(index) {
|
|
414
|
+
const starts = index.lineStarts;
|
|
415
|
+
starts.sort((a, b) => a - b);
|
|
416
|
+
let write = 0;
|
|
417
|
+
for (let read = 0; read < starts.length; read++) {
|
|
418
|
+
const value = starts[read];
|
|
419
|
+
if (write === 0 || starts[write - 1] !== value) starts[write++] = value;
|
|
468
420
|
}
|
|
469
|
-
|
|
470
|
-
|
|
421
|
+
starts.length = write;
|
|
422
|
+
if (starts.length === 0 || starts[0] !== 0) starts.unshift(0);
|
|
423
|
+
return index;
|
|
424
|
+
}
|
|
425
|
+
function offsetToLineCol(index, offset) {
|
|
426
|
+
const { lineStarts } = index;
|
|
427
|
+
let lo = 0;
|
|
428
|
+
let hi = lineStarts.length - 1;
|
|
429
|
+
while (lo < hi) {
|
|
430
|
+
const mid = lo + hi + 1 >> 1;
|
|
431
|
+
if (lineStarts[mid] <= offset) lo = mid;
|
|
432
|
+
else hi = mid - 1;
|
|
471
433
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
return
|
|
434
|
+
return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
|
|
435
|
+
}
|
|
436
|
+
function annotateSpan(span, index) {
|
|
437
|
+
const s = offsetToLineCol(index, span.start);
|
|
438
|
+
const e = offsetToLineCol(index, span.end);
|
|
439
|
+
return {
|
|
440
|
+
...span,
|
|
441
|
+
startLine: s.line,
|
|
442
|
+
startColumn: s.col,
|
|
443
|
+
endLine: e.line,
|
|
444
|
+
endColumn: e.col
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
function annotateSpanFromLineContext(span, ctx) {
|
|
448
|
+
if (!ctx.trackLines) return span;
|
|
449
|
+
const index = ctx._lineIndex ?? (ctx._lineStarts ? { lineStarts: ctx._lineStarts } : void 0);
|
|
450
|
+
return index ? annotateSpan(span, index) : span;
|
|
478
451
|
}
|
|
479
452
|
|
|
480
453
|
// src/cst/capture-buffer.ts
|
|
@@ -518,7 +491,12 @@ function endCstNodeCapture(ctx, saved) {
|
|
|
518
491
|
return materialized;
|
|
519
492
|
}
|
|
520
493
|
function pushCstLeaf(ctx, leaf2) {
|
|
521
|
-
|
|
494
|
+
if (!ctx.trackLines) {
|
|
495
|
+
pushCstChild(ctx, leaf2, leaf2);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
const annotated = leaf2 && typeof leaf2 === "object" && leaf2.span ? { ...leaf2, span: annotateSpanFromLineContext(leaf2.span, ctx) } : leaf2;
|
|
499
|
+
pushCstChild(ctx, annotated, annotated);
|
|
522
500
|
}
|
|
523
501
|
function pushCstChild(ctx, built, rawEntry) {
|
|
524
502
|
const b = ctx._cstBuf;
|
|
@@ -708,7 +686,9 @@ function firstSetSentinel(fs) {
|
|
|
708
686
|
function recoverScan(input, from, ctx, sync, expected) {
|
|
709
687
|
let scanPos = from;
|
|
710
688
|
while (scanPos < input.length && !probeAt(sync, input, scanPos, ctx)) scanPos++;
|
|
711
|
-
const
|
|
689
|
+
const span = { start: from, end: scanPos };
|
|
690
|
+
if (ctx.trackLines) recordLineRangeFromContext(ctx, input, from, scanPos);
|
|
691
|
+
const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
|
|
712
692
|
ctx._errors?.push(error);
|
|
713
693
|
return { error, end: scanPos };
|
|
714
694
|
}
|
|
@@ -810,7 +790,8 @@ function expect(combinator, label2) {
|
|
|
810
790
|
parse(input, pos, ctx) {
|
|
811
791
|
const result = combinator.parse(input, pos, ctx);
|
|
812
792
|
if (result.ok) return result;
|
|
813
|
-
const
|
|
793
|
+
const span = { start: pos, end: pos };
|
|
794
|
+
const error = { _tag: "parseError", span: ctx.trackLines ? annotateSpanFromLineContext(span, ctx) : span, expected };
|
|
814
795
|
ctx._errors?.push(error);
|
|
815
796
|
if (ctx._tolerant) captureError(ctx, error);
|
|
816
797
|
return { ok: true, value: error, span: { start: pos, end: pos } };
|
|
@@ -1081,34 +1062,329 @@ function codesToFirstSet(codes) {
|
|
|
1081
1062
|
lo = hi = codes[i];
|
|
1082
1063
|
}
|
|
1083
1064
|
}
|
|
1084
|
-
ranges.push({ lo, hi });
|
|
1085
|
-
return { kind: "ranges", ranges };
|
|
1086
|
-
}
|
|
1087
|
-
function inFirstSet(code, fs) {
|
|
1088
|
-
if (fs.kind === "any") return true;
|
|
1089
|
-
if (fs.kind === "empty") return false;
|
|
1090
|
-
for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
1091
|
-
return false;
|
|
1092
|
-
}
|
|
1093
|
-
function areDisjoint(sets) {
|
|
1094
|
-
if (sets.some((s) => s.kind === "any")) return false;
|
|
1095
|
-
for (let i = 0; i < sets.length; i++)
|
|
1096
|
-
for (let j2 = i + 1; j2 < sets.length; j2++)
|
|
1097
|
-
if (intersects(sets[i], sets[j2])) return false;
|
|
1098
|
-
return true;
|
|
1099
|
-
}
|
|
1100
|
-
function buildAsciiDispatch(parsers) {
|
|
1101
|
-
const table = Array(128).fill(-1);
|
|
1102
|
-
for (let i = 0; i < parsers.length; i++) {
|
|
1103
|
-
const fs = parsers[i]._meta.firstSet;
|
|
1104
|
-
if (fs.kind !== "ranges") continue;
|
|
1105
|
-
for (const { lo, hi } of fs.ranges) {
|
|
1106
|
-
for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
|
|
1107
|
-
table[code] = i;
|
|
1065
|
+
ranges.push({ lo, hi });
|
|
1066
|
+
return { kind: "ranges", ranges };
|
|
1067
|
+
}
|
|
1068
|
+
function inFirstSet(code, fs) {
|
|
1069
|
+
if (fs.kind === "any") return true;
|
|
1070
|
+
if (fs.kind === "empty") return false;
|
|
1071
|
+
for (const r of fs.ranges) if (code >= r.lo && code <= r.hi) return true;
|
|
1072
|
+
return false;
|
|
1073
|
+
}
|
|
1074
|
+
function areDisjoint(sets) {
|
|
1075
|
+
if (sets.some((s) => s.kind === "any")) return false;
|
|
1076
|
+
for (let i = 0; i < sets.length; i++)
|
|
1077
|
+
for (let j2 = i + 1; j2 < sets.length; j2++)
|
|
1078
|
+
if (intersects(sets[i], sets[j2])) return false;
|
|
1079
|
+
return true;
|
|
1080
|
+
}
|
|
1081
|
+
function buildAsciiDispatch(parsers) {
|
|
1082
|
+
const table = Array(128).fill(-1);
|
|
1083
|
+
for (let i = 0; i < parsers.length; i++) {
|
|
1084
|
+
const fs = parsers[i]._meta.firstSet;
|
|
1085
|
+
if (fs.kind !== "ranges") continue;
|
|
1086
|
+
for (const { lo, hi } of fs.ranges) {
|
|
1087
|
+
for (let code = Math.max(0, lo); code <= Math.min(127, hi); code++) {
|
|
1088
|
+
table[code] = i;
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
return table;
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// src/cst/trivia-kinds.ts
|
|
1096
|
+
function unwrapTrivia(p) {
|
|
1097
|
+
let cur = p;
|
|
1098
|
+
while (cur._def.tag === "trivia") cur = cur._def.parser;
|
|
1099
|
+
return cur;
|
|
1100
|
+
}
|
|
1101
|
+
function peelLabel(p) {
|
|
1102
|
+
if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
|
|
1103
|
+
return null;
|
|
1104
|
+
}
|
|
1105
|
+
function analyzeLabeledTrivia(trivia2) {
|
|
1106
|
+
let core = unwrapTrivia(trivia2);
|
|
1107
|
+
let minRepeats = 1;
|
|
1108
|
+
if (core._def.tag === "oneOrMore") {
|
|
1109
|
+
core = core._def.parser;
|
|
1110
|
+
minRepeats = 1;
|
|
1111
|
+
} else if (core._def.tag === "many") {
|
|
1112
|
+
core = core._def.parser;
|
|
1113
|
+
minRepeats = 0;
|
|
1114
|
+
}
|
|
1115
|
+
const arms = [];
|
|
1116
|
+
if (core._def.tag === "choice") {
|
|
1117
|
+
for (let i = 0; i < core._def.parsers.length; i++) {
|
|
1118
|
+
const peeled = peelLabel(core._def.parsers[i]);
|
|
1119
|
+
if (!peeled) return null;
|
|
1120
|
+
arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
|
|
1121
|
+
}
|
|
1122
|
+
} else {
|
|
1123
|
+
const peeled = peelLabel(core);
|
|
1124
|
+
if (!peeled) return null;
|
|
1125
|
+
arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
|
|
1126
|
+
}
|
|
1127
|
+
return { labels: arms.map((a) => a.label), arms, minRepeats };
|
|
1128
|
+
}
|
|
1129
|
+
function matchArmAt(input, pos, arm) {
|
|
1130
|
+
const r = arm.parse(input, pos, { trackLines: false });
|
|
1131
|
+
if (!r.ok || r.span.end <= pos) return null;
|
|
1132
|
+
return { end: r.span.end };
|
|
1133
|
+
}
|
|
1134
|
+
function scanLabeledTriviaChunks(input, cur, spec) {
|
|
1135
|
+
const chunks = [];
|
|
1136
|
+
let pos = cur;
|
|
1137
|
+
while (pos < input.length) {
|
|
1138
|
+
let matched = null;
|
|
1139
|
+
for (const arm of spec.arms) {
|
|
1140
|
+
const m = matchArmAt(input, pos, arm.parser);
|
|
1141
|
+
if (m) {
|
|
1142
|
+
matched = { end: m.end, kindIndex: arm.kindIndex };
|
|
1143
|
+
break;
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
if (!matched) break;
|
|
1147
|
+
chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
|
|
1148
|
+
pos = matched.end;
|
|
1149
|
+
}
|
|
1150
|
+
if (chunks.length < spec.minRepeats) {
|
|
1151
|
+
return { end: cur, chunks: [] };
|
|
1152
|
+
}
|
|
1153
|
+
return { end: pos, chunks };
|
|
1154
|
+
}
|
|
1155
|
+
function scanFastWsCommentsChunks(input, cur, wsKind, commentKind) {
|
|
1156
|
+
const chunks = [];
|
|
1157
|
+
let pos = cur;
|
|
1158
|
+
while (pos < input.length) {
|
|
1159
|
+
const c = input.charCodeAt(pos);
|
|
1160
|
+
if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {
|
|
1161
|
+
const start = pos;
|
|
1162
|
+
pos++;
|
|
1163
|
+
while (pos < input.length) {
|
|
1164
|
+
const c2 = input.charCodeAt(pos);
|
|
1165
|
+
if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) pos++;
|
|
1166
|
+
else break;
|
|
1167
|
+
}
|
|
1168
|
+
chunks.push({ start, end: pos, kindIndex: wsKind });
|
|
1169
|
+
continue;
|
|
1170
|
+
}
|
|
1171
|
+
if (c === 47 && input.charCodeAt(pos + 1) === 42) {
|
|
1172
|
+
let j2 = pos + 2;
|
|
1173
|
+
while (j2 + 1 < input.length && !(input.charCodeAt(j2) === 42 && input.charCodeAt(j2 + 1) === 47)) j2++;
|
|
1174
|
+
if (j2 + 1 < input.length && input.charCodeAt(j2) === 42 && input.charCodeAt(j2 + 1) === 47) {
|
|
1175
|
+
const start = pos;
|
|
1176
|
+
pos = j2 + 2;
|
|
1177
|
+
chunks.push({ start, end: pos, kindIndex: commentKind });
|
|
1178
|
+
continue;
|
|
1179
|
+
}
|
|
1180
|
+
break;
|
|
1181
|
+
}
|
|
1182
|
+
break;
|
|
1183
|
+
}
|
|
1184
|
+
return { end: pos, chunks };
|
|
1185
|
+
}
|
|
1186
|
+
function tryFastLabeledScan(input, cur, trivia2) {
|
|
1187
|
+
const spec = analyzeLabeledTrivia(trivia2);
|
|
1188
|
+
if (!spec || spec.arms.length !== 2) return null;
|
|
1189
|
+
const wsArm = spec.arms.find((a) => {
|
|
1190
|
+
const src = getCoreRegexDef(a.parser)?.source;
|
|
1191
|
+
return src != null && !src.includes("\\*");
|
|
1192
|
+
});
|
|
1193
|
+
const commentArm = spec.arms.find((a) => {
|
|
1194
|
+
const src = getCoreRegexDef(a.parser)?.source;
|
|
1195
|
+
return src != null && src.includes("\\*");
|
|
1196
|
+
});
|
|
1197
|
+
if (!wsArm || !commentArm) return null;
|
|
1198
|
+
const { chunks } = scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
|
|
1199
|
+
if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
|
|
1200
|
+
return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
|
|
1201
|
+
}
|
|
1202
|
+
function recordTriviaChunks(ctx, chunks) {
|
|
1203
|
+
const kinds = ctx.triviaKindLabels;
|
|
1204
|
+
const mask = ctx._triviaCaptureMask;
|
|
1205
|
+
for (const ch of chunks) {
|
|
1206
|
+
pushTriviaLogEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
1207
|
+
if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
|
|
1208
|
+
if (mask === void 0 || kinds === void 0 || (mask & 1 << ch.kindIndex) !== 0) {
|
|
1209
|
+
pushCstTriviaEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
function triviaKindMask(labels, keep) {
|
|
1215
|
+
if (!labels) return void 0;
|
|
1216
|
+
let mask = 0;
|
|
1217
|
+
for (const name of keep) {
|
|
1218
|
+
const idx = labels.indexOf(name);
|
|
1219
|
+
if (idx >= 0) mask |= 1 << idx;
|
|
1220
|
+
}
|
|
1221
|
+
return mask;
|
|
1222
|
+
}
|
|
1223
|
+
|
|
1224
|
+
// src/combinators/grammar.ts
|
|
1225
|
+
function annotateResultLines(result, index) {
|
|
1226
|
+
const annotated = { ...result, span: annotateSpan(result.span, index) };
|
|
1227
|
+
const errors = annotated.errors;
|
|
1228
|
+
if (errors) {
|
|
1229
|
+
;
|
|
1230
|
+
annotated.errors = errors.map((error) => ({
|
|
1231
|
+
...error,
|
|
1232
|
+
span: annotateSpan(error.span, index)
|
|
1233
|
+
}));
|
|
1234
|
+
}
|
|
1235
|
+
return annotated;
|
|
1236
|
+
}
|
|
1237
|
+
function createParseLineContext(input, pos) {
|
|
1238
|
+
const lineIndex = createLineIndex();
|
|
1239
|
+
if (pos > 0) recordLineRange(lineIndex, input, 0, pos);
|
|
1240
|
+
return { lineIndex, lineScannedTo: pos };
|
|
1241
|
+
}
|
|
1242
|
+
function parser(opts, root) {
|
|
1243
|
+
const clearTrivia = opts.trivia === null;
|
|
1244
|
+
return {
|
|
1245
|
+
_tag: "grammar",
|
|
1246
|
+
_meta: root._meta,
|
|
1247
|
+
_def: {
|
|
1248
|
+
tag: "grammar",
|
|
1249
|
+
parser: root,
|
|
1250
|
+
triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
|
|
1251
|
+
clearTrivia,
|
|
1252
|
+
...opts.captureTrivia ? { captureTrivia: true } : {},
|
|
1253
|
+
trackLines: opts.trackLines ?? false
|
|
1254
|
+
},
|
|
1255
|
+
parse(input, pos, _ctx) {
|
|
1256
|
+
const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
|
|
1257
|
+
const lineContext = trackLines && _ctx?._lineIndex === void 0 && _ctx?._lineStarts === void 0 ? createParseLineContext(input, pos ?? 0) : void 0;
|
|
1258
|
+
const lineIndex = trackLines ? _ctx?._lineIndex ?? (_ctx?._lineStarts ? { lineStarts: _ctx._lineStarts } : lineContext.lineIndex) : void 0;
|
|
1259
|
+
const ctx = {
|
|
1260
|
+
..._ctx,
|
|
1261
|
+
trackLines,
|
|
1262
|
+
...lineIndex ? { _lineIndex: lineIndex } : {},
|
|
1263
|
+
...lineContext ? { _lineScannedTo: lineContext.lineScannedTo } : {},
|
|
1264
|
+
// trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
|
|
1265
|
+
...clearTrivia ? {
|
|
1266
|
+
trivia: void 0,
|
|
1267
|
+
triviaKindLabels: void 0
|
|
1268
|
+
} : opts.trivia != null ? {
|
|
1269
|
+
trivia: opts.trivia,
|
|
1270
|
+
...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
|
|
1271
|
+
} : {},
|
|
1272
|
+
...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
|
|
1273
|
+
// Kind-filter for per-node capture. Resolve against this scope's trivia
|
|
1274
|
+
// labels — this parser's own trivia if it declares one, else the INHERITED
|
|
1275
|
+
// labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
|
|
1276
|
+
// trivia is inherited rather than re-declared here. No labels → undefined
|
|
1277
|
+
// (capture all).
|
|
1278
|
+
...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
|
|
1279
|
+
};
|
|
1280
|
+
const result = root.parse(input, pos ?? 0, ctx);
|
|
1281
|
+
if (trackLines && _ctx && ctx._lineScannedTo !== void 0) {
|
|
1282
|
+
_ctx._lineScannedTo = Math.max(_ctx._lineScannedTo ?? 0, ctx._lineScannedTo);
|
|
1283
|
+
}
|
|
1284
|
+
return lineIndex ? annotateResultLines(result, normalizeLineIndex(lineIndex)) : result;
|
|
1285
|
+
}
|
|
1286
|
+
};
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
// src/combinators/parser.ts
|
|
1290
|
+
var RULE_ORDER = "__parsemanRuleOrder";
|
|
1291
|
+
function tagRule(r, key) {
|
|
1292
|
+
;
|
|
1293
|
+
r._ruleName = key;
|
|
1294
|
+
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
|
|
1295
|
+
}
|
|
1296
|
+
function isDefinableRef(v) {
|
|
1297
|
+
return !!v && typeof v === "object" && "_def" in v && v._def.tag === "lazy" && typeof v.define === "function";
|
|
1298
|
+
}
|
|
1299
|
+
function ruleNameOf(r) {
|
|
1300
|
+
return r._ruleName;
|
|
1301
|
+
}
|
|
1302
|
+
function isNamedRuleRefForAnotherRule(r, key) {
|
|
1303
|
+
const name = r._def.tag === "lazy" ? ruleNameOf(r) : void 0;
|
|
1304
|
+
return name !== void 0 && name !== key;
|
|
1305
|
+
}
|
|
1306
|
+
function rules(a, b) {
|
|
1307
|
+
const factory = typeof a === "function" ? a : b;
|
|
1308
|
+
const options = typeof a === "function" ? b : a;
|
|
1309
|
+
const cache = {};
|
|
1310
|
+
const proxy = new Proxy(cache, {
|
|
1311
|
+
get(target, key) {
|
|
1312
|
+
if (typeof key !== "string") return void 0;
|
|
1313
|
+
const record = target;
|
|
1314
|
+
if (!(key in record)) {
|
|
1315
|
+
const r = ref();
|
|
1316
|
+
tagRule(r, key);
|
|
1317
|
+
record[key] = r;
|
|
1318
|
+
}
|
|
1319
|
+
return record[key];
|
|
1320
|
+
}
|
|
1321
|
+
});
|
|
1322
|
+
const definitions = factory(proxy);
|
|
1323
|
+
for (const key of Object.keys(definitions)) {
|
|
1324
|
+
const placeholder = cache[key];
|
|
1325
|
+
const parser2 = definitions[key];
|
|
1326
|
+
if (placeholder === parser2) {
|
|
1327
|
+
throw new Error(`rules(): rule "${key}" cannot be a direct alias to itself`);
|
|
1328
|
+
}
|
|
1329
|
+
if (isDefinableRef(placeholder)) {
|
|
1330
|
+
if (!isNamedRuleRefForAnotherRule(parser2, key)) tagRule(parser2, key);
|
|
1331
|
+
placeholder.define(parser2);
|
|
1332
|
+
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
1333
|
+
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
1334
|
+
} else if (isNamedRuleRefForAnotherRule(parser2, key)) {
|
|
1335
|
+
const alias = ref();
|
|
1336
|
+
tagRule(alias, key);
|
|
1337
|
+
alias.define(parser2);
|
|
1338
|
+
alias._meta.firstSet = parser2._meta.firstSet;
|
|
1339
|
+
alias._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
1340
|
+
cache[key] = alias;
|
|
1341
|
+
} else {
|
|
1342
|
+
tagRule(parser2, key);
|
|
1343
|
+
cache[key] = parser2;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
if (options?.trivia != null) {
|
|
1347
|
+
for (const key of Object.keys(definitions)) {
|
|
1348
|
+
const rule = cache[key];
|
|
1349
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrivia = options.trivia;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
if (options?.scanSkip != null) {
|
|
1353
|
+
for (const key of Object.keys(definitions)) {
|
|
1354
|
+
const rule = cache[key];
|
|
1355
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarScanSkip = options.scanSkip;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
if (options?.hostMode === "cst") {
|
|
1359
|
+
for (const key of Object.keys(definitions)) {
|
|
1360
|
+
const rule = cache[key];
|
|
1361
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarHostMode = "cst";
|
|
1362
|
+
}
|
|
1363
|
+
}
|
|
1364
|
+
if (options?.trackLines === true) {
|
|
1365
|
+
for (const key of Object.keys(definitions)) {
|
|
1366
|
+
const rule = cache[key];
|
|
1367
|
+
if (rule && !rule._meta.isTrivia) rule._meta.grammarTrackLines = true;
|
|
1368
|
+
}
|
|
1369
|
+
for (const key of Object.keys(definitions)) {
|
|
1370
|
+
const rule = cache[key];
|
|
1371
|
+
if (rule && !rule._meta.isTrivia && rule._def.tag !== "grammar") {
|
|
1372
|
+
const wrapped = parser({ trackLines: true }, rule);
|
|
1373
|
+
tagRule(wrapped, key);
|
|
1374
|
+
wrapped._meta.grammarTrackLines = true;
|
|
1375
|
+
cache[key] = wrapped;
|
|
1108
1376
|
}
|
|
1109
1377
|
}
|
|
1110
1378
|
}
|
|
1111
|
-
|
|
1379
|
+
for (const key of Object.keys(definitions)) {
|
|
1380
|
+
markUnusedValues(cache[key]);
|
|
1381
|
+
}
|
|
1382
|
+
Object.defineProperty(cache, RULE_ORDER, {
|
|
1383
|
+
value: Object.keys(definitions),
|
|
1384
|
+
enumerable: false,
|
|
1385
|
+
configurable: true
|
|
1386
|
+
});
|
|
1387
|
+
return cache;
|
|
1112
1388
|
}
|
|
1113
1389
|
|
|
1114
1390
|
// src/analysis/duplication.ts
|
|
@@ -1150,6 +1426,7 @@ function literal(value, opts = {}) {
|
|
|
1150
1426
|
canMatchNewline: value.includes("\n"),
|
|
1151
1427
|
isTrivia: false
|
|
1152
1428
|
};
|
|
1429
|
+
const canMatchNewline = meta.canMatchNewline;
|
|
1153
1430
|
if (caseInsensitive) {
|
|
1154
1431
|
const upper = value.toUpperCase();
|
|
1155
1432
|
const lower = value.toLowerCase();
|
|
@@ -1166,6 +1443,7 @@ function literal(value, opts = {}) {
|
|
|
1166
1443
|
return function parse2(input, pos, ctx) {
|
|
1167
1444
|
if (input.charCodeAt(pos) === code) {
|
|
1168
1445
|
const span = { start: pos, end: pos + 1 };
|
|
1446
|
+
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
|
|
1169
1447
|
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span });
|
|
1170
1448
|
return { ok: true, value, span };
|
|
1171
1449
|
}
|
|
@@ -1179,6 +1457,7 @@ function literal(value, opts = {}) {
|
|
|
1179
1457
|
const matchedValue = caseInsensitive ? input.slice(pos, end) : value;
|
|
1180
1458
|
if (caseInsensitive ? asciiFoldEq(matchedValue, value) : input.startsWith(value, pos)) {
|
|
1181
1459
|
const span = { start: pos, end };
|
|
1460
|
+
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, end);
|
|
1182
1461
|
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: matchedValue, span });
|
|
1183
1462
|
return { ok: true, value: matchedValue, span };
|
|
1184
1463
|
}
|
|
@@ -1343,6 +1622,7 @@ function regex(pattern, flags = "") {
|
|
|
1343
1622
|
if (scanEnd === null) return failAt(ctx, [`/${source}/`], pos);
|
|
1344
1623
|
const value = input.slice(pos, scanEnd);
|
|
1345
1624
|
const span2 = { start: pos, end: scanEnd };
|
|
1625
|
+
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, scanEnd);
|
|
1346
1626
|
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value, span: span2 });
|
|
1347
1627
|
return { ok: true, value, span: span2 };
|
|
1348
1628
|
}
|
|
@@ -1352,141 +1632,13 @@ function regex(pattern, flags = "") {
|
|
|
1352
1632
|
return failAt(ctx, [`/${source}/`], pos);
|
|
1353
1633
|
}
|
|
1354
1634
|
const span = { start: pos, end: pos + m[0].length };
|
|
1635
|
+
if (canMatchNewline && ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, span.end);
|
|
1355
1636
|
if (cstCaptureActive(ctx)) pushCstLeaf(ctx, { _tag: "leaf", value: m[0], span });
|
|
1356
1637
|
return { ok: true, value: m[0], span };
|
|
1357
1638
|
}
|
|
1358
1639
|
};
|
|
1359
1640
|
}
|
|
1360
1641
|
|
|
1361
|
-
// src/cst/trivia-kinds.ts
|
|
1362
|
-
function unwrapTrivia(p) {
|
|
1363
|
-
let cur = p;
|
|
1364
|
-
while (cur._def.tag === "trivia") cur = cur._def.parser;
|
|
1365
|
-
return cur;
|
|
1366
|
-
}
|
|
1367
|
-
function peelLabel(p) {
|
|
1368
|
-
if (p._def.tag === "label") return { label: p._def.label, parser: p._def.parser };
|
|
1369
|
-
return null;
|
|
1370
|
-
}
|
|
1371
|
-
function analyzeLabeledTrivia(trivia2) {
|
|
1372
|
-
let core = unwrapTrivia(trivia2);
|
|
1373
|
-
let minRepeats = 1;
|
|
1374
|
-
if (core._def.tag === "oneOrMore") {
|
|
1375
|
-
core = core._def.parser;
|
|
1376
|
-
minRepeats = 1;
|
|
1377
|
-
} else if (core._def.tag === "many") {
|
|
1378
|
-
core = core._def.parser;
|
|
1379
|
-
minRepeats = 0;
|
|
1380
|
-
}
|
|
1381
|
-
const arms = [];
|
|
1382
|
-
if (core._def.tag === "choice") {
|
|
1383
|
-
for (let i = 0; i < core._def.parsers.length; i++) {
|
|
1384
|
-
const peeled = peelLabel(core._def.parsers[i]);
|
|
1385
|
-
if (!peeled) return null;
|
|
1386
|
-
arms.push({ label: peeled.label, kindIndex: i, parser: peeled.parser });
|
|
1387
|
-
}
|
|
1388
|
-
} else {
|
|
1389
|
-
const peeled = peelLabel(core);
|
|
1390
|
-
if (!peeled) return null;
|
|
1391
|
-
arms.push({ label: peeled.label, kindIndex: 0, parser: peeled.parser });
|
|
1392
|
-
}
|
|
1393
|
-
return { labels: arms.map((a) => a.label), arms, minRepeats };
|
|
1394
|
-
}
|
|
1395
|
-
function matchArmAt(input, pos, arm) {
|
|
1396
|
-
const r = arm.parse(input, pos, { trackLines: false });
|
|
1397
|
-
if (!r.ok || r.span.end <= pos) return null;
|
|
1398
|
-
return { end: r.span.end };
|
|
1399
|
-
}
|
|
1400
|
-
function scanLabeledTriviaChunks(input, cur, spec) {
|
|
1401
|
-
const chunks = [];
|
|
1402
|
-
let pos = cur;
|
|
1403
|
-
while (pos < input.length) {
|
|
1404
|
-
let matched = null;
|
|
1405
|
-
for (const arm of spec.arms) {
|
|
1406
|
-
const m = matchArmAt(input, pos, arm.parser);
|
|
1407
|
-
if (m) {
|
|
1408
|
-
matched = { end: m.end, kindIndex: arm.kindIndex };
|
|
1409
|
-
break;
|
|
1410
|
-
}
|
|
1411
|
-
}
|
|
1412
|
-
if (!matched) break;
|
|
1413
|
-
chunks.push({ start: pos, end: matched.end, kindIndex: matched.kindIndex });
|
|
1414
|
-
pos = matched.end;
|
|
1415
|
-
}
|
|
1416
|
-
if (chunks.length < spec.minRepeats) {
|
|
1417
|
-
return { end: cur, chunks: [] };
|
|
1418
|
-
}
|
|
1419
|
-
return { end: pos, chunks };
|
|
1420
|
-
}
|
|
1421
|
-
function scanFastWsCommentsChunks(input, cur, wsKind, commentKind) {
|
|
1422
|
-
const chunks = [];
|
|
1423
|
-
let pos = cur;
|
|
1424
|
-
while (pos < input.length) {
|
|
1425
|
-
const c = input.charCodeAt(pos);
|
|
1426
|
-
if (c === 32 || c === 9 || c === 10 || c === 13 || c === 12) {
|
|
1427
|
-
const start = pos;
|
|
1428
|
-
pos++;
|
|
1429
|
-
while (pos < input.length) {
|
|
1430
|
-
const c2 = input.charCodeAt(pos);
|
|
1431
|
-
if (c2 === 32 || c2 === 9 || c2 === 10 || c2 === 13 || c2 === 12) pos++;
|
|
1432
|
-
else break;
|
|
1433
|
-
}
|
|
1434
|
-
chunks.push({ start, end: pos, kindIndex: wsKind });
|
|
1435
|
-
continue;
|
|
1436
|
-
}
|
|
1437
|
-
if (c === 47 && input.charCodeAt(pos + 1) === 42) {
|
|
1438
|
-
let j2 = pos + 2;
|
|
1439
|
-
while (j2 + 1 < input.length && !(input.charCodeAt(j2) === 42 && input.charCodeAt(j2 + 1) === 47)) j2++;
|
|
1440
|
-
if (j2 + 1 < input.length && input.charCodeAt(j2) === 42 && input.charCodeAt(j2 + 1) === 47) {
|
|
1441
|
-
const start = pos;
|
|
1442
|
-
pos = j2 + 2;
|
|
1443
|
-
chunks.push({ start, end: pos, kindIndex: commentKind });
|
|
1444
|
-
continue;
|
|
1445
|
-
}
|
|
1446
|
-
break;
|
|
1447
|
-
}
|
|
1448
|
-
break;
|
|
1449
|
-
}
|
|
1450
|
-
return { end: pos, chunks };
|
|
1451
|
-
}
|
|
1452
|
-
function tryFastLabeledScan(input, cur, trivia2) {
|
|
1453
|
-
const spec = analyzeLabeledTrivia(trivia2);
|
|
1454
|
-
if (!spec || spec.arms.length !== 2) return null;
|
|
1455
|
-
const wsArm = spec.arms.find((a) => {
|
|
1456
|
-
const src = getCoreRegexDef(a.parser)?.source;
|
|
1457
|
-
return src != null && !src.includes("\\*");
|
|
1458
|
-
});
|
|
1459
|
-
const commentArm = spec.arms.find((a) => {
|
|
1460
|
-
const src = getCoreRegexDef(a.parser)?.source;
|
|
1461
|
-
return src != null && src.includes("\\*");
|
|
1462
|
-
});
|
|
1463
|
-
if (!wsArm || !commentArm) return null;
|
|
1464
|
-
const { chunks } = scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
|
|
1465
|
-
if (chunks.length < spec.minRepeats) return { end: cur, chunks: [] };
|
|
1466
|
-
return scanFastWsCommentsChunks(input, cur, wsArm.kindIndex, commentArm.kindIndex);
|
|
1467
|
-
}
|
|
1468
|
-
function recordTriviaChunks(ctx, chunks) {
|
|
1469
|
-
const kinds = ctx.triviaKindLabels;
|
|
1470
|
-
const mask = ctx._triviaCaptureMask;
|
|
1471
|
-
for (const ch of chunks) {
|
|
1472
|
-
pushTriviaLogEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
1473
|
-
if (ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0)) {
|
|
1474
|
-
if (mask === void 0 || kinds === void 0 || (mask & 1 << ch.kindIndex) !== 0) {
|
|
1475
|
-
pushCstTriviaEntry(ctx, ch.start, ch.end, kinds ? ch.kindIndex : void 0);
|
|
1476
|
-
}
|
|
1477
|
-
}
|
|
1478
|
-
}
|
|
1479
|
-
}
|
|
1480
|
-
function triviaKindMask(labels, keep) {
|
|
1481
|
-
if (!labels) return void 0;
|
|
1482
|
-
let mask = 0;
|
|
1483
|
-
for (const name of keep) {
|
|
1484
|
-
const idx = labels.indexOf(name);
|
|
1485
|
-
if (idx >= 0) mask |= 1 << idx;
|
|
1486
|
-
}
|
|
1487
|
-
return mask;
|
|
1488
|
-
}
|
|
1489
|
-
|
|
1490
1642
|
// src/combinators/trivia-skip.ts
|
|
1491
1643
|
var NOOP_COMMIT = () => {
|
|
1492
1644
|
};
|
|
@@ -1502,6 +1654,18 @@ function rollbackTrivia(ctx, mark) {
|
|
|
1502
1654
|
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields, errors: mark.errors });
|
|
1503
1655
|
if (ctx._triviaLog && ctx._triviaLog.length !== mark.log) ctx._triviaLog.length = mark.log;
|
|
1504
1656
|
}
|
|
1657
|
+
function parseTriviaNoCapture(triviaP, input, cur, ctx) {
|
|
1658
|
+
const probeCtx = {
|
|
1659
|
+
trackLines: ctx.trackLines,
|
|
1660
|
+
state: ctx.state,
|
|
1661
|
+
...ctx._lineIndex ? { _lineIndex: ctx._lineIndex } : {},
|
|
1662
|
+
...ctx._lineStarts ? { _lineStarts: ctx._lineStarts } : {},
|
|
1663
|
+
...ctx._lineScannedTo !== void 0 ? { _lineScannedTo: ctx._lineScannedTo } : {}
|
|
1664
|
+
};
|
|
1665
|
+
const result = triviaP.parse(input, cur, probeCtx);
|
|
1666
|
+
ctx._lineScannedTo = probeCtx._lineScannedTo;
|
|
1667
|
+
return result;
|
|
1668
|
+
}
|
|
1505
1669
|
function saveLookaheadMark(ctx) {
|
|
1506
1670
|
return { ...saveTriviaMark(ctx), probeBest: ctx._probe ? ctx._probe.best : null };
|
|
1507
1671
|
}
|
|
@@ -1524,13 +1688,29 @@ function scanWithLabels(input, cur, ctx) {
|
|
|
1524
1688
|
function advanceTrivia(input, cur, ctx) {
|
|
1525
1689
|
const triviaP = ctx.trivia;
|
|
1526
1690
|
if (!triviaP) return cur;
|
|
1691
|
+
if (!ctx.trackLines) {
|
|
1692
|
+
const fast2 = fastTriviaScanner(triviaP);
|
|
1693
|
+
if (fast2) return fast2(input, cur);
|
|
1694
|
+
if (ctx.triviaKindLabels) {
|
|
1695
|
+
const scan = scanWithLabels(input, cur, ctx);
|
|
1696
|
+
return scan.end;
|
|
1697
|
+
}
|
|
1698
|
+
const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1699
|
+
return tr2.ok && tr2.span.end > cur ? tr2.span.end : cur;
|
|
1700
|
+
}
|
|
1701
|
+
const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
|
|
1527
1702
|
const fast = fastTriviaScanner(triviaP);
|
|
1528
|
-
if (fast)
|
|
1703
|
+
if (fast) {
|
|
1704
|
+
const end = fast(input, cur);
|
|
1705
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1706
|
+
return end;
|
|
1707
|
+
}
|
|
1529
1708
|
if (ctx.triviaKindLabels) {
|
|
1530
1709
|
const scan = scanWithLabels(input, cur, ctx);
|
|
1710
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
|
|
1531
1711
|
return scan.end;
|
|
1532
1712
|
}
|
|
1533
|
-
const tr = triviaP
|
|
1713
|
+
const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
|
|
1534
1714
|
return tr.ok && tr.span.end > cur ? tr.span.end : cur;
|
|
1535
1715
|
}
|
|
1536
1716
|
function scanTrivia(input, cur, ctx) {
|
|
@@ -1538,18 +1718,46 @@ function scanTrivia(input, cur, ctx) {
|
|
|
1538
1718
|
if (!triviaP) return { end: cur, commit: NOOP_COMMIT };
|
|
1539
1719
|
const log = ctx._triviaLog;
|
|
1540
1720
|
const captureTl = ctx.captureTrivia && (ctx._cstBuf !== void 0 || ctx._cstTriviaLog !== void 0);
|
|
1721
|
+
if (!ctx.trackLines) {
|
|
1722
|
+
const fast2 = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
|
|
1723
|
+
if (fast2 && log === void 0 && !captureTl) {
|
|
1724
|
+
return { end: fast2(input, cur), commit: NOOP_COMMIT };
|
|
1725
|
+
}
|
|
1726
|
+
if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
|
|
1727
|
+
return scanWithLabels(input, cur, ctx);
|
|
1728
|
+
}
|
|
1729
|
+
if (log !== void 0 || captureTl) {
|
|
1730
|
+
const tr3 = triviaP.parse(input, cur, {
|
|
1731
|
+
trackLines: log !== void 0 ? false : ctx.trackLines,
|
|
1732
|
+
state: ctx.state
|
|
1733
|
+
});
|
|
1734
|
+
if (!tr3.ok || tr3.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1735
|
+
const end = tr3.span.end;
|
|
1736
|
+
return {
|
|
1737
|
+
end,
|
|
1738
|
+
commit: () => {
|
|
1739
|
+
pushTriviaLogEntry(ctx, cur, end);
|
|
1740
|
+
if (captureTl) pushCstTriviaEntry(ctx, cur, end);
|
|
1741
|
+
}
|
|
1742
|
+
};
|
|
1743
|
+
}
|
|
1744
|
+
const tr2 = triviaP.parse(input, cur, { trackLines: ctx.trackLines, state: ctx.state });
|
|
1745
|
+
return { end: tr2.ok ? tr2.span.end : cur, commit: NOOP_COMMIT };
|
|
1746
|
+
}
|
|
1747
|
+
const trackTriviaLines = ctx.trackLines && triviaP._meta.canMatchNewline;
|
|
1541
1748
|
const fast = !ctx.triviaKindLabels ? fastTriviaScanner(triviaP) : null;
|
|
1542
1749
|
if (fast && log === void 0 && !captureTl) {
|
|
1543
|
-
|
|
1750
|
+
const end = fast(input, cur);
|
|
1751
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, end);
|
|
1752
|
+
return { end, commit: NOOP_COMMIT };
|
|
1544
1753
|
}
|
|
1545
1754
|
if (ctx.triviaKindLabels && (log !== void 0 || captureTl)) {
|
|
1546
|
-
|
|
1755
|
+
const scan = scanWithLabels(input, cur, ctx);
|
|
1756
|
+
if (trackTriviaLines) recordLineRangeFromContext(ctx, input, cur, scan.end);
|
|
1757
|
+
return scan;
|
|
1547
1758
|
}
|
|
1548
1759
|
if (log !== void 0 || captureTl) {
|
|
1549
|
-
const tr2 = triviaP
|
|
1550
|
-
trackLines: log !== void 0 ? false : ctx.trackLines,
|
|
1551
|
-
state: ctx.state
|
|
1552
|
-
});
|
|
1760
|
+
const tr2 = parseTriviaNoCapture(triviaP, input, cur, ctx);
|
|
1553
1761
|
if (!tr2.ok || tr2.span.end === cur) return { end: cur, commit: NOOP_COMMIT };
|
|
1554
1762
|
const end = tr2.span.end;
|
|
1555
1763
|
return {
|
|
@@ -1560,7 +1768,7 @@ function scanTrivia(input, cur, ctx) {
|
|
|
1560
1768
|
}
|
|
1561
1769
|
};
|
|
1562
1770
|
}
|
|
1563
|
-
const tr = triviaP
|
|
1771
|
+
const tr = parseTriviaNoCapture(triviaP, input, cur, ctx);
|
|
1564
1772
|
return { end: tr.ok ? tr.span.end : cur, commit: NOOP_COMMIT };
|
|
1565
1773
|
}
|
|
1566
1774
|
function consumeTrivia(input, cur, ctx) {
|
|
@@ -2213,7 +2421,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
|
|
|
2213
2421
|
let cur = pos;
|
|
2214
2422
|
const skip3 = resolveScanSkip(explicitSkip, raw, ctx);
|
|
2215
2423
|
const probeCtx = {
|
|
2216
|
-
trackLines:
|
|
2424
|
+
trackLines: false,
|
|
2217
2425
|
state: ctx.state,
|
|
2218
2426
|
...ctx._errors !== void 0 ? { _errors: ctx._errors } : {}
|
|
2219
2427
|
};
|
|
@@ -2226,6 +2434,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
|
|
|
2226
2434
|
while (cur < input.length) {
|
|
2227
2435
|
const s = sentinel.parse(input, cur, probeCtx);
|
|
2228
2436
|
if (s.ok) {
|
|
2437
|
+
if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
|
|
2229
2438
|
emit(cur);
|
|
2230
2439
|
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
2231
2440
|
}
|
|
@@ -2241,6 +2450,7 @@ function scanTo(sentinel, { skip: skip2, raw = false, orEOF = false } = {}) {
|
|
|
2241
2450
|
if (!advanced) cur++;
|
|
2242
2451
|
}
|
|
2243
2452
|
if (orEOF) {
|
|
2453
|
+
if (ctx.trackLines) recordLineRangeFromContext(ctx, input, pos, cur);
|
|
2244
2454
|
emit(cur);
|
|
2245
2455
|
return { ok: true, value: input.slice(pos, cur), span: { start: pos, end: cur } };
|
|
2246
2456
|
}
|
|
@@ -2850,89 +3060,14 @@ function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
|
2850
3060
|
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
2851
3061
|
const nodeType = def.type ?? missingInferredType();
|
|
2852
3062
|
const cstOutput = cstOutputHost(ctx.build);
|
|
3063
|
+
const span = ctx.trackLines ? annotateSpanFromLineContext(r.span, ctx) : r.span;
|
|
2853
3064
|
const hostState = clonesState ? st : ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
2854
|
-
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,
|
|
2855
|
-
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
|
|
3065
|
+
const built = unwrap && children.length === 1 ? unwrapChild(children[0]) : collapse && children.length === 1 ? children[0] : !build && project === void 0 && ctx.build?._parsemanCstCollapse && children.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children[0], children, rawChildren) ? children[0] : project !== void 0 ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, hostState) : projectChild(children, project, nodeType) : build ? cstOutput && ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, hostState) : build(children, fields, span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children, fields, span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: ctx.trackLines ? { ...span } : { start: r.span.start, end: r.span.end }, state: st ?? null, children };
|
|
3066
|
+
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 };
|
|
2856
3067
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
2857
3068
|
pushCstChild(ctx, built, rawEntry);
|
|
2858
3069
|
}
|
|
2859
|
-
return { ok: true, value: built, span
|
|
2860
|
-
}
|
|
2861
|
-
};
|
|
2862
|
-
}
|
|
2863
|
-
|
|
2864
|
-
// src/compiler/line-index.ts
|
|
2865
|
-
function buildLineIndex(input) {
|
|
2866
|
-
const lineStarts = [0];
|
|
2867
|
-
for (let i = 0; i < input.length; i++) {
|
|
2868
|
-
if (input.charCodeAt(i) === 10) lineStarts.push(i + 1);
|
|
2869
|
-
}
|
|
2870
|
-
return { lineStarts };
|
|
2871
|
-
}
|
|
2872
|
-
function offsetToLineCol(index, offset) {
|
|
2873
|
-
const { lineStarts } = index;
|
|
2874
|
-
let lo = 0;
|
|
2875
|
-
let hi = lineStarts.length - 1;
|
|
2876
|
-
while (lo < hi) {
|
|
2877
|
-
const mid = lo + hi + 1 >> 1;
|
|
2878
|
-
if (lineStarts[mid] <= offset) lo = mid;
|
|
2879
|
-
else hi = mid - 1;
|
|
2880
|
-
}
|
|
2881
|
-
return { line: lo + 1, col: offset - lineStarts[lo] + 1 };
|
|
2882
|
-
}
|
|
2883
|
-
function annotateSpan(span, index) {
|
|
2884
|
-
const s = offsetToLineCol(index, span.start);
|
|
2885
|
-
const e = offsetToLineCol(index, span.end);
|
|
2886
|
-
return {
|
|
2887
|
-
...span,
|
|
2888
|
-
startLine: s.line,
|
|
2889
|
-
startColumn: s.col,
|
|
2890
|
-
endLine: e.line,
|
|
2891
|
-
endColumn: e.col
|
|
2892
|
-
};
|
|
2893
|
-
}
|
|
2894
|
-
|
|
2895
|
-
// src/combinators/grammar.ts
|
|
2896
|
-
function parser(opts, root) {
|
|
2897
|
-
const clearTrivia = opts.trivia === null;
|
|
2898
|
-
return {
|
|
2899
|
-
_tag: "grammar",
|
|
2900
|
-
_meta: root._meta,
|
|
2901
|
-
_def: {
|
|
2902
|
-
tag: "grammar",
|
|
2903
|
-
parser: root,
|
|
2904
|
-
triviaParser: clearTrivia ? void 0 : opts.trivia ?? void 0,
|
|
2905
|
-
clearTrivia,
|
|
2906
|
-
...opts.captureTrivia ? { captureTrivia: true } : {},
|
|
2907
|
-
trackLines: opts.trackLines ?? false
|
|
2908
|
-
},
|
|
2909
|
-
parse(input, pos, _ctx) {
|
|
2910
|
-
const trackLines = opts.trackLines ?? _ctx?.trackLines ?? false;
|
|
2911
|
-
const ctx = {
|
|
2912
|
-
..._ctx,
|
|
2913
|
-
trackLines,
|
|
2914
|
-
// trivia: null clears (contiguous terms); a Combinator sets; undefined inherits.
|
|
2915
|
-
...clearTrivia ? {
|
|
2916
|
-
trivia: void 0,
|
|
2917
|
-
triviaKindLabels: void 0
|
|
2918
|
-
} : opts.trivia != null ? {
|
|
2919
|
-
trivia: opts.trivia,
|
|
2920
|
-
...opts.trivia._meta.triviaKindLabels ? { triviaKindLabels: opts.trivia._meta.triviaKindLabels } : {}
|
|
2921
|
-
} : {},
|
|
2922
|
-
...opts.captureTrivia || _ctx?.captureTrivia ? { captureTrivia: true } : {},
|
|
2923
|
-
// Kind-filter for per-node capture. Resolve against this scope's trivia
|
|
2924
|
-
// labels — this parser's own trivia if it declares one, else the INHERITED
|
|
2925
|
-
// labels (`_ctx.triviaKindLabels`), so captureTriviaKinds still applies when
|
|
2926
|
-
// trivia is inherited rather than re-declared here. No labels → undefined
|
|
2927
|
-
// (capture all).
|
|
2928
|
-
...opts.captureTriviaKinds && !clearTrivia ? { _triviaCaptureMask: triviaKindMask(opts.trivia?._meta.triviaKindLabels ?? _ctx?.triviaKindLabels, opts.captureTriviaKinds) } : {}
|
|
2929
|
-
};
|
|
2930
|
-
const result = root.parse(input, pos ?? 0, ctx);
|
|
2931
|
-
if (trackLines) {
|
|
2932
|
-
const idx = buildLineIndex(input);
|
|
2933
|
-
return { ...result, span: annotateSpan(result.span, idx) };
|
|
2934
|
-
}
|
|
2935
|
-
return result;
|
|
3070
|
+
return { ok: true, value: built, span };
|
|
2936
3071
|
}
|
|
2937
3072
|
};
|
|
2938
3073
|
}
|
|
@@ -3220,7 +3355,7 @@ function normalizeCstCollapse(collapse) {
|
|
|
3220
3355
|
return typeof collapse === "function" ? collapse : void 0;
|
|
3221
3356
|
}
|
|
3222
3357
|
function buildCstNode(type, children, _fields, span, _rawChildren, _triviaLog, state) {
|
|
3223
|
-
return { _tag: "node", type, span: {
|
|
3358
|
+
return { _tag: "node", type, span: { ...span }, state: state ?? null, children: [...children] };
|
|
3224
3359
|
}
|
|
3225
3360
|
function cstBuildHost(typeOrOptions, children, _fields, span, rawChildren, triviaLog, state) {
|
|
3226
3361
|
if (typeof typeOrOptions === "string") {
|