parseman 0.18.2 → 0.20.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/README.md +7 -4
- package/dist/combinators/map.d.ts +5 -0
- package/dist/combinators/map.d.ts.map +1 -1
- package/dist/combinators/node.d.ts +14 -13
- package/dist/combinators/node.d.ts.map +1 -1
- package/dist/combinators/parser.d.ts.map +1 -1
- package/dist/combinators/ref.d.ts.map +1 -1
- package/dist/combinators/regex.d.ts +7 -7
- package/dist/combinators/regex.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 +3 -3
- package/dist/compiler/codegen.d.ts.map +1 -1
- package/dist/compiler/fields.d.ts +16 -0
- package/dist/compiler/fields.d.ts.map +1 -0
- 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 +17 -3
- package/dist/compiler/linker.d.ts.map +1 -1
- package/dist/compiler/scannable-run.d.ts +2 -10
- package/dist/compiler/scannable-run.d.ts.map +1 -1
- package/dist/compiler/value-usage.d.ts.map +1 -1
- package/dist/cst/capture-buffer.d.ts +1 -0
- package/dist/cst/capture-buffer.d.ts.map +1 -1
- package/dist/index.cjs +568 -262
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +568 -252
- package/dist/index.js.map +4 -4
- package/dist/plugin/evaluator.d.ts.map +1 -1
- package/dist/plugin/index.cjs +568 -260
- package/dist/plugin/index.cjs.map +4 -4
- package/dist/plugin/index.js +568 -260
- package/dist/plugin/index.js.map +4 -4
- package/dist/regex/classes.d.ts +40 -0
- package/dist/regex/classes.d.ts.map +1 -0
- package/dist/regex/first-set.d.ts +35 -0
- package/dist/regex/first-set.d.ts.map +1 -0
- package/dist/types.d.ts +31 -8
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -3
- package/dist/combinators/regex-analyze.d.ts +0 -6
- package/dist/combinators/regex-analyze.d.ts.map +0 -1
package/dist/plugin/index.js
CHANGED
|
@@ -182,6 +182,13 @@ function ref() {
|
|
|
182
182
|
define(p) {
|
|
183
183
|
if (resolved) throw new Error("ref<T>() already defined");
|
|
184
184
|
resolved = p;
|
|
185
|
+
meta.firstSet = p._meta.firstSet;
|
|
186
|
+
meta.canMatchNewline = p._meta.canMatchNewline;
|
|
187
|
+
meta.isTrivia = p._meta.isTrivia;
|
|
188
|
+
if (p._meta.triviaKindLabels !== void 0) meta.triviaKindLabels = p._meta.triviaKindLabels;
|
|
189
|
+
else delete meta.triviaKindLabels;
|
|
190
|
+
if (p._meta.disjoint !== void 0) meta.disjoint = p._meta.disjoint;
|
|
191
|
+
else delete meta.disjoint;
|
|
185
192
|
}
|
|
186
193
|
};
|
|
187
194
|
return slot;
|
|
@@ -289,7 +296,8 @@ function saveCstMark(ctx) {
|
|
|
289
296
|
return {
|
|
290
297
|
raw: cstRawLen(ctx),
|
|
291
298
|
tlog: cstTlLen(ctx),
|
|
292
|
-
leaves: cstLeavesLen(ctx)
|
|
299
|
+
leaves: cstLeavesLen(ctx),
|
|
300
|
+
fields: ctx._fields?.length ?? 0
|
|
293
301
|
};
|
|
294
302
|
}
|
|
295
303
|
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
@@ -313,11 +321,13 @@ function rollbackCstCapture(ctx, mark) {
|
|
|
313
321
|
if (mark.tlog === 0) b.tl = void 0;
|
|
314
322
|
else b.tl.length = mark.tlog;
|
|
315
323
|
}
|
|
324
|
+
if (ctx._fields) ctx._fields.length = mark.fields;
|
|
316
325
|
return;
|
|
317
326
|
}
|
|
318
327
|
if (ctx._cstRawChildren) ctx._cstRawChildren.length = mark.raw;
|
|
319
328
|
if (ctx._cstTriviaLog) ctx._cstTriviaLog.length = mark.tlog;
|
|
320
329
|
if (ctx._cstLeaves) ctx._cstLeaves.length = mark.leaves;
|
|
330
|
+
if (ctx._fields) ctx._fields.length = mark.fields;
|
|
321
331
|
}
|
|
322
332
|
function pushCstTriviaEntry(ctx, start, end, kindIndex) {
|
|
323
333
|
const insertIdx = cstRawLen(ctx);
|
|
@@ -361,9 +371,9 @@ function asciiFoldEq(a, b) {
|
|
|
361
371
|
}
|
|
362
372
|
function literal(value, opts = {}) {
|
|
363
373
|
const caseInsensitive = opts.caseInsensitive ?? false;
|
|
364
|
-
const
|
|
374
|
+
const firstSet2 = value.length > 0 ? fromChar(value.codePointAt(0)) : empty();
|
|
365
375
|
const meta = {
|
|
366
|
-
firstSet,
|
|
376
|
+
firstSet: firstSet2,
|
|
367
377
|
canMatchNewline: value.includes("\n"),
|
|
368
378
|
isTrivia: false
|
|
369
379
|
};
|
|
@@ -375,7 +385,7 @@ function literal(value, opts = {}) {
|
|
|
375
385
|
meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? firstLower === firstUpper ? { kind: "ranges", ranges: [{ lo: firstLower, hi: firstLower }] } : { kind: "ranges", ranges: [
|
|
376
386
|
{ lo: firstLower, hi: firstLower },
|
|
377
387
|
{ lo: firstUpper, hi: firstUpper }
|
|
378
|
-
] } :
|
|
388
|
+
] } : firstSet2;
|
|
379
389
|
}
|
|
380
390
|
return {
|
|
381
391
|
_tag: "literal",
|
|
@@ -398,68 +408,66 @@ function literal(value, opts = {}) {
|
|
|
398
408
|
};
|
|
399
409
|
}
|
|
400
410
|
|
|
401
|
-
// src/
|
|
402
|
-
var
|
|
403
|
-
function registerRegexAnalyzer(analyzer) {
|
|
404
|
-
firstSetAnalyzer = analyzer;
|
|
405
|
-
}
|
|
406
|
-
var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
|
|
407
|
-
var SCAN_BAIL_AT = 64;
|
|
411
|
+
// src/regex/classes.ts
|
|
412
|
+
var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
408
413
|
var SPACE_RANGES = [
|
|
409
414
|
[9, 13],
|
|
410
415
|
[32, 32],
|
|
411
416
|
[160, 160],
|
|
412
417
|
[5760, 5760],
|
|
413
418
|
[8192, 8202],
|
|
414
|
-
[8232,
|
|
419
|
+
[8232, 8232],
|
|
420
|
+
[8233, 8233],
|
|
415
421
|
[8239, 8239],
|
|
416
422
|
[8287, 8287],
|
|
417
423
|
[12288, 12288],
|
|
418
424
|
[65279, 65279]
|
|
419
425
|
];
|
|
420
|
-
var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
421
426
|
function shorthandRanges(ch) {
|
|
422
427
|
if (ch === "d") return [[48, 57]];
|
|
423
428
|
if (ch === "s") return SPACE_RANGES;
|
|
424
429
|
return [[48, 57], [65, 90], [97, 122], [95, 95]];
|
|
425
430
|
}
|
|
426
|
-
function
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
return false;
|
|
431
|
+
function readUnicodeEscape(body, i) {
|
|
432
|
+
if (body[i] !== "\\" || body[i + 1] !== "u") return null;
|
|
433
|
+
const hex = body.slice(i + 2, i + 6);
|
|
434
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
|
|
435
|
+
return { cp: Number.parseInt(hex, 16), next: i + 6 };
|
|
432
436
|
}
|
|
433
|
-
function
|
|
434
|
-
if (body.startsWith("^")) return null;
|
|
437
|
+
function parseClassRanges(body) {
|
|
435
438
|
const ranges = [];
|
|
436
439
|
let i = 0;
|
|
437
440
|
const readAtom = () => {
|
|
438
441
|
const ch = body[i];
|
|
439
442
|
if (ch === void 0) return null;
|
|
440
443
|
if (ch === "\\") {
|
|
441
|
-
const
|
|
442
|
-
if (
|
|
444
|
+
const uni = readUnicodeEscape(body, i);
|
|
445
|
+
if (uni) {
|
|
446
|
+
i = uni.next;
|
|
447
|
+
return { cp: uni.cp };
|
|
448
|
+
}
|
|
449
|
+
const e = body[i + 1];
|
|
450
|
+
if (e === void 0) return null;
|
|
443
451
|
i += 2;
|
|
444
|
-
if (
|
|
445
|
-
if (
|
|
446
|
-
if (
|
|
447
|
-
return { cp:
|
|
452
|
+
if (e in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[e] };
|
|
453
|
+
if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges(e) };
|
|
454
|
+
if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
|
|
455
|
+
return { cp: e.codePointAt(0) };
|
|
448
456
|
}
|
|
449
|
-
i
|
|
450
|
-
return { cp: ch.
|
|
457
|
+
i += ch.length;
|
|
458
|
+
return { cp: ch.codePointAt(0) };
|
|
451
459
|
};
|
|
452
460
|
while (i < body.length) {
|
|
453
461
|
const lo = readAtom();
|
|
454
|
-
if (
|
|
455
|
-
if ("
|
|
456
|
-
ranges.push(...lo.
|
|
462
|
+
if (lo === null) return null;
|
|
463
|
+
if ("set" in lo) {
|
|
464
|
+
ranges.push(...lo.set);
|
|
457
465
|
continue;
|
|
458
466
|
}
|
|
459
467
|
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
460
|
-
i
|
|
468
|
+
i += 1;
|
|
461
469
|
const hi = readAtom();
|
|
462
|
-
if (
|
|
470
|
+
if (hi === null || "set" in hi) return null;
|
|
463
471
|
ranges.push([lo.cp, hi.cp]);
|
|
464
472
|
} else {
|
|
465
473
|
ranges.push([lo.cp, lo.cp]);
|
|
@@ -467,6 +475,25 @@ function readClassRanges(body) {
|
|
|
467
475
|
}
|
|
468
476
|
return ranges.length ? ranges : null;
|
|
469
477
|
}
|
|
478
|
+
|
|
479
|
+
// src/combinators/regex.ts
|
|
480
|
+
var firstSetAnalyzer = null;
|
|
481
|
+
function registerRegexAnalyzer(analyzer) {
|
|
482
|
+
firstSetAnalyzer = analyzer;
|
|
483
|
+
}
|
|
484
|
+
var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
|
|
485
|
+
var SCAN_BAIL_AT = 64;
|
|
486
|
+
function inRanges(cp, ranges) {
|
|
487
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
488
|
+
const [lo, hi] = ranges[i];
|
|
489
|
+
if (cp >= lo && cp <= hi) return true;
|
|
490
|
+
}
|
|
491
|
+
return false;
|
|
492
|
+
}
|
|
493
|
+
function readClassRanges(body) {
|
|
494
|
+
if (body.startsWith("^")) return null;
|
|
495
|
+
return parseClassRanges(body);
|
|
496
|
+
}
|
|
470
497
|
function shortScanner(source, flags) {
|
|
471
498
|
if (/[imsuvy]/.test(flags)) return null;
|
|
472
499
|
let ranges = null;
|
|
@@ -500,8 +527,8 @@ function regex(pattern, flags = "") {
|
|
|
500
527
|
const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
|
|
501
528
|
const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
|
|
502
529
|
const scan = shortScanner(source, resolvedFlags);
|
|
503
|
-
const { firstSet, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
|
|
504
|
-
const meta = { firstSet, canMatchNewline, isTrivia: false };
|
|
530
|
+
const { firstSet: firstSet2, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
|
|
531
|
+
const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
|
|
505
532
|
return {
|
|
506
533
|
_tag: "regex",
|
|
507
534
|
_meta: meta,
|
|
@@ -529,111 +556,266 @@ function regex(pattern, flags = "") {
|
|
|
529
556
|
};
|
|
530
557
|
}
|
|
531
558
|
|
|
532
|
-
// src/
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
return extractFirstSet(ast.body);
|
|
538
|
-
} catch {
|
|
539
|
-
return { firstSet: any(), canMatchNewline: true };
|
|
540
|
-
}
|
|
559
|
+
// src/regex/first-set.ts
|
|
560
|
+
var ANY = { t: "any" };
|
|
561
|
+
var EMPTY2 = { t: "empty" };
|
|
562
|
+
function charNode(set, nl) {
|
|
563
|
+
return { t: "char", set, nl };
|
|
541
564
|
}
|
|
542
|
-
function
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
565
|
+
function rangesToSet(ranges) {
|
|
566
|
+
let fs2 = empty();
|
|
567
|
+
for (const [lo, hi] of ranges) fs2 = union(fs2, fromRange(lo, hi));
|
|
568
|
+
return fs2;
|
|
569
|
+
}
|
|
570
|
+
function rangesHaveNewline(ranges) {
|
|
571
|
+
return ranges.some(([lo, hi]) => lo <= 10 && 10 <= hi);
|
|
572
|
+
}
|
|
573
|
+
var BAIL = /* @__PURE__ */ Symbol("regex-bail");
|
|
574
|
+
function parseRegex(src) {
|
|
575
|
+
let i = 0;
|
|
576
|
+
const parseAlt = () => {
|
|
577
|
+
const arms = [parseSeq()];
|
|
578
|
+
while (src[i] === "|") {
|
|
579
|
+
i++;
|
|
580
|
+
arms.push(parseSeq());
|
|
548
581
|
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
582
|
+
return arms.length === 1 ? arms[0] : { t: "alt", arms };
|
|
583
|
+
};
|
|
584
|
+
const parseSeq = () => {
|
|
585
|
+
const parts = [];
|
|
586
|
+
while (i < src.length) {
|
|
587
|
+
const ch = src[i];
|
|
588
|
+
if (ch === "|" || ch === ")") break;
|
|
589
|
+
parts.push(parseQuantified());
|
|
590
|
+
}
|
|
591
|
+
if (parts.length === 0) return EMPTY2;
|
|
592
|
+
return parts.length === 1 ? parts[0] : { t: "seq", parts };
|
|
593
|
+
};
|
|
594
|
+
const parseQuantified = () => {
|
|
595
|
+
const atom = parseAtom();
|
|
596
|
+
const ch = src[i];
|
|
597
|
+
let min = null;
|
|
598
|
+
if (ch === "*") {
|
|
599
|
+
min = 0;
|
|
600
|
+
i++;
|
|
601
|
+
} else if (ch === "+") {
|
|
602
|
+
min = 1;
|
|
603
|
+
i++;
|
|
604
|
+
} else if (ch === "?") {
|
|
605
|
+
min = 0;
|
|
606
|
+
i++;
|
|
607
|
+
} else if (ch === "{") {
|
|
608
|
+
min = parseBraceQuantifier();
|
|
552
609
|
}
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
610
|
+
if (min === null) return atom;
|
|
611
|
+
if (src[i] === "?") i++;
|
|
612
|
+
return { t: "rep", node: atom, min };
|
|
613
|
+
};
|
|
614
|
+
const parseBraceQuantifier = () => {
|
|
615
|
+
const close = src.indexOf("}", i);
|
|
616
|
+
if (close === -1) return null;
|
|
617
|
+
const m = /^(\d+)(?:,(\d*))?$/.exec(src.slice(i + 1, close));
|
|
618
|
+
if (!m) return null;
|
|
619
|
+
i = close + 1;
|
|
620
|
+
return Number.parseInt(m[1], 10);
|
|
621
|
+
};
|
|
622
|
+
const parseAtom = () => {
|
|
623
|
+
const ch = src[i];
|
|
624
|
+
switch (ch) {
|
|
625
|
+
case "(":
|
|
626
|
+
return parseGroup();
|
|
627
|
+
case "[":
|
|
628
|
+
return parseClass();
|
|
629
|
+
case ".":
|
|
630
|
+
i++;
|
|
631
|
+
return charNode(any(), false);
|
|
632
|
+
// `.` matches any char except line terminators
|
|
633
|
+
case "\\":
|
|
634
|
+
return parseEscape();
|
|
635
|
+
case "^":
|
|
636
|
+
case "$":
|
|
637
|
+
i++;
|
|
638
|
+
return EMPTY2;
|
|
639
|
+
// anchors are zero-width
|
|
640
|
+
case "{":
|
|
641
|
+
i++;
|
|
642
|
+
return charNode(fromRange(123, 123), false);
|
|
643
|
+
// a `{` with nothing to quantify is a literal brace
|
|
644
|
+
default:
|
|
645
|
+
i += ch.length;
|
|
646
|
+
return charNode(fromRange(ch.codePointAt(0), ch.codePointAt(0)), ch === "\n");
|
|
571
647
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
}
|
|
583
|
-
|
|
648
|
+
};
|
|
649
|
+
const parseGroup = () => {
|
|
650
|
+
i++;
|
|
651
|
+
let lookaround = false;
|
|
652
|
+
if (src[i] === "?") {
|
|
653
|
+
const c1 = src[i + 1];
|
|
654
|
+
if (c1 === ":") i += 2;
|
|
655
|
+
else if (c1 === "=" || c1 === "!") {
|
|
656
|
+
i += 2;
|
|
657
|
+
lookaround = true;
|
|
658
|
+
} else if (c1 === "<") {
|
|
659
|
+
const c2 = src[i + 2];
|
|
660
|
+
if (c2 === "=" || c2 === "!") {
|
|
661
|
+
i += 3;
|
|
662
|
+
lookaround = true;
|
|
663
|
+
} else {
|
|
664
|
+
const gt = src.indexOf(">", i);
|
|
665
|
+
if (gt === -1) throw BAIL;
|
|
666
|
+
i = gt + 1;
|
|
667
|
+
}
|
|
668
|
+
} else throw BAIL;
|
|
584
669
|
}
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
};
|
|
603
|
-
if (val === "s") return { firstSet: fromRange(9, 13), canMatchNewline: true };
|
|
604
|
-
if (val === "n") return { firstSet: fromRange(10, 10), canMatchNewline: true };
|
|
670
|
+
const inner = parseAlt();
|
|
671
|
+
if (src[i] !== ")") throw BAIL;
|
|
672
|
+
i++;
|
|
673
|
+
return lookaround ? EMPTY2 : inner;
|
|
674
|
+
};
|
|
675
|
+
const parseClass = () => {
|
|
676
|
+
let k = i + 1;
|
|
677
|
+
const negated = src[k] === "^";
|
|
678
|
+
if (negated) k++;
|
|
679
|
+
let body = "";
|
|
680
|
+
while (k < src.length && src[k] !== "]") {
|
|
681
|
+
if (src[k] === "\\") {
|
|
682
|
+
body += src[k] + (src[k + 1] ?? "");
|
|
683
|
+
k += 2;
|
|
684
|
+
} else {
|
|
685
|
+
body += src[k];
|
|
686
|
+
k++;
|
|
605
687
|
}
|
|
606
|
-
return { firstSet: any(), canMatchNewline: true };
|
|
607
688
|
}
|
|
608
|
-
|
|
609
|
-
|
|
689
|
+
if (src[k] !== "]") throw BAIL;
|
|
690
|
+
i = k + 1;
|
|
691
|
+
if (negated) return charNode(any(), true);
|
|
692
|
+
const ranges = parseClassRanges(body);
|
|
693
|
+
if (!ranges) return charNode(any(), true);
|
|
694
|
+
return charNode(rangesToSet(ranges), rangesHaveNewline(ranges));
|
|
695
|
+
};
|
|
696
|
+
const parseEscape = () => {
|
|
697
|
+
const e = src[i + 1];
|
|
698
|
+
if (e === void 0) throw BAIL;
|
|
699
|
+
if (e === "u" && /^[0-9a-fA-F]{4}$/.test(src.slice(i + 2, i + 6))) {
|
|
700
|
+
const cp = Number.parseInt(src.slice(i + 2, i + 6), 16);
|
|
701
|
+
i += 6;
|
|
702
|
+
return charNode(fromRange(cp, cp), cp === 10);
|
|
703
|
+
}
|
|
704
|
+
if (e === "x" && /^[0-9a-fA-F]{2}$/.test(src.slice(i + 2, i + 4))) {
|
|
705
|
+
const cp = Number.parseInt(src.slice(i + 2, i + 4), 16);
|
|
706
|
+
i += 4;
|
|
707
|
+
return charNode(fromRange(cp, cp), cp === 10);
|
|
708
|
+
}
|
|
709
|
+
i += 2;
|
|
710
|
+
switch (e) {
|
|
711
|
+
case "d":
|
|
712
|
+
return charNode(rangesToSet(shorthandRanges("d")), false);
|
|
713
|
+
case "w":
|
|
714
|
+
return charNode(rangesToSet(shorthandRanges("w")), false);
|
|
715
|
+
case "s":
|
|
716
|
+
return charNode(rangesToSet(shorthandRanges("s")), true);
|
|
717
|
+
case "D":
|
|
718
|
+
case "W":
|
|
719
|
+
case "S":
|
|
720
|
+
return charNode(any(), true);
|
|
721
|
+
// negated shorthand → widen
|
|
722
|
+
case "b":
|
|
723
|
+
case "B":
|
|
724
|
+
return EMPTY2;
|
|
725
|
+
// word boundary: zero-width
|
|
726
|
+
case "n":
|
|
727
|
+
return charNode(fromRange(10, 10), true);
|
|
728
|
+
case "r":
|
|
729
|
+
return charNode(fromRange(13, 13), false);
|
|
730
|
+
case "t":
|
|
731
|
+
return charNode(fromRange(9, 9), false);
|
|
732
|
+
case "f":
|
|
733
|
+
return charNode(fromRange(12, 12), false);
|
|
734
|
+
case "v":
|
|
735
|
+
return charNode(fromRange(11, 11), false);
|
|
736
|
+
case "0":
|
|
737
|
+
return charNode(fromRange(0, 0), false);
|
|
738
|
+
default:
|
|
739
|
+
if (e >= "1" && e <= "9") return ANY;
|
|
740
|
+
return charNode(fromRange(e.codePointAt(0), e.codePointAt(0)), e === "\n");
|
|
741
|
+
}
|
|
742
|
+
};
|
|
743
|
+
const node2 = parseAlt();
|
|
744
|
+
if (i < src.length) throw BAIL;
|
|
745
|
+
return node2;
|
|
746
|
+
}
|
|
747
|
+
function nullable(n) {
|
|
748
|
+
switch (n.t) {
|
|
749
|
+
case "char":
|
|
750
|
+
return false;
|
|
751
|
+
case "any":
|
|
752
|
+
return true;
|
|
753
|
+
case "empty":
|
|
754
|
+
return true;
|
|
755
|
+
case "seq":
|
|
756
|
+
return n.parts.every(nullable);
|
|
757
|
+
case "alt":
|
|
758
|
+
return n.arms.some(nullable);
|
|
759
|
+
case "rep":
|
|
760
|
+
return n.min === 0 || nullable(n.node);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
function firstSet(n) {
|
|
764
|
+
switch (n.t) {
|
|
765
|
+
case "char":
|
|
766
|
+
return n.set;
|
|
767
|
+
case "any":
|
|
768
|
+
return any();
|
|
769
|
+
case "empty":
|
|
770
|
+
return empty();
|
|
771
|
+
case "rep":
|
|
772
|
+
return firstSet(n.node);
|
|
773
|
+
case "alt": {
|
|
610
774
|
let fs2 = empty();
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
if (expr.type === "ClassRange") {
|
|
614
|
-
const from = expr.from.codePoint;
|
|
615
|
-
const to = expr.to.codePoint;
|
|
616
|
-
fs2 = union(fs2, fromRange(from, to));
|
|
617
|
-
if (from <= 10 && 10 <= to) canNL = true;
|
|
618
|
-
} else if (expr.type === "Char") {
|
|
619
|
-
const r = extractFirstSet(expr);
|
|
620
|
-
fs2 = union(fs2, r.firstSet);
|
|
621
|
-
canNL = canNL || r.canMatchNewline;
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
if (node2.negative) return { firstSet: any(), canMatchNewline: true };
|
|
625
|
-
return { firstSet: fs2, canMatchNewline: canNL };
|
|
775
|
+
for (const arm of n.arms) fs2 = union(fs2, firstSet(arm));
|
|
776
|
+
return fs2;
|
|
626
777
|
}
|
|
627
|
-
case "
|
|
628
|
-
|
|
778
|
+
case "seq": {
|
|
779
|
+
let fs2 = empty();
|
|
780
|
+
for (const part of n.parts) {
|
|
781
|
+
fs2 = union(fs2, firstSet(part));
|
|
782
|
+
if (!nullable(part)) break;
|
|
783
|
+
}
|
|
784
|
+
return fs2;
|
|
629
785
|
}
|
|
630
|
-
|
|
631
|
-
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
function firstCanBeNewline(n) {
|
|
789
|
+
switch (n.t) {
|
|
790
|
+
case "char":
|
|
791
|
+
return n.nl;
|
|
792
|
+
case "any":
|
|
793
|
+
return true;
|
|
794
|
+
case "empty":
|
|
795
|
+
return false;
|
|
796
|
+
case "rep":
|
|
797
|
+
return firstCanBeNewline(n.node);
|
|
798
|
+
case "alt":
|
|
799
|
+
return n.arms.some(firstCanBeNewline);
|
|
800
|
+
case "seq": {
|
|
801
|
+
for (const part of n.parts) {
|
|
802
|
+
if (firstCanBeNewline(part)) return true;
|
|
803
|
+
if (!nullable(part)) break;
|
|
804
|
+
}
|
|
805
|
+
return false;
|
|
632
806
|
}
|
|
633
|
-
default:
|
|
634
|
-
return { firstSet: any(), canMatchNewline: true };
|
|
635
807
|
}
|
|
636
808
|
}
|
|
809
|
+
function firstSetFromRegex(source) {
|
|
810
|
+
let ast;
|
|
811
|
+
try {
|
|
812
|
+
ast = parseRegex(source);
|
|
813
|
+
} catch {
|
|
814
|
+
return { firstSet: any(), canMatchNewline: true };
|
|
815
|
+
}
|
|
816
|
+
if (nullable(ast)) return { firstSet: any(), canMatchNewline: true };
|
|
817
|
+
return { firstSet: firstSet(ast), canMatchNewline: firstCanBeNewline(ast) };
|
|
818
|
+
}
|
|
637
819
|
|
|
638
820
|
// src/combinators/keywords.ts
|
|
639
821
|
function word(str, boundary = "_0-9A-Za-z") {
|
|
@@ -648,19 +830,19 @@ function keywords(words, opts = {}) {
|
|
|
648
830
|
const boundary = opts.boundary ? `(?![${opts.boundary}])` : "";
|
|
649
831
|
const flags = opts.caseInsensitive ? "iuy" : "uy";
|
|
650
832
|
const re = new RegExp(`(?:${alt})${boundary}`, flags);
|
|
651
|
-
let
|
|
833
|
+
let firstSet2 = empty();
|
|
652
834
|
for (const w of sorted) {
|
|
653
835
|
if (w.length === 0) continue;
|
|
654
836
|
const cp = w.codePointAt(0);
|
|
655
|
-
|
|
837
|
+
firstSet2 = union(firstSet2, fromChar(cp));
|
|
656
838
|
if (opts.caseInsensitive) {
|
|
657
839
|
const u = String.fromCodePoint(cp).toUpperCase().codePointAt(0);
|
|
658
840
|
const l = String.fromCodePoint(cp).toLowerCase().codePointAt(0);
|
|
659
|
-
if (u !== void 0)
|
|
660
|
-
if (l !== void 0)
|
|
841
|
+
if (u !== void 0) firstSet2 = union(firstSet2, fromChar(u));
|
|
842
|
+
if (l !== void 0) firstSet2 = union(firstSet2, fromChar(l));
|
|
661
843
|
}
|
|
662
844
|
}
|
|
663
|
-
const meta = { firstSet, canMatchNewline: false, isTrivia: false };
|
|
845
|
+
const meta = { firstSet: firstSet2, canMatchNewline: false, isTrivia: false };
|
|
664
846
|
return {
|
|
665
847
|
_tag: "keywords",
|
|
666
848
|
_meta: meta,
|
|
@@ -1054,10 +1236,10 @@ function needsDeferredTriviaCommit(ctx) {
|
|
|
1054
1236
|
}
|
|
1055
1237
|
function saveTriviaMark(ctx) {
|
|
1056
1238
|
const m = saveCstMark(ctx);
|
|
1057
|
-
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1239
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1058
1240
|
}
|
|
1059
1241
|
function rollbackTrivia(ctx, mark) {
|
|
1060
|
-
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves });
|
|
1242
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields });
|
|
1061
1243
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1062
1244
|
}
|
|
1063
1245
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1441,6 +1623,9 @@ function markUnusedValues(root) {
|
|
|
1441
1623
|
case "transform":
|
|
1442
1624
|
visit(def.parser, true);
|
|
1443
1625
|
return;
|
|
1626
|
+
case "field":
|
|
1627
|
+
visit(def.parser, true);
|
|
1628
|
+
return;
|
|
1444
1629
|
case "skip":
|
|
1445
1630
|
visit(def.main, consumed);
|
|
1446
1631
|
visit(def.skipped, false);
|
|
@@ -1492,6 +1677,11 @@ function markUnusedValues(root) {
|
|
|
1492
1677
|
}
|
|
1493
1678
|
|
|
1494
1679
|
// src/combinators/parser.ts
|
|
1680
|
+
function tagRule(r, key) {
|
|
1681
|
+
;
|
|
1682
|
+
r._ruleName = key;
|
|
1683
|
+
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
|
|
1684
|
+
}
|
|
1495
1685
|
function rules(factory) {
|
|
1496
1686
|
const cache = {};
|
|
1497
1687
|
const proxy = new Proxy(cache, {
|
|
@@ -1500,7 +1690,7 @@ function rules(factory) {
|
|
|
1500
1690
|
const record = target;
|
|
1501
1691
|
if (!(key in record)) {
|
|
1502
1692
|
const r = ref();
|
|
1503
|
-
r
|
|
1693
|
+
tagRule(r, key);
|
|
1504
1694
|
record[key] = r;
|
|
1505
1695
|
}
|
|
1506
1696
|
return record[key];
|
|
@@ -1511,12 +1701,12 @@ function rules(factory) {
|
|
|
1511
1701
|
const placeholder = cache[key];
|
|
1512
1702
|
const parser2 = definitions[key];
|
|
1513
1703
|
if (placeholder !== void 0 && typeof placeholder.define === "function") {
|
|
1514
|
-
;
|
|
1704
|
+
tagRule(parser2, key);
|
|
1515
1705
|
placeholder.define(parser2);
|
|
1516
1706
|
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
1517
1707
|
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
1518
1708
|
} else {
|
|
1519
|
-
;
|
|
1709
|
+
tagRule(parser2, key);
|
|
1520
1710
|
cache[key] = parser2;
|
|
1521
1711
|
}
|
|
1522
1712
|
}
|
|
@@ -1573,44 +1763,130 @@ function buildReadsTrivia(def) {
|
|
|
1573
1763
|
const src = def.buildSrc ?? def.build.toString();
|
|
1574
1764
|
const arity = confirmedBuildArity(src);
|
|
1575
1765
|
if (arity === null) return true;
|
|
1576
|
-
return arity >=
|
|
1766
|
+
return arity >= 5;
|
|
1577
1767
|
}
|
|
1578
1768
|
function buildReadsState(def) {
|
|
1579
1769
|
if (!def.build) return true;
|
|
1580
1770
|
const src = def.buildSrc ?? def.build.toString();
|
|
1581
1771
|
const arity = confirmedBuildArity(src);
|
|
1582
1772
|
if (arity === null) return true;
|
|
1583
|
-
return arity >=
|
|
1773
|
+
return arity >= 6;
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
// src/compiler/fields.ts
|
|
1777
|
+
function buildReadsFields(def) {
|
|
1778
|
+
if (!def.build) return true;
|
|
1779
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
1780
|
+
const arity = confirmedBuildArity(src);
|
|
1781
|
+
if (arity === null) return true;
|
|
1782
|
+
return arity >= 2;
|
|
1783
|
+
}
|
|
1784
|
+
function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
1785
|
+
if (seen.has(p)) return false;
|
|
1786
|
+
seen.add(p);
|
|
1787
|
+
const d = p._def;
|
|
1788
|
+
switch (d.tag) {
|
|
1789
|
+
case "field":
|
|
1790
|
+
return true;
|
|
1791
|
+
case "node":
|
|
1792
|
+
return false;
|
|
1793
|
+
case "lazy": {
|
|
1794
|
+
try {
|
|
1795
|
+
return parserHasOwnFields(d.thunk(), seen);
|
|
1796
|
+
} catch {
|
|
1797
|
+
return false;
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1800
|
+
case "sequence":
|
|
1801
|
+
case "choice":
|
|
1802
|
+
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
1803
|
+
case "sepBy":
|
|
1804
|
+
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
1805
|
+
case "skip":
|
|
1806
|
+
return parserHasOwnFields(d.main, seen) || parserHasOwnFields(d.skipped, seen);
|
|
1807
|
+
case "grammar":
|
|
1808
|
+
return parserHasOwnFields(d.parser, seen) || (d.triviaParser ? parserHasOwnFields(d.triviaParser, seen) : false);
|
|
1809
|
+
case "scanTo":
|
|
1810
|
+
return parserHasOwnFields(d.sentinel, seen) || d.skip.some((x) => parserHasOwnFields(x, seen));
|
|
1811
|
+
case "recover":
|
|
1812
|
+
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.sentinel, seen);
|
|
1813
|
+
case "many":
|
|
1814
|
+
case "oneOrMore":
|
|
1815
|
+
case "optional":
|
|
1816
|
+
case "transform":
|
|
1817
|
+
case "trivia":
|
|
1818
|
+
case "token":
|
|
1819
|
+
case "label":
|
|
1820
|
+
case "expect":
|
|
1821
|
+
case "withCtx":
|
|
1822
|
+
case "not":
|
|
1823
|
+
return parserHasOwnFields(d.parser, seen);
|
|
1824
|
+
default:
|
|
1825
|
+
return false;
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
function buildFieldMap(captures) {
|
|
1829
|
+
if (!captures?.length) return void 0;
|
|
1830
|
+
const out = {};
|
|
1831
|
+
for (const cap of captures) {
|
|
1832
|
+
const entry = { value: cap.value, span: cap.span };
|
|
1833
|
+
const current = out[cap.name];
|
|
1834
|
+
if (current === void 0) out[cap.name] = entry;
|
|
1835
|
+
else if (Array.isArray(current)) current.push(entry);
|
|
1836
|
+
else out[cap.name] = [current, entry];
|
|
1837
|
+
}
|
|
1838
|
+
return out;
|
|
1584
1839
|
}
|
|
1585
1840
|
|
|
1586
1841
|
// src/combinators/node.ts
|
|
1587
|
-
function
|
|
1842
|
+
function unwrapChild(child) {
|
|
1588
1843
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
1589
1844
|
}
|
|
1590
|
-
function
|
|
1845
|
+
function isCstChild(value) {
|
|
1846
|
+
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "error");
|
|
1847
|
+
}
|
|
1848
|
+
function missingInferredType() {
|
|
1849
|
+
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
1850
|
+
}
|
|
1851
|
+
function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
1852
|
+
const hasExplicitType = typeof typeOrCombinator === "string";
|
|
1853
|
+
const type = hasExplicitType ? typeOrCombinator : void 0;
|
|
1854
|
+
const combinator = hasExplicitType ? combinatorOrBuild : typeOrCombinator;
|
|
1855
|
+
const build = hasExplicitType ? buildOrOpts : combinatorOrBuild;
|
|
1856
|
+
const opts = hasExplicitType ? maybeOpts : buildOrOpts;
|
|
1857
|
+
const baseDef = { tag: "node", parser: combinator, ...type === void 0 ? {} : { type }, ...build === void 0 ? {} : { build } };
|
|
1591
1858
|
const meta = {
|
|
1592
1859
|
firstSet: combinator._meta.firstSet,
|
|
1593
1860
|
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1594
1861
|
isTrivia: false
|
|
1595
1862
|
};
|
|
1863
|
+
const unwrap = opts?.unwrap === true;
|
|
1596
1864
|
const collapse = opts?.collapse === true;
|
|
1597
|
-
|
|
1865
|
+
if (unwrap && collapse) {
|
|
1866
|
+
throw new Error("node() options cannot set both unwrap and collapse");
|
|
1867
|
+
}
|
|
1868
|
+
const def = unwrap || collapse ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {} } : baseDef;
|
|
1598
1869
|
const capturesTrivia = build ? buildReadsTrivia(def) : true;
|
|
1599
1870
|
const clonesState = build ? buildReadsState(def) : true;
|
|
1871
|
+
const capturesFields = parserHasOwnFields(combinator) && (build ? buildReadsFields(def) : true);
|
|
1600
1872
|
return {
|
|
1601
1873
|
_tag: "node",
|
|
1602
1874
|
_meta: meta,
|
|
1603
1875
|
_def: def,
|
|
1604
1876
|
parse(input, pos, ctx) {
|
|
1605
1877
|
const saved = beginCstNodeCapture(ctx);
|
|
1878
|
+
const savedFields = ctx._fields;
|
|
1879
|
+
ctx._fields = capturesFields ? [] : void 0;
|
|
1606
1880
|
if (!capturesTrivia) ctx.captureTrivia = false;
|
|
1607
1881
|
const r = combinator.parse(input, pos, ctx);
|
|
1882
|
+
const fields = capturesFields ? buildFieldMap(ctx._fields) : void 0;
|
|
1883
|
+
ctx._fields = savedFields;
|
|
1608
1884
|
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
1609
1885
|
if (!r.ok) return r;
|
|
1610
1886
|
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
1611
|
-
const
|
|
1612
|
-
const
|
|
1613
|
-
const rawEntry =
|
|
1887
|
+
const nodeType = def.type ?? missingInferredType();
|
|
1888
|
+
const built = unwrap && children.length === 1 ? unwrapChild(children[0]) : collapse && children.length === 1 ? children[0] : !build && ctx.build?._parsemanCstCollapse && children.length === 1 && rawChildren.length === 1 && ctx.build._parsemanCstCollapse(nodeType, children[0], children, rawChildren) ? children[0] : build ? build(children, fields, r.span, rawChildren, triviaLog, st) : ctx.build ? ctx.build(nodeType, children, fields, r.span, rawChildren, triviaLog, st) : { _tag: "node", type: nodeType, span: { start: r.span.start, end: r.span.end }, state: st ?? null, children };
|
|
1889
|
+
const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
|
|
1614
1890
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
1615
1891
|
pushCstChild(ctx, built, rawEntry);
|
|
1616
1892
|
}
|
|
@@ -1671,6 +1947,19 @@ function label(name, combinator) {
|
|
|
1671
1947
|
}
|
|
1672
1948
|
};
|
|
1673
1949
|
}
|
|
1950
|
+
function field(name, combinator) {
|
|
1951
|
+
return {
|
|
1952
|
+
_tag: combinator._tag,
|
|
1953
|
+
_meta: combinator._meta,
|
|
1954
|
+
_def: { tag: "field", name, parser: combinator },
|
|
1955
|
+
parse(input, pos, ctx) {
|
|
1956
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1957
|
+
if (!result.ok) return result;
|
|
1958
|
+
ctx._fields?.push({ name, value: result.value, span: result.span });
|
|
1959
|
+
return result;
|
|
1960
|
+
}
|
|
1961
|
+
};
|
|
1962
|
+
}
|
|
1674
1963
|
|
|
1675
1964
|
// src/compiler/line-index.ts
|
|
1676
1965
|
function buildLineIndex(input) {
|
|
@@ -1857,77 +2146,11 @@ function expect(combinator, label2) {
|
|
|
1857
2146
|
|
|
1858
2147
|
// src/compiler/scannable-run.ts
|
|
1859
2148
|
var BACKSLASH = 92;
|
|
1860
|
-
var CLASS_ESCAPES2 = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
1861
2149
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
1862
|
-
var SPACE_RANGES2 = [
|
|
1863
|
-
[9, 13],
|
|
1864
|
-
[32, 32],
|
|
1865
|
-
[160, 160],
|
|
1866
|
-
[5760, 5760],
|
|
1867
|
-
[8192, 8202],
|
|
1868
|
-
[8232, 8232],
|
|
1869
|
-
[8233, 8233],
|
|
1870
|
-
[8239, 8239],
|
|
1871
|
-
[8287, 8287],
|
|
1872
|
-
[12288, 12288],
|
|
1873
|
-
[65279, 65279]
|
|
1874
|
-
];
|
|
1875
|
-
function shorthandRanges2(ch) {
|
|
1876
|
-
if (ch === "d") return [[48, 57]];
|
|
1877
|
-
if (ch === "s") return SPACE_RANGES2;
|
|
1878
|
-
return [[48, 57], [65, 90], [97, 122], [95, 95]];
|
|
1879
|
-
}
|
|
1880
|
-
function readUnicodeEscape(body, i) {
|
|
1881
|
-
if (body[i] !== "\\" || body[i + 1] !== "u") return null;
|
|
1882
|
-
const hex = body.slice(i + 2, i + 6);
|
|
1883
|
-
if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
|
|
1884
|
-
return { cp: Number.parseInt(hex, 16), next: i + 6 };
|
|
1885
|
-
}
|
|
1886
|
-
function parseClassRanges(body) {
|
|
1887
|
-
const ranges = [];
|
|
1888
|
-
let i = 0;
|
|
1889
|
-
const readAtom = () => {
|
|
1890
|
-
const ch = body[i];
|
|
1891
|
-
if (ch === void 0) return null;
|
|
1892
|
-
if (ch === "\\") {
|
|
1893
|
-
const uni = readUnicodeEscape(body, i);
|
|
1894
|
-
if (uni) {
|
|
1895
|
-
i = uni.next;
|
|
1896
|
-
return { cp: uni.cp };
|
|
1897
|
-
}
|
|
1898
|
-
const e = body[i + 1];
|
|
1899
|
-
if (e === void 0) return null;
|
|
1900
|
-
i += 2;
|
|
1901
|
-
if (e in CLASS_ESCAPES2) return { cp: CLASS_ESCAPES2[e] };
|
|
1902
|
-
if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges2(e) };
|
|
1903
|
-
if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
|
|
1904
|
-
return { cp: e.codePointAt(0) };
|
|
1905
|
-
}
|
|
1906
|
-
i += ch.length;
|
|
1907
|
-
return { cp: ch.codePointAt(0) };
|
|
1908
|
-
};
|
|
1909
|
-
while (i < body.length) {
|
|
1910
|
-
const lo = readAtom();
|
|
1911
|
-
if (lo === null) return null;
|
|
1912
|
-
if ("set" in lo) {
|
|
1913
|
-
ranges.push(...lo.set);
|
|
1914
|
-
continue;
|
|
1915
|
-
}
|
|
1916
|
-
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
1917
|
-
i += 1;
|
|
1918
|
-
const hi = readAtom();
|
|
1919
|
-
if (hi === null || "set" in hi) return null;
|
|
1920
|
-
ranges.push([lo.cp, hi.cp]);
|
|
1921
|
-
} else {
|
|
1922
|
-
ranges.push([lo.cp, lo.cp]);
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
return ranges.length ? ranges : null;
|
|
1926
|
-
}
|
|
1927
2150
|
function classToRanges(cls) {
|
|
1928
|
-
if (cls === "\\d") return
|
|
1929
|
-
if (cls === "\\w") return
|
|
1930
|
-
if (cls === "\\s") return
|
|
2151
|
+
if (cls === "\\d") return shorthandRanges("d");
|
|
2152
|
+
if (cls === "\\w") return shorthandRanges("w");
|
|
2153
|
+
if (cls === "\\s") return shorthandRanges("s");
|
|
1931
2154
|
const body = cls.slice(1, -1);
|
|
1932
2155
|
if (body.startsWith("^")) return null;
|
|
1933
2156
|
return parseClassRanges(body);
|
|
@@ -1945,7 +2168,7 @@ function literalCodePoints(frag) {
|
|
|
1945
2168
|
if (ch === "\\") {
|
|
1946
2169
|
const e = frag[i + 1];
|
|
1947
2170
|
if (e === void 0) return null;
|
|
1948
|
-
out.push(e in
|
|
2171
|
+
out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
|
|
1949
2172
|
i += 2;
|
|
1950
2173
|
continue;
|
|
1951
2174
|
}
|
|
@@ -2038,7 +2261,7 @@ function parseSeqParts(source) {
|
|
|
2038
2261
|
if (e === "d" || e === "w" || e === "s") {
|
|
2039
2262
|
flush();
|
|
2040
2263
|
i += 2;
|
|
2041
|
-
i += runFrom(
|
|
2264
|
+
i += runFrom(shorthandRanges(e), false, source[i]);
|
|
2042
2265
|
continue;
|
|
2043
2266
|
}
|
|
2044
2267
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -2047,8 +2270,8 @@ function parseSeqParts(source) {
|
|
|
2047
2270
|
cp2 = uni.cp;
|
|
2048
2271
|
i = uni.next;
|
|
2049
2272
|
} else if (e === void 0) return null;
|
|
2050
|
-
else if (e in
|
|
2051
|
-
cp2 =
|
|
2273
|
+
else if (e in CLASS_ESCAPES) {
|
|
2274
|
+
cp2 = CLASS_ESCAPES[e];
|
|
2052
2275
|
i += 2;
|
|
2053
2276
|
} else if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
|
|
2054
2277
|
else {
|
|
@@ -2155,7 +2378,7 @@ function rangesSubset(sub, sup) {
|
|
|
2155
2378
|
}
|
|
2156
2379
|
function parseClassOperand(body) {
|
|
2157
2380
|
if (body === "\\d" || body === "\\w" || body === "\\s") {
|
|
2158
|
-
return { ranges:
|
|
2381
|
+
return { ranges: shorthandRanges(body[1]), negated: false };
|
|
2159
2382
|
}
|
|
2160
2383
|
if (body.length >= 2 && body[0] === "[" && body[body.length - 1] === "]") {
|
|
2161
2384
|
let inner = body.slice(1, -1);
|
|
@@ -2588,7 +2811,7 @@ function parseScanShapeCore(source) {
|
|
|
2588
2811
|
}
|
|
2589
2812
|
m = /^\\([dws])([+*])$/.exec(source);
|
|
2590
2813
|
if (m) {
|
|
2591
|
-
return { kind: "chars", ranges:
|
|
2814
|
+
return { kind: "chars", ranges: shorthandRanges(m[1]), minOne: m[2] === "+" };
|
|
2592
2815
|
}
|
|
2593
2816
|
m = /^(\[(?:\\.|[^\]])+\]|\\[dws])(\[(?:\\.|[^\]])+\]|\\[dws])\*$/.exec(source);
|
|
2594
2817
|
if (m) {
|
|
@@ -3130,21 +3353,22 @@ function emitScannableTerminal(shape, c) {
|
|
|
3130
3353
|
}
|
|
3131
3354
|
|
|
3132
3355
|
// src/compiler/inline-build.ts
|
|
3133
|
-
var MK_BUILD_RE = /^\(\s*(
|
|
3356
|
+
var MK_BUILD_RE = /^\(\s*(\w+)\s*,\s*\w+\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\)\s*=>\s*mk\s*\(\s*(['"])([^'"]+)\5\s*,\s*\1\s*,\s*\3\s*,\s*\2\s*,\s*\4\s*\)\s*$/;
|
|
3134
3357
|
function escapeRegExp(s) {
|
|
3135
3358
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3136
3359
|
}
|
|
3137
3360
|
function looseMkBuildRe(type) {
|
|
3138
3361
|
return new RegExp(
|
|
3139
|
-
String.raw`^\(\s*(
|
|
3362
|
+
String.raw`^\(\s*(\w+)\s*,\s*\w+\s*,\s*(\w+)\s*,\s*(\w+)\s*,\s*(\w+)\s*\)\s*=>\s*.+\(\s*(['"])${escapeRegExp(type)}\5\s*,\s*\1\s*,\s*\3\s*,\s*\2\s*,\s*\4\s*\)\s*$`
|
|
3140
3363
|
);
|
|
3141
3364
|
}
|
|
3142
3365
|
function analyzeMkInlineBuild(def) {
|
|
3143
3366
|
if (!def.build) return null;
|
|
3367
|
+
if (def.type === void 0) return null;
|
|
3144
3368
|
const src = (def.buildSrc ?? def.build.toString()).trim();
|
|
3145
3369
|
const strict = src.match(MK_BUILD_RE);
|
|
3146
3370
|
if (strict) {
|
|
3147
|
-
const mkType = strict[
|
|
3371
|
+
const mkType = strict[6];
|
|
3148
3372
|
return mkType === def.type ? def.type : null;
|
|
3149
3373
|
}
|
|
3150
3374
|
if (looseMkBuildRe(def.type).test(src)) return def.type;
|
|
@@ -3479,8 +3703,9 @@ function planDisjointDispatch(parsers) {
|
|
|
3479
3703
|
}
|
|
3480
3704
|
return total >= SWITCH_MIN_CASES ? { kind: "switch", cases } : { kind: "if" };
|
|
3481
3705
|
}
|
|
3482
|
-
function captureRestoreBody(mL, mR, mTl, mLg) {
|
|
3483
|
-
const
|
|
3706
|
+
function captureRestoreBody(mL, mR, mTl, mLg, mF = null) {
|
|
3707
|
+
const fieldRestore = mF ? `; if (_ctx._fields) _ctx._fields.length = ${mF}` : "";
|
|
3708
|
+
const base = `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${mL}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${mR}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${mTl}${fieldRestore}`;
|
|
3484
3709
|
return mLg ? `${base}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${mLg}` : base;
|
|
3485
3710
|
}
|
|
3486
3711
|
function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -3528,6 +3753,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
3528
3753
|
// Delegating wrappers: defer to the wrapped parser.
|
|
3529
3754
|
case "transform":
|
|
3530
3755
|
case "label":
|
|
3756
|
+
case "field":
|
|
3531
3757
|
case "expect":
|
|
3532
3758
|
case "withCtx":
|
|
3533
3759
|
case "grammar":
|
|
@@ -3574,6 +3800,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
3574
3800
|
case "optional":
|
|
3575
3801
|
case "transform":
|
|
3576
3802
|
case "label":
|
|
3803
|
+
case "field":
|
|
3577
3804
|
case "expect":
|
|
3578
3805
|
case "withCtx":
|
|
3579
3806
|
case "grammar":
|
|
@@ -3611,22 +3838,25 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
3611
3838
|
ctx.recordFail = savedRecord;
|
|
3612
3839
|
const ind0 = ind(ctx);
|
|
3613
3840
|
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
3841
|
+
const needsFieldRollback = needsRollback && parserHasOwnFields(inner);
|
|
3614
3842
|
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
3615
3843
|
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
3616
3844
|
const mTl = needsRollback ? v(ctx, "_fctl") : null;
|
|
3845
|
+
const mF = needsFieldRollback ? v(ctx, "_fcf") : null;
|
|
3617
3846
|
const stmts = [
|
|
3618
3847
|
`${ind0}let ${okV} = false, ${valV}, ${endV} = ${pos}`,
|
|
3619
3848
|
...mL ? [
|
|
3620
3849
|
`${ind0}const ${mL} = _ctx._cstLeaves?.length ?? 0`,
|
|
3621
3850
|
`${ind0}const ${mR} = _ctx._cstRawChildren?.length ?? 0`,
|
|
3622
|
-
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0
|
|
3851
|
+
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
3852
|
+
...mF ? [`${ind0}const ${mF} = _ctx._fields?.length ?? 0`] : []
|
|
3623
3853
|
] : [],
|
|
3624
3854
|
`${ind0}${lbl}: {`,
|
|
3625
3855
|
...r.stmts,
|
|
3626
3856
|
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
3627
3857
|
`${ind0}}`,
|
|
3628
3858
|
...mL ? [
|
|
3629
|
-
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null)} }`
|
|
3859
|
+
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
|
|
3630
3860
|
] : []
|
|
3631
3861
|
];
|
|
3632
3862
|
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
@@ -3853,6 +4083,7 @@ function failsAtStart(p) {
|
|
|
3853
4083
|
return true;
|
|
3854
4084
|
case "transform":
|
|
3855
4085
|
case "label":
|
|
4086
|
+
case "field":
|
|
3856
4087
|
return failsAtStart(d.parser);
|
|
3857
4088
|
default:
|
|
3858
4089
|
return false;
|
|
@@ -3872,6 +4103,7 @@ function canMatchEmptyAtStart(p) {
|
|
|
3872
4103
|
return true;
|
|
3873
4104
|
case "transform":
|
|
3874
4105
|
case "label":
|
|
4106
|
+
case "field":
|
|
3875
4107
|
return canMatchEmptyAtStart(d.parser);
|
|
3876
4108
|
case "literal":
|
|
3877
4109
|
return d.value.length === 0;
|
|
@@ -4054,11 +4286,13 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4054
4286
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
4055
4287
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
4056
4288
|
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
4289
|
+
const armNeedsFieldRollback = armNeedsRollback && parserHasOwnFields(p);
|
|
4057
4290
|
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
4058
4291
|
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
4059
4292
|
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
4060
4293
|
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
4061
|
-
const
|
|
4294
|
+
const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
|
|
4295
|
+
const rollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
|
|
4062
4296
|
const failSlot = atStart ? staticFx : "_ctx._fx";
|
|
4063
4297
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
4064
4298
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
@@ -4068,7 +4302,8 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4068
4302
|
`${ind(ctx)}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
|
|
4069
4303
|
`${ind(ctx)}const ${markRaw} = _ctx._cstRawChildren?.length ?? 0`,
|
|
4070
4304
|
`${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
4071
|
-
`${ind(ctx)}const ${markLog} = _ctx._triviaLog?.length ?? 0
|
|
4305
|
+
`${ind(ctx)}const ${markLog} = _ctx._triviaLog?.length ?? 0`,
|
|
4306
|
+
...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
|
|
4072
4307
|
);
|
|
4073
4308
|
}
|
|
4074
4309
|
const { stmts: armStmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos, atStart);
|
|
@@ -4461,6 +4696,9 @@ function emitToken(def, ctx, pos) {
|
|
|
4461
4696
|
};
|
|
4462
4697
|
}
|
|
4463
4698
|
function emitNode(def, ctx, pos) {
|
|
4699
|
+
if (def.type === void 0) {
|
|
4700
|
+
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
4701
|
+
}
|
|
4464
4702
|
const structural = def.build === void 0;
|
|
4465
4703
|
const mkType = structural ? null : analyzeMkInlineBuild(def);
|
|
4466
4704
|
let buildIdx = null;
|
|
@@ -4472,25 +4710,36 @@ function emitNode(def, ctx, pos) {
|
|
|
4472
4710
|
const i = ind(ctx);
|
|
4473
4711
|
const capturesTrivia = mkType !== null || !structural && buildReadsTrivia(def);
|
|
4474
4712
|
const clonesState = !structural && buildReadsState(def);
|
|
4713
|
+
const hasFields = parserHasOwnFields(def.parser);
|
|
4714
|
+
const capturesFields = hasFields && !structural && buildReadsFields(def);
|
|
4475
4715
|
const chV = v(ctx, "_ch");
|
|
4476
4716
|
const rawV = v(ctx, "_raw");
|
|
4477
4717
|
const capTLv = structural ? v(ctx, "_ctl") : null;
|
|
4478
4718
|
const capSTv = structural ? v(ctx, "_cst") : null;
|
|
4719
|
+
const capFv = structural && hasFields ? v(ctx, "_cf") : null;
|
|
4479
4720
|
const tlV = capturesTrivia || structural ? v(ctx, "_tl") : "_EMPTY_TL";
|
|
4480
4721
|
if (!capturesTrivia) ctx.needsEmptyTl = true;
|
|
4481
4722
|
const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
|
|
4482
4723
|
if (structural) ctx.needsHostReads = true;
|
|
4483
|
-
const
|
|
4724
|
+
const hostTriviaGate = `_ctx.build !== undefined && (_ctx.build._parsemanCaptureTrivia !== undefined ? _ctx.build._parsemanCaptureTrivia(${JSON.stringify(def.type)}) : (_ctx._pmCapTL ??= _hostReads(_ctx.build, 5)))`;
|
|
4725
|
+
const allocStmt = structural ? `${i}const ${capTLv} = ${hostTriviaGate}, ${capSTv} = _ctx._pmCapST ??= (_ctx.build === undefined || _hostReads(_ctx.build, 6))${capFv ? `, ${capFv} = _ctx.build !== undefined && _hostReads(_ctx.build, 2)` : ""}
|
|
4484
4726
|
${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capturesTrivia ? `${i}const ${chV} = [], ${rawV} = [], ${tlV} = []` : `${i}const ${chV} = [], ${rawV} = []`;
|
|
4485
4727
|
const innerTl = structural ? `${capTLv} ? ${tlV} : undefined` : capturesTrivia ? tlV : "undefined";
|
|
4728
|
+
const fieldsOn = structural ? capFv ?? "false" : capturesFields ? "true" : "false";
|
|
4729
|
+
const sf = hasFields ? v(ctx, "_sf") : null;
|
|
4730
|
+
const fArr = hasFields ? v(ctx, "_fa") : null;
|
|
4731
|
+
const fObj = hasFields ? v(ctx, "_fields") : "undefined";
|
|
4486
4732
|
const stmts = [
|
|
4487
4733
|
allocStmt,
|
|
4488
|
-
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog`,
|
|
4489
|
-
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}`
|
|
4734
|
+
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
4735
|
+
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
|
|
4490
4736
|
];
|
|
4491
4737
|
const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
4492
4738
|
stmts.push(...innerStmts);
|
|
4493
|
-
|
|
4739
|
+
if (sf && fArr) {
|
|
4740
|
+
stmts.push(`${i}const ${fArr} = _ctx._fields`);
|
|
4741
|
+
}
|
|
4742
|
+
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${sf ? `; _ctx._fields = ${sf}` : ""}`);
|
|
4494
4743
|
stmts.push(...emitIfFail(ctx, `!${okVar}`, propagateFailBody(ctx)));
|
|
4495
4744
|
let stV = "undefined";
|
|
4496
4745
|
if (structural) {
|
|
@@ -4500,14 +4749,33 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
4500
4749
|
stV = v(ctx, "_nst");
|
|
4501
4750
|
stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
|
|
4502
4751
|
}
|
|
4752
|
+
if (sf && fArr) {
|
|
4753
|
+
const fe = v(ctx, "_fe");
|
|
4754
|
+
const cur = v(ctx, "_fc");
|
|
4755
|
+
stmts.push(
|
|
4756
|
+
`${i}let ${fObj} = undefined`,
|
|
4757
|
+
`${i}if (${fArr} && ${fArr}.length) {`,
|
|
4758
|
+
`${i} ${fObj} = {}`,
|
|
4759
|
+
`${i} for (const ${fe} of ${fArr}) {`,
|
|
4760
|
+
`${i} const ${cur} = ${fObj}[${fe}.name], _entry = { value: ${fe}.value, span: ${fe}.span }`,
|
|
4761
|
+
`${i} if (${cur} === undefined) ${fObj}[${fe}.name] = _entry`,
|
|
4762
|
+
`${i} else if (Array.isArray(${cur})) ${cur}.push(_entry)`,
|
|
4763
|
+
`${i} else ${fObj}[${fe}.name] = [${cur}, _entry]`,
|
|
4764
|
+
`${i} }`,
|
|
4765
|
+
`${i}}`
|
|
4766
|
+
);
|
|
4767
|
+
}
|
|
4503
4768
|
const ndV = v(ctx, "_nd");
|
|
4504
|
-
const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${
|
|
4505
|
-
const ndExpr = ctx.ns || structural ? `_ctx.build !== undefined ? _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${
|
|
4506
|
-
const
|
|
4769
|
+
const buildExpr = structural ? `{ _tag: 'node', type: ${JSON.stringify(def.type)}, span: { start: ${pos}, end: ${endVar} }, state: ${stV} ?? null, children: ${chV} }` : mkType ? emitInlineMkNodeExpr(mkType, chV, rawV, pos, endVar, tlV) : `${buildRef(ctx)}[${buildIdx}](${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV})`;
|
|
4770
|
+
const ndExpr = ctx.ns || structural ? `_ctx.build !== undefined ? _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${fObj}, { start: ${pos}, end: ${endVar} }, ${rawV}, ${tlV}, ${stV}) : (${buildExpr})` : buildExpr;
|
|
4771
|
+
const hostCollapseExpr = ctx.ns || structural ? `_ctx.build !== undefined && _ctx.build._parsemanCstCollapse !== undefined && ${chV}.length === 1 && ${rawV}.length === 1 && _ctx.build._parsemanCstCollapse(${JSON.stringify(def.type)}, ${chV}[0], ${chV}, ${rawV}) ? ${chV}[0] : (${ndExpr})` : ndExpr;
|
|
4772
|
+
const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
|
|
4773
|
+
const collapseExpr = `${chV}.length === 1 ? ${chV}[0] : (${ndExpr})`;
|
|
4774
|
+
const finalExpr = def.unwrap ? unwrapExpr : def.collapse ? collapseExpr : hostCollapseExpr;
|
|
4507
4775
|
stmts.push(
|
|
4508
4776
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
4509
4777
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
4510
|
-
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && ${ndV}._tag === 'node') ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : '', span: { start: ${pos}, end: ${endVar} } })`
|
|
4778
|
+
`${i}if (${sr}) ${sr}.push((typeof ${ndV} === 'object' && ${ndV} !== null && (${ndV}._tag === 'node' || ${ndV}._tag === 'leaf' || ${ndV}._tag === 'error')) ? ${ndV} : { _tag: 'leaf', value: typeof ${ndV} === 'string' ? ${ndV} : '', span: { start: ${pos}, end: ${endVar} } })`
|
|
4511
4779
|
);
|
|
4512
4780
|
return { stmts, valueVar: ndV, endVar };
|
|
4513
4781
|
}
|
|
@@ -4722,6 +4990,17 @@ function emitDispatch(p, ctx, pos) {
|
|
|
4722
4990
|
endVar: inner.endVar
|
|
4723
4991
|
};
|
|
4724
4992
|
}
|
|
4993
|
+
case "field": {
|
|
4994
|
+
const inner = emit(def.parser, ctx, pos);
|
|
4995
|
+
return {
|
|
4996
|
+
stmts: [
|
|
4997
|
+
...inner.stmts,
|
|
4998
|
+
`${ind(ctx)}if (_ctx._fields) _ctx._fields.push({ name: ${JSON.stringify(def.name)}, value: ${inner.valueVar}, span: { start: ${pos}, end: ${inner.endVar} } })`
|
|
4999
|
+
],
|
|
5000
|
+
valueVar: inner.valueVar,
|
|
5001
|
+
endVar: inner.endVar
|
|
5002
|
+
};
|
|
5003
|
+
}
|
|
4725
5004
|
case "grammar": {
|
|
4726
5005
|
const savedTrivia = ctx.activeTrivia;
|
|
4727
5006
|
const savedKindLabels = ctx.triviaKindLabels;
|
|
@@ -4823,6 +5102,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4823
5102
|
case "trivia":
|
|
4824
5103
|
case "token":
|
|
4825
5104
|
case "label":
|
|
5105
|
+
case "field":
|
|
4826
5106
|
case "optional":
|
|
4827
5107
|
case "many":
|
|
4828
5108
|
case "oneOrMore":
|
|
@@ -4859,6 +5139,7 @@ function childrenOf(def) {
|
|
|
4859
5139
|
case "trivia":
|
|
4860
5140
|
case "token":
|
|
4861
5141
|
case "label":
|
|
5142
|
+
case "field":
|
|
4862
5143
|
case "grammar":
|
|
4863
5144
|
case "not":
|
|
4864
5145
|
case "node":
|
|
@@ -5100,6 +5381,11 @@ function assertRuleName(name) {
|
|
|
5100
5381
|
);
|
|
5101
5382
|
}
|
|
5102
5383
|
}
|
|
5384
|
+
function publicRuleWrapperSource(rule, fnSource) {
|
|
5385
|
+
const labels = rule._meta.triviaKindLabels;
|
|
5386
|
+
if (labels === void 0) return fnSource;
|
|
5387
|
+
return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
|
|
5388
|
+
}
|
|
5103
5389
|
function compileRuleMap(ruleMap) {
|
|
5104
5390
|
for (const [, rule] of ruleMap) markUnusedValues(rule);
|
|
5105
5391
|
const ctx = {
|
|
@@ -5132,7 +5418,7 @@ function compileRuleMap(ruleMap) {
|
|
|
5132
5418
|
ruleNames.set(rule, n === 0 ? base : `${base}$${n}`);
|
|
5133
5419
|
}
|
|
5134
5420
|
ctx.ruleNames = ruleNames;
|
|
5135
|
-
const perEntry = ruleMap.map(([key, rule]) => ({ key, r: emit(rule, ctx, "_pos") }));
|
|
5421
|
+
const perEntry = ruleMap.map(([key, rule]) => ({ key, rule, r: emit(rule, ctx, "_pos") }));
|
|
5136
5422
|
const derivedSrcs = ctx.mapFnSrcs.length === ctx.mapFns.length && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : void 0;
|
|
5137
5423
|
const buildCovered = ctx.buildFns.length === 0 || ctx.buildSrcs.every((s) => s !== null);
|
|
5138
5424
|
const buildSources = ctx.buildFns.length === 0 ? void 0 : ctx.buildSrcs;
|
|
@@ -5162,7 +5448,10 @@ function compileRuleMap(ruleMap) {
|
|
|
5162
5448
|
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
5163
5449
|
`}`
|
|
5164
5450
|
].join("\n");
|
|
5165
|
-
const objBody = perEntry.map(({ key, r }) =>
|
|
5451
|
+
const objBody = perEntry.map(({ key, rule, r }) => {
|
|
5452
|
+
const src = publicRuleWrapperSource(rule, entryFnText(r));
|
|
5453
|
+
return ` ${JSON.stringify(key)}: ${src.split("\n").join("\n ")}`;
|
|
5454
|
+
}).join(",\n");
|
|
5166
5455
|
const replacement = [
|
|
5167
5456
|
`/* @__PURE__ */ (() => {`,
|
|
5168
5457
|
...hoistedDecls,
|
|
@@ -5275,7 +5564,7 @@ function compileLinkable(ruleMapArg, ns) {
|
|
|
5275
5564
|
ctx.recordFail = savedRec;
|
|
5276
5565
|
pushNamedFnDecl(ctx, fn, body.stmts, body.valueVar, body.endVar);
|
|
5277
5566
|
}
|
|
5278
|
-
perEntry.push({ key, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
5567
|
+
perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
5279
5568
|
}
|
|
5280
5569
|
if (ctx.runtimeParsers.length !== 0) return null;
|
|
5281
5570
|
const mfSrcs = ctx.mapFns.length > 0 && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : null;
|
|
@@ -5298,14 +5587,14 @@ function compileLinkable(ruleMapArg, ns) {
|
|
|
5298
5587
|
...privateFns
|
|
5299
5588
|
].filter(Boolean);
|
|
5300
5589
|
const wrappers = /* @__PURE__ */ new Map();
|
|
5301
|
-
for (const { key, r } of perEntry) {
|
|
5302
|
-
wrappers.set(key, [
|
|
5590
|
+
for (const { key, rule, r } of perEntry) {
|
|
5591
|
+
wrappers.set(key, publicRuleWrapperSource(rule, [
|
|
5303
5592
|
`function(input, _pos, _ctx) {`,
|
|
5304
5593
|
` let pos = _pos`,
|
|
5305
5594
|
...r.stmts,
|
|
5306
5595
|
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
5307
5596
|
`}`
|
|
5308
|
-
].join("\n"));
|
|
5597
|
+
].join("\n")));
|
|
5309
5598
|
}
|
|
5310
5599
|
const firstSets = /* @__PURE__ */ new Map();
|
|
5311
5600
|
for (const [key, rule] of ruleMap) {
|
|
@@ -5480,6 +5769,7 @@ function childrenOf2(def) {
|
|
|
5480
5769
|
case "trivia":
|
|
5481
5770
|
case "token":
|
|
5482
5771
|
case "label":
|
|
5772
|
+
case "field":
|
|
5483
5773
|
case "not":
|
|
5484
5774
|
case "node":
|
|
5485
5775
|
case "expect":
|
|
@@ -5565,6 +5855,7 @@ function evalRuleMapIR(ir) {
|
|
|
5565
5855
|
"skip",
|
|
5566
5856
|
"trivia",
|
|
5567
5857
|
"label",
|
|
5858
|
+
"field",
|
|
5568
5859
|
"expect",
|
|
5569
5860
|
"_tf",
|
|
5570
5861
|
"_nd",
|
|
@@ -5591,6 +5882,7 @@ function evalRuleMapIR(ir) {
|
|
|
5591
5882
|
skip,
|
|
5592
5883
|
trivia,
|
|
5593
5884
|
label,
|
|
5885
|
+
field,
|
|
5594
5886
|
expect,
|
|
5595
5887
|
_tf,
|
|
5596
5888
|
_nd
|
|
@@ -5724,6 +6016,8 @@ ${body}
|
|
|
5724
6016
|
return `token(${kid(def.parser)})`;
|
|
5725
6017
|
case "label":
|
|
5726
6018
|
return `label(${JSON.stringify(def.label)}, ${kid(def.parser)})`;
|
|
6019
|
+
case "field":
|
|
6020
|
+
return `field(${JSON.stringify(def.name)}, ${kid(def.parser)})`;
|
|
5727
6021
|
case "expect":
|
|
5728
6022
|
return `expect(${kid(def.parser)}${def.label !== void 0 ? `, ${JSON.stringify(def.label)}` : ""})`;
|
|
5729
6023
|
case "skip":
|
|
@@ -5736,7 +6030,11 @@ ${body}
|
|
|
5736
6030
|
}
|
|
5737
6031
|
case "node": {
|
|
5738
6032
|
if (def.build !== void 0 && def.buildSrc === void 0) throw new Unserializable("node build without buildSrc");
|
|
5739
|
-
const opts = def.collapse ? `, { collapse: true }` : "";
|
|
6033
|
+
const opts = def.unwrap || def.collapse ? `, { ${def.unwrap ? "unwrap: true" : "collapse: true"} }` : "";
|
|
6034
|
+
if (def.type === void 0) {
|
|
6035
|
+
if (def.buildSrc !== void 0) throw new Unserializable("inferred node build without inferred type");
|
|
6036
|
+
return opts ? `node(${kid(def.parser)}, undefined${opts})` : `node(${kid(def.parser)})`;
|
|
6037
|
+
}
|
|
5740
6038
|
if (def.buildSrc !== void 0) return `_nd(${JSON.stringify(def.type)}, ${kid(def.parser)}, ${JSON.stringify(def.buildSrc)}${opts})`;
|
|
5741
6039
|
return opts ? `node(${JSON.stringify(def.type)}, ${kid(def.parser)}, undefined${opts})` : `node(${JSON.stringify(def.type)}, ${kid(def.parser)})`;
|
|
5742
6040
|
}
|
|
@@ -5763,8 +6061,9 @@ function fusedBody(pieces) {
|
|
|
5763
6061
|
}
|
|
5764
6062
|
}
|
|
5765
6063
|
const contributing = new Set(winner.values());
|
|
5766
|
-
const
|
|
5767
|
-
const
|
|
6064
|
+
const contributingPieces = [...contributing];
|
|
6065
|
+
const needsEmptyTl = contributingPieces.some((p) => p.needsEmptyTl);
|
|
6066
|
+
const needsHostReads = contributingPieces.some((p) => p.needsHostReads);
|
|
5768
6067
|
const lines = [
|
|
5769
6068
|
// Shared sentinel protocol (must match NAMED_FN_FAIL / NAMED_FN_END in codegen).
|
|
5770
6069
|
"const _pfFail = {}",
|
|
@@ -5772,7 +6071,7 @@ function fusedBody(pieces) {
|
|
|
5772
6071
|
...needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [],
|
|
5773
6072
|
...needsHostReads ? [HOST_READS_DECL] : [],
|
|
5774
6073
|
// Each contributing artifact's namespaced private prelude (regexes, _pf, …).
|
|
5775
|
-
...[...
|
|
6074
|
+
...[...new Set(contributingPieces.flatMap((p) => p.prelude))],
|
|
5776
6075
|
// The winning `_r_<Name>` function for each rule (one per name → no redeclare).
|
|
5777
6076
|
...[...winner].map(([k, p]) => p.ruleFns.get(k))
|
|
5778
6077
|
];
|
|
@@ -5795,7 +6094,7 @@ function fusedBody(pieces) {
|
|
|
5795
6094
|
}
|
|
5796
6095
|
);
|
|
5797
6096
|
const env = {};
|
|
5798
|
-
for (const p of
|
|
6097
|
+
for (const p of contributingPieces) {
|
|
5799
6098
|
if (p.mfFns.length) env[`${p.ns}mf`] = p.mfFns;
|
|
5800
6099
|
if (p.buildFns.length) env[`${p.ns}build`] = p.buildFns;
|
|
5801
6100
|
}
|
|
@@ -5843,6 +6142,7 @@ var SUPPORTED = {
|
|
|
5843
6142
|
sepBy: (...a) => sepBy(a[0], a[1]),
|
|
5844
6143
|
trivia: (...a) => trivia(a[0]),
|
|
5845
6144
|
label: (...a) => label(a[0], a[1]),
|
|
6145
|
+
field: (...a) => field(a[0], a[1]),
|
|
5846
6146
|
noTrivia: (...a) => noTrivia(a[0]),
|
|
5847
6147
|
token: (...a) => token(a[0]),
|
|
5848
6148
|
expect: (...a) => expect(a[0], a[1])
|
|
@@ -5863,19 +6163,20 @@ function scopeGet(scope, name, mfs) {
|
|
|
5863
6163
|
if (isCombinator(entry)) return entry;
|
|
5864
6164
|
return null;
|
|
5865
6165
|
}
|
|
5866
|
-
function
|
|
5867
|
-
if (expr.type !== "ObjectExpression") return
|
|
6166
|
+
function staticNodeOptions(expr) {
|
|
6167
|
+
if (expr.type !== "ObjectExpression") return void 0;
|
|
6168
|
+
const opts = {};
|
|
5868
6169
|
for (const prop of expr.properties) {
|
|
5869
6170
|
const p = prop;
|
|
5870
6171
|
if (p.computed) continue;
|
|
5871
6172
|
const key = p.key;
|
|
5872
6173
|
const name = key.type === "Identifier" ? key.name : key.type === "Literal" ? String(key.value) : void 0;
|
|
5873
|
-
if (name === "collapse") {
|
|
6174
|
+
if (name === "unwrap" || name === "collapse") {
|
|
5874
6175
|
const val = p.value;
|
|
5875
|
-
|
|
6176
|
+
if ((val.type === "Literal" || val.type === "BooleanLiteral") && val.value === true) opts[name] = true;
|
|
5876
6177
|
}
|
|
5877
6178
|
}
|
|
5878
|
-
return
|
|
6179
|
+
return opts.unwrap || opts.collapse ? opts : void 0;
|
|
5879
6180
|
}
|
|
5880
6181
|
function exprToCombi(node2, scope, code, mfs) {
|
|
5881
6182
|
if (node2.type === "Identifier") return scopeGet(scope, node2.name, mfs);
|
|
@@ -5925,18 +6226,22 @@ function exprToCombi(node2, scope, code, mfs) {
|
|
|
5925
6226
|
}
|
|
5926
6227
|
}
|
|
5927
6228
|
if (callee.name === "node" && code !== void 0) {
|
|
5928
|
-
const [
|
|
5929
|
-
if (!
|
|
5930
|
-
const
|
|
5931
|
-
|
|
6229
|
+
const [firstArg, secondArg, thirdArg, fourthArg] = node2.arguments;
|
|
6230
|
+
if (!firstArg || firstArg.type === "SpreadElement") return null;
|
|
6231
|
+
const firstVal = anyValue(firstArg, scope, code, mfs);
|
|
6232
|
+
const explicitType = typeof firstVal === "string" ? firstVal : void 0;
|
|
6233
|
+
const parserArg = explicitType !== void 0 ? secondArg : firstArg;
|
|
6234
|
+
const buildArg = explicitType !== void 0 ? thirdArg : secondArg;
|
|
6235
|
+
const optsArg = explicitType !== void 0 ? fourthArg : thirdArg;
|
|
6236
|
+
if (!parserArg || parserArg.type === "SpreadElement") return null;
|
|
5932
6237
|
const inner = anyValue(parserArg, scope, code, mfs);
|
|
5933
6238
|
if (!isCombinator(inner)) return null;
|
|
5934
6239
|
const be = buildArg;
|
|
5935
6240
|
const hasBuild = be !== void 0 && be.type !== "SpreadElement" && !(be.type === "Identifier" && be.name === "undefined");
|
|
5936
6241
|
const buildSrc = hasBuild ? code.slice(be.start, be.end) : void 0;
|
|
5937
|
-
const
|
|
6242
|
+
const opts = optsArg !== void 0 && optsArg.type !== "SpreadElement" ? staticNodeOptions(optsArg) : void 0;
|
|
5938
6243
|
try {
|
|
5939
|
-
const combi = node(
|
|
6244
|
+
const combi = explicitType !== void 0 ? node(explicitType, inner, hasBuild ? () => null : void 0, opts) : node(inner, hasBuild ? () => null : void 0, opts);
|
|
5940
6245
|
if (combi._def.tag === "node" && buildSrc !== void 0) combi._def.buildSrc = buildSrc;
|
|
5941
6246
|
return combi;
|
|
5942
6247
|
} catch {
|
|
@@ -6202,7 +6507,9 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
6202
6507
|
if (!keys) return null;
|
|
6203
6508
|
const ruleRefs = /* @__PURE__ */ new Map();
|
|
6204
6509
|
const tagRef = (r, name) => {
|
|
6510
|
+
;
|
|
6205
6511
|
r._ruleName = name;
|
|
6512
|
+
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = name;
|
|
6206
6513
|
};
|
|
6207
6514
|
for (const key of keys) {
|
|
6208
6515
|
if (!ruleRefs.has(key)) {
|
|
@@ -6234,6 +6541,7 @@ function evaluateParserFactory(factoryNode, scope, code, mapFnSources) {
|
|
|
6234
6541
|
for (const [key, e] of finalByKey) {
|
|
6235
6542
|
const val = anyValue(e.value, e.scope, e.code, mapFnSources);
|
|
6236
6543
|
if (!isCombinator(val)) return null;
|
|
6544
|
+
tagRef(val, key);
|
|
6237
6545
|
ruleRefs.get(key).define(val);
|
|
6238
6546
|
}
|
|
6239
6547
|
return ruleRefs;
|