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/index.js
CHANGED
|
@@ -252,7 +252,8 @@ function saveCstMark(ctx) {
|
|
|
252
252
|
return {
|
|
253
253
|
raw: cstRawLen(ctx),
|
|
254
254
|
tlog: cstTlLen(ctx),
|
|
255
|
-
leaves: cstLeavesLen(ctx)
|
|
255
|
+
leaves: cstLeavesLen(ctx),
|
|
256
|
+
fields: ctx._fields?.length ?? 0
|
|
256
257
|
};
|
|
257
258
|
}
|
|
258
259
|
function rollbackBufList(b, keyMulti, keySingle, len) {
|
|
@@ -276,11 +277,13 @@ function rollbackCstCapture(ctx, mark) {
|
|
|
276
277
|
if (mark.tlog === 0) b.tl = void 0;
|
|
277
278
|
else b.tl.length = mark.tlog;
|
|
278
279
|
}
|
|
280
|
+
if (ctx._fields) ctx._fields.length = mark.fields;
|
|
279
281
|
return;
|
|
280
282
|
}
|
|
281
283
|
if (ctx._cstRawChildren) ctx._cstRawChildren.length = mark.raw;
|
|
282
284
|
if (ctx._cstTriviaLog) ctx._cstTriviaLog.length = mark.tlog;
|
|
283
285
|
if (ctx._cstLeaves) ctx._cstLeaves.length = mark.leaves;
|
|
286
|
+
if (ctx._fields) ctx._fields.length = mark.fields;
|
|
284
287
|
}
|
|
285
288
|
function pushCstTriviaEntry(ctx, start, end, kindIndex) {
|
|
286
289
|
const insertIdx = cstRawLen(ctx);
|
|
@@ -324,9 +327,9 @@ function asciiFoldEq(a, b) {
|
|
|
324
327
|
}
|
|
325
328
|
function literal(value, opts = {}) {
|
|
326
329
|
const caseInsensitive = opts.caseInsensitive ?? false;
|
|
327
|
-
const
|
|
330
|
+
const firstSet2 = value.length > 0 ? fromChar(value.codePointAt(0)) : empty();
|
|
328
331
|
const meta = {
|
|
329
|
-
firstSet,
|
|
332
|
+
firstSet: firstSet2,
|
|
330
333
|
canMatchNewline: value.includes("\n"),
|
|
331
334
|
isTrivia: false
|
|
332
335
|
};
|
|
@@ -338,7 +341,7 @@ function literal(value, opts = {}) {
|
|
|
338
341
|
meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? firstLower === firstUpper ? { kind: "ranges", ranges: [{ lo: firstLower, hi: firstLower }] } : { kind: "ranges", ranges: [
|
|
339
342
|
{ lo: firstLower, hi: firstLower },
|
|
340
343
|
{ lo: firstUpper, hi: firstUpper }
|
|
341
|
-
] } :
|
|
344
|
+
] } : firstSet2;
|
|
342
345
|
}
|
|
343
346
|
return {
|
|
344
347
|
_tag: "literal",
|
|
@@ -361,68 +364,66 @@ function literal(value, opts = {}) {
|
|
|
361
364
|
};
|
|
362
365
|
}
|
|
363
366
|
|
|
364
|
-
// src/
|
|
365
|
-
var
|
|
366
|
-
function registerRegexAnalyzer(analyzer) {
|
|
367
|
-
firstSetAnalyzer = analyzer;
|
|
368
|
-
}
|
|
369
|
-
var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
|
|
370
|
-
var SCAN_BAIL_AT = 64;
|
|
367
|
+
// src/regex/classes.ts
|
|
368
|
+
var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
371
369
|
var SPACE_RANGES = [
|
|
372
370
|
[9, 13],
|
|
373
371
|
[32, 32],
|
|
374
372
|
[160, 160],
|
|
375
373
|
[5760, 5760],
|
|
376
374
|
[8192, 8202],
|
|
377
|
-
[8232,
|
|
375
|
+
[8232, 8232],
|
|
376
|
+
[8233, 8233],
|
|
378
377
|
[8239, 8239],
|
|
379
378
|
[8287, 8287],
|
|
380
379
|
[12288, 12288],
|
|
381
380
|
[65279, 65279]
|
|
382
381
|
];
|
|
383
|
-
var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
384
382
|
function shorthandRanges(ch) {
|
|
385
383
|
if (ch === "d") return [[48, 57]];
|
|
386
384
|
if (ch === "s") return SPACE_RANGES;
|
|
387
385
|
return [[48, 57], [65, 90], [97, 122], [95, 95]];
|
|
388
386
|
}
|
|
389
|
-
function
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
394
|
-
return false;
|
|
387
|
+
function readUnicodeEscape(body, i) {
|
|
388
|
+
if (body[i] !== "\\" || body[i + 1] !== "u") return null;
|
|
389
|
+
const hex = body.slice(i + 2, i + 6);
|
|
390
|
+
if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
|
|
391
|
+
return { cp: Number.parseInt(hex, 16), next: i + 6 };
|
|
395
392
|
}
|
|
396
|
-
function
|
|
397
|
-
if (body.startsWith("^")) return null;
|
|
393
|
+
function parseClassRanges(body) {
|
|
398
394
|
const ranges = [];
|
|
399
395
|
let i = 0;
|
|
400
396
|
const readAtom = () => {
|
|
401
397
|
const ch = body[i];
|
|
402
398
|
if (ch === void 0) return null;
|
|
403
399
|
if (ch === "\\") {
|
|
404
|
-
const
|
|
405
|
-
if (
|
|
400
|
+
const uni = readUnicodeEscape(body, i);
|
|
401
|
+
if (uni) {
|
|
402
|
+
i = uni.next;
|
|
403
|
+
return { cp: uni.cp };
|
|
404
|
+
}
|
|
405
|
+
const e = body[i + 1];
|
|
406
|
+
if (e === void 0) return null;
|
|
406
407
|
i += 2;
|
|
407
|
-
if (
|
|
408
|
-
if (
|
|
409
|
-
if (
|
|
410
|
-
return { cp:
|
|
408
|
+
if (e in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[e] };
|
|
409
|
+
if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges(e) };
|
|
410
|
+
if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
|
|
411
|
+
return { cp: e.codePointAt(0) };
|
|
411
412
|
}
|
|
412
|
-
i
|
|
413
|
-
return { cp: ch.
|
|
413
|
+
i += ch.length;
|
|
414
|
+
return { cp: ch.codePointAt(0) };
|
|
414
415
|
};
|
|
415
416
|
while (i < body.length) {
|
|
416
417
|
const lo = readAtom();
|
|
417
|
-
if (
|
|
418
|
-
if ("
|
|
419
|
-
ranges.push(...lo.
|
|
418
|
+
if (lo === null) return null;
|
|
419
|
+
if ("set" in lo) {
|
|
420
|
+
ranges.push(...lo.set);
|
|
420
421
|
continue;
|
|
421
422
|
}
|
|
422
423
|
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
423
|
-
i
|
|
424
|
+
i += 1;
|
|
424
425
|
const hi = readAtom();
|
|
425
|
-
if (
|
|
426
|
+
if (hi === null || "set" in hi) return null;
|
|
426
427
|
ranges.push([lo.cp, hi.cp]);
|
|
427
428
|
} else {
|
|
428
429
|
ranges.push([lo.cp, lo.cp]);
|
|
@@ -430,6 +431,25 @@ function readClassRanges(body) {
|
|
|
430
431
|
}
|
|
431
432
|
return ranges.length ? ranges : null;
|
|
432
433
|
}
|
|
434
|
+
|
|
435
|
+
// src/combinators/regex.ts
|
|
436
|
+
var firstSetAnalyzer = null;
|
|
437
|
+
function registerRegexAnalyzer(analyzer) {
|
|
438
|
+
firstSetAnalyzer = analyzer;
|
|
439
|
+
}
|
|
440
|
+
var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
|
|
441
|
+
var SCAN_BAIL_AT = 64;
|
|
442
|
+
function inRanges(cp, ranges) {
|
|
443
|
+
for (let i = 0; i < ranges.length; i++) {
|
|
444
|
+
const [lo, hi] = ranges[i];
|
|
445
|
+
if (cp >= lo && cp <= hi) return true;
|
|
446
|
+
}
|
|
447
|
+
return false;
|
|
448
|
+
}
|
|
449
|
+
function readClassRanges(body) {
|
|
450
|
+
if (body.startsWith("^")) return null;
|
|
451
|
+
return parseClassRanges(body);
|
|
452
|
+
}
|
|
433
453
|
function shortScanner(source, flags) {
|
|
434
454
|
if (/[imsuvy]/.test(flags)) return null;
|
|
435
455
|
let ranges = null;
|
|
@@ -463,8 +483,8 @@ function regex(pattern, flags = "") {
|
|
|
463
483
|
const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
|
|
464
484
|
const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
|
|
465
485
|
const scan = shortScanner(source, resolvedFlags);
|
|
466
|
-
const { firstSet, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
|
|
467
|
-
const meta = { firstSet, canMatchNewline, isTrivia: false };
|
|
486
|
+
const { firstSet: firstSet2, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
|
|
487
|
+
const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
|
|
468
488
|
return {
|
|
469
489
|
_tag: "regex",
|
|
470
490
|
_meta: meta,
|
|
@@ -492,111 +512,266 @@ function regex(pattern, flags = "") {
|
|
|
492
512
|
};
|
|
493
513
|
}
|
|
494
514
|
|
|
495
|
-
// src/
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
return extractFirstSet(ast.body);
|
|
501
|
-
} catch {
|
|
502
|
-
return { firstSet: any(), canMatchNewline: true };
|
|
503
|
-
}
|
|
515
|
+
// src/regex/first-set.ts
|
|
516
|
+
var ANY = { t: "any" };
|
|
517
|
+
var EMPTY2 = { t: "empty" };
|
|
518
|
+
function charNode(set, nl) {
|
|
519
|
+
return { t: "char", set, nl };
|
|
504
520
|
}
|
|
505
|
-
function
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
521
|
+
function rangesToSet(ranges) {
|
|
522
|
+
let fs = empty();
|
|
523
|
+
for (const [lo, hi] of ranges) fs = union(fs, fromRange(lo, hi));
|
|
524
|
+
return fs;
|
|
525
|
+
}
|
|
526
|
+
function rangesHaveNewline(ranges) {
|
|
527
|
+
return ranges.some(([lo, hi]) => lo <= 10 && 10 <= hi);
|
|
528
|
+
}
|
|
529
|
+
var BAIL = /* @__PURE__ */ Symbol("regex-bail");
|
|
530
|
+
function parseRegex(src) {
|
|
531
|
+
let i = 0;
|
|
532
|
+
const parseAlt = () => {
|
|
533
|
+
const arms = [parseSeq()];
|
|
534
|
+
while (src[i] === "|") {
|
|
535
|
+
i++;
|
|
536
|
+
arms.push(parseSeq());
|
|
511
537
|
}
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
538
|
+
return arms.length === 1 ? arms[0] : { t: "alt", arms };
|
|
539
|
+
};
|
|
540
|
+
const parseSeq = () => {
|
|
541
|
+
const parts = [];
|
|
542
|
+
while (i < src.length) {
|
|
543
|
+
const ch = src[i];
|
|
544
|
+
if (ch === "|" || ch === ")") break;
|
|
545
|
+
parts.push(parseQuantified());
|
|
546
|
+
}
|
|
547
|
+
if (parts.length === 0) return EMPTY2;
|
|
548
|
+
return parts.length === 1 ? parts[0] : { t: "seq", parts };
|
|
549
|
+
};
|
|
550
|
+
const parseQuantified = () => {
|
|
551
|
+
const atom = parseAtom();
|
|
552
|
+
const ch = src[i];
|
|
553
|
+
let min = null;
|
|
554
|
+
if (ch === "*") {
|
|
555
|
+
min = 0;
|
|
556
|
+
i++;
|
|
557
|
+
} else if (ch === "+") {
|
|
558
|
+
min = 1;
|
|
559
|
+
i++;
|
|
560
|
+
} else if (ch === "?") {
|
|
561
|
+
min = 0;
|
|
562
|
+
i++;
|
|
563
|
+
} else if (ch === "{") {
|
|
564
|
+
min = parseBraceQuantifier();
|
|
515
565
|
}
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
566
|
+
if (min === null) return atom;
|
|
567
|
+
if (src[i] === "?") i++;
|
|
568
|
+
return { t: "rep", node: atom, min };
|
|
569
|
+
};
|
|
570
|
+
const parseBraceQuantifier = () => {
|
|
571
|
+
const close = src.indexOf("}", i);
|
|
572
|
+
if (close === -1) return null;
|
|
573
|
+
const m = /^(\d+)(?:,(\d*))?$/.exec(src.slice(i + 1, close));
|
|
574
|
+
if (!m) return null;
|
|
575
|
+
i = close + 1;
|
|
576
|
+
return Number.parseInt(m[1], 10);
|
|
577
|
+
};
|
|
578
|
+
const parseAtom = () => {
|
|
579
|
+
const ch = src[i];
|
|
580
|
+
switch (ch) {
|
|
581
|
+
case "(":
|
|
582
|
+
return parseGroup();
|
|
583
|
+
case "[":
|
|
584
|
+
return parseClass();
|
|
585
|
+
case ".":
|
|
586
|
+
i++;
|
|
587
|
+
return charNode(any(), false);
|
|
588
|
+
// `.` matches any char except line terminators
|
|
589
|
+
case "\\":
|
|
590
|
+
return parseEscape();
|
|
591
|
+
case "^":
|
|
592
|
+
case "$":
|
|
593
|
+
i++;
|
|
594
|
+
return EMPTY2;
|
|
595
|
+
// anchors are zero-width
|
|
596
|
+
case "{":
|
|
597
|
+
i++;
|
|
598
|
+
return charNode(fromRange(123, 123), false);
|
|
599
|
+
// a `{` with nothing to quantify is a literal brace
|
|
600
|
+
default:
|
|
601
|
+
i += ch.length;
|
|
602
|
+
return charNode(fromRange(ch.codePointAt(0), ch.codePointAt(0)), ch === "\n");
|
|
534
603
|
}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
}
|
|
546
|
-
|
|
604
|
+
};
|
|
605
|
+
const parseGroup = () => {
|
|
606
|
+
i++;
|
|
607
|
+
let lookaround = false;
|
|
608
|
+
if (src[i] === "?") {
|
|
609
|
+
const c1 = src[i + 1];
|
|
610
|
+
if (c1 === ":") i += 2;
|
|
611
|
+
else if (c1 === "=" || c1 === "!") {
|
|
612
|
+
i += 2;
|
|
613
|
+
lookaround = true;
|
|
614
|
+
} else if (c1 === "<") {
|
|
615
|
+
const c2 = src[i + 2];
|
|
616
|
+
if (c2 === "=" || c2 === "!") {
|
|
617
|
+
i += 3;
|
|
618
|
+
lookaround = true;
|
|
619
|
+
} else {
|
|
620
|
+
const gt = src.indexOf(">", i);
|
|
621
|
+
if (gt === -1) throw BAIL;
|
|
622
|
+
i = gt + 1;
|
|
623
|
+
}
|
|
624
|
+
} else throw BAIL;
|
|
547
625
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
};
|
|
566
|
-
if (val === "s") return { firstSet: fromRange(9, 13), canMatchNewline: true };
|
|
567
|
-
if (val === "n") return { firstSet: fromRange(10, 10), canMatchNewline: true };
|
|
626
|
+
const inner = parseAlt();
|
|
627
|
+
if (src[i] !== ")") throw BAIL;
|
|
628
|
+
i++;
|
|
629
|
+
return lookaround ? EMPTY2 : inner;
|
|
630
|
+
};
|
|
631
|
+
const parseClass = () => {
|
|
632
|
+
let k = i + 1;
|
|
633
|
+
const negated = src[k] === "^";
|
|
634
|
+
if (negated) k++;
|
|
635
|
+
let body = "";
|
|
636
|
+
while (k < src.length && src[k] !== "]") {
|
|
637
|
+
if (src[k] === "\\") {
|
|
638
|
+
body += src[k] + (src[k + 1] ?? "");
|
|
639
|
+
k += 2;
|
|
640
|
+
} else {
|
|
641
|
+
body += src[k];
|
|
642
|
+
k++;
|
|
568
643
|
}
|
|
569
|
-
return { firstSet: any(), canMatchNewline: true };
|
|
570
644
|
}
|
|
571
|
-
|
|
572
|
-
|
|
645
|
+
if (src[k] !== "]") throw BAIL;
|
|
646
|
+
i = k + 1;
|
|
647
|
+
if (negated) return charNode(any(), true);
|
|
648
|
+
const ranges = parseClassRanges(body);
|
|
649
|
+
if (!ranges) return charNode(any(), true);
|
|
650
|
+
return charNode(rangesToSet(ranges), rangesHaveNewline(ranges));
|
|
651
|
+
};
|
|
652
|
+
const parseEscape = () => {
|
|
653
|
+
const e = src[i + 1];
|
|
654
|
+
if (e === void 0) throw BAIL;
|
|
655
|
+
if (e === "u" && /^[0-9a-fA-F]{4}$/.test(src.slice(i + 2, i + 6))) {
|
|
656
|
+
const cp = Number.parseInt(src.slice(i + 2, i + 6), 16);
|
|
657
|
+
i += 6;
|
|
658
|
+
return charNode(fromRange(cp, cp), cp === 10);
|
|
659
|
+
}
|
|
660
|
+
if (e === "x" && /^[0-9a-fA-F]{2}$/.test(src.slice(i + 2, i + 4))) {
|
|
661
|
+
const cp = Number.parseInt(src.slice(i + 2, i + 4), 16);
|
|
662
|
+
i += 4;
|
|
663
|
+
return charNode(fromRange(cp, cp), cp === 10);
|
|
664
|
+
}
|
|
665
|
+
i += 2;
|
|
666
|
+
switch (e) {
|
|
667
|
+
case "d":
|
|
668
|
+
return charNode(rangesToSet(shorthandRanges("d")), false);
|
|
669
|
+
case "w":
|
|
670
|
+
return charNode(rangesToSet(shorthandRanges("w")), false);
|
|
671
|
+
case "s":
|
|
672
|
+
return charNode(rangesToSet(shorthandRanges("s")), true);
|
|
673
|
+
case "D":
|
|
674
|
+
case "W":
|
|
675
|
+
case "S":
|
|
676
|
+
return charNode(any(), true);
|
|
677
|
+
// negated shorthand → widen
|
|
678
|
+
case "b":
|
|
679
|
+
case "B":
|
|
680
|
+
return EMPTY2;
|
|
681
|
+
// word boundary: zero-width
|
|
682
|
+
case "n":
|
|
683
|
+
return charNode(fromRange(10, 10), true);
|
|
684
|
+
case "r":
|
|
685
|
+
return charNode(fromRange(13, 13), false);
|
|
686
|
+
case "t":
|
|
687
|
+
return charNode(fromRange(9, 9), false);
|
|
688
|
+
case "f":
|
|
689
|
+
return charNode(fromRange(12, 12), false);
|
|
690
|
+
case "v":
|
|
691
|
+
return charNode(fromRange(11, 11), false);
|
|
692
|
+
case "0":
|
|
693
|
+
return charNode(fromRange(0, 0), false);
|
|
694
|
+
default:
|
|
695
|
+
if (e >= "1" && e <= "9") return ANY;
|
|
696
|
+
return charNode(fromRange(e.codePointAt(0), e.codePointAt(0)), e === "\n");
|
|
697
|
+
}
|
|
698
|
+
};
|
|
699
|
+
const node2 = parseAlt();
|
|
700
|
+
if (i < src.length) throw BAIL;
|
|
701
|
+
return node2;
|
|
702
|
+
}
|
|
703
|
+
function nullable(n) {
|
|
704
|
+
switch (n.t) {
|
|
705
|
+
case "char":
|
|
706
|
+
return false;
|
|
707
|
+
case "any":
|
|
708
|
+
return true;
|
|
709
|
+
case "empty":
|
|
710
|
+
return true;
|
|
711
|
+
case "seq":
|
|
712
|
+
return n.parts.every(nullable);
|
|
713
|
+
case "alt":
|
|
714
|
+
return n.arms.some(nullable);
|
|
715
|
+
case "rep":
|
|
716
|
+
return n.min === 0 || nullable(n.node);
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
function firstSet(n) {
|
|
720
|
+
switch (n.t) {
|
|
721
|
+
case "char":
|
|
722
|
+
return n.set;
|
|
723
|
+
case "any":
|
|
724
|
+
return any();
|
|
725
|
+
case "empty":
|
|
726
|
+
return empty();
|
|
727
|
+
case "rep":
|
|
728
|
+
return firstSet(n.node);
|
|
729
|
+
case "alt": {
|
|
573
730
|
let fs = empty();
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
if (expr.type === "ClassRange") {
|
|
577
|
-
const from = expr.from.codePoint;
|
|
578
|
-
const to = expr.to.codePoint;
|
|
579
|
-
fs = union(fs, fromRange(from, to));
|
|
580
|
-
if (from <= 10 && 10 <= to) canNL = true;
|
|
581
|
-
} else if (expr.type === "Char") {
|
|
582
|
-
const r = extractFirstSet(expr);
|
|
583
|
-
fs = union(fs, r.firstSet);
|
|
584
|
-
canNL = canNL || r.canMatchNewline;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
if (node2.negative) return { firstSet: any(), canMatchNewline: true };
|
|
588
|
-
return { firstSet: fs, canMatchNewline: canNL };
|
|
731
|
+
for (const arm of n.arms) fs = union(fs, firstSet(arm));
|
|
732
|
+
return fs;
|
|
589
733
|
}
|
|
590
|
-
case "
|
|
591
|
-
|
|
734
|
+
case "seq": {
|
|
735
|
+
let fs = empty();
|
|
736
|
+
for (const part of n.parts) {
|
|
737
|
+
fs = union(fs, firstSet(part));
|
|
738
|
+
if (!nullable(part)) break;
|
|
739
|
+
}
|
|
740
|
+
return fs;
|
|
592
741
|
}
|
|
593
|
-
|
|
594
|
-
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
function firstCanBeNewline(n) {
|
|
745
|
+
switch (n.t) {
|
|
746
|
+
case "char":
|
|
747
|
+
return n.nl;
|
|
748
|
+
case "any":
|
|
749
|
+
return true;
|
|
750
|
+
case "empty":
|
|
751
|
+
return false;
|
|
752
|
+
case "rep":
|
|
753
|
+
return firstCanBeNewline(n.node);
|
|
754
|
+
case "alt":
|
|
755
|
+
return n.arms.some(firstCanBeNewline);
|
|
756
|
+
case "seq": {
|
|
757
|
+
for (const part of n.parts) {
|
|
758
|
+
if (firstCanBeNewline(part)) return true;
|
|
759
|
+
if (!nullable(part)) break;
|
|
760
|
+
}
|
|
761
|
+
return false;
|
|
595
762
|
}
|
|
596
|
-
default:
|
|
597
|
-
return { firstSet: any(), canMatchNewline: true };
|
|
598
763
|
}
|
|
599
764
|
}
|
|
765
|
+
function firstSetFromRegex(source) {
|
|
766
|
+
let ast;
|
|
767
|
+
try {
|
|
768
|
+
ast = parseRegex(source);
|
|
769
|
+
} catch {
|
|
770
|
+
return { firstSet: any(), canMatchNewline: true };
|
|
771
|
+
}
|
|
772
|
+
if (nullable(ast)) return { firstSet: any(), canMatchNewline: true };
|
|
773
|
+
return { firstSet: firstSet(ast), canMatchNewline: firstCanBeNewline(ast) };
|
|
774
|
+
}
|
|
600
775
|
|
|
601
776
|
// src/combinators/keywords.ts
|
|
602
777
|
function word(str, boundary = "_0-9A-Za-z") {
|
|
@@ -614,19 +789,19 @@ function keywords(words, opts = {}) {
|
|
|
614
789
|
const boundary = opts.boundary ? `(?![${opts.boundary}])` : "";
|
|
615
790
|
const flags = opts.caseInsensitive ? "iuy" : "uy";
|
|
616
791
|
const re = new RegExp(`(?:${alt})${boundary}`, flags);
|
|
617
|
-
let
|
|
792
|
+
let firstSet2 = empty();
|
|
618
793
|
for (const w of sorted) {
|
|
619
794
|
if (w.length === 0) continue;
|
|
620
795
|
const cp = w.codePointAt(0);
|
|
621
|
-
|
|
796
|
+
firstSet2 = union(firstSet2, fromChar(cp));
|
|
622
797
|
if (opts.caseInsensitive) {
|
|
623
798
|
const u = String.fromCodePoint(cp).toUpperCase().codePointAt(0);
|
|
624
799
|
const l = String.fromCodePoint(cp).toLowerCase().codePointAt(0);
|
|
625
|
-
if (u !== void 0)
|
|
626
|
-
if (l !== void 0)
|
|
800
|
+
if (u !== void 0) firstSet2 = union(firstSet2, fromChar(u));
|
|
801
|
+
if (l !== void 0) firstSet2 = union(firstSet2, fromChar(l));
|
|
627
802
|
}
|
|
628
803
|
}
|
|
629
|
-
const meta = { firstSet, canMatchNewline: false, isTrivia: false };
|
|
804
|
+
const meta = { firstSet: firstSet2, canMatchNewline: false, isTrivia: false };
|
|
630
805
|
return {
|
|
631
806
|
_tag: "keywords",
|
|
632
807
|
_meta: meta,
|
|
@@ -1020,10 +1195,10 @@ function needsDeferredTriviaCommit(ctx) {
|
|
|
1020
1195
|
}
|
|
1021
1196
|
function saveTriviaMark(ctx) {
|
|
1022
1197
|
const m = saveCstMark(ctx);
|
|
1023
|
-
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1198
|
+
return { raw: m.raw, tlog: m.tlog, leaves: m.leaves, fields: m.fields, log: ctx._triviaLog ? ctx._triviaLog.length : 0 };
|
|
1024
1199
|
}
|
|
1025
1200
|
function rollbackTrivia(ctx, mark) {
|
|
1026
|
-
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves });
|
|
1201
|
+
rollbackCstCapture(ctx, { raw: mark.raw, tlog: mark.tlog, leaves: mark.leaves, fields: mark.fields });
|
|
1027
1202
|
if (ctx._triviaLog) ctx._triviaLog.length = mark.log;
|
|
1028
1203
|
}
|
|
1029
1204
|
function scanWithLabels(input, cur, ctx) {
|
|
@@ -1397,6 +1572,13 @@ function ref() {
|
|
|
1397
1572
|
define(p) {
|
|
1398
1573
|
if (resolved) throw new Error("ref<T>() already defined");
|
|
1399
1574
|
resolved = p;
|
|
1575
|
+
meta.firstSet = p._meta.firstSet;
|
|
1576
|
+
meta.canMatchNewline = p._meta.canMatchNewline;
|
|
1577
|
+
meta.isTrivia = p._meta.isTrivia;
|
|
1578
|
+
if (p._meta.triviaKindLabels !== void 0) meta.triviaKindLabels = p._meta.triviaKindLabels;
|
|
1579
|
+
else delete meta.triviaKindLabels;
|
|
1580
|
+
if (p._meta.disjoint !== void 0) meta.disjoint = p._meta.disjoint;
|
|
1581
|
+
else delete meta.disjoint;
|
|
1400
1582
|
}
|
|
1401
1583
|
};
|
|
1402
1584
|
return slot;
|
|
@@ -1437,6 +1619,9 @@ function markUnusedValues(root) {
|
|
|
1437
1619
|
case "transform":
|
|
1438
1620
|
visit(def.parser, true);
|
|
1439
1621
|
return;
|
|
1622
|
+
case "field":
|
|
1623
|
+
visit(def.parser, true);
|
|
1624
|
+
return;
|
|
1440
1625
|
case "skip":
|
|
1441
1626
|
visit(def.main, consumed);
|
|
1442
1627
|
visit(def.skipped, false);
|
|
@@ -1488,6 +1673,11 @@ function markUnusedValues(root) {
|
|
|
1488
1673
|
}
|
|
1489
1674
|
|
|
1490
1675
|
// src/combinators/parser.ts
|
|
1676
|
+
function tagRule(r, key) {
|
|
1677
|
+
;
|
|
1678
|
+
r._ruleName = key;
|
|
1679
|
+
if (r._def.tag === "node" && r._def.type === void 0) r._def.type = key;
|
|
1680
|
+
}
|
|
1491
1681
|
function rules(factory) {
|
|
1492
1682
|
const cache = {};
|
|
1493
1683
|
const proxy = new Proxy(cache, {
|
|
@@ -1496,7 +1686,7 @@ function rules(factory) {
|
|
|
1496
1686
|
const record = target;
|
|
1497
1687
|
if (!(key in record)) {
|
|
1498
1688
|
const r = ref();
|
|
1499
|
-
r
|
|
1689
|
+
tagRule(r, key);
|
|
1500
1690
|
record[key] = r;
|
|
1501
1691
|
}
|
|
1502
1692
|
return record[key];
|
|
@@ -1507,12 +1697,12 @@ function rules(factory) {
|
|
|
1507
1697
|
const placeholder = cache[key];
|
|
1508
1698
|
const parser2 = definitions[key];
|
|
1509
1699
|
if (placeholder !== void 0 && typeof placeholder.define === "function") {
|
|
1510
|
-
;
|
|
1700
|
+
tagRule(parser2, key);
|
|
1511
1701
|
placeholder.define(parser2);
|
|
1512
1702
|
placeholder._meta.firstSet = parser2._meta.firstSet;
|
|
1513
1703
|
placeholder._meta.canMatchNewline = parser2._meta.canMatchNewline;
|
|
1514
1704
|
} else {
|
|
1515
|
-
;
|
|
1705
|
+
tagRule(parser2, key);
|
|
1516
1706
|
cache[key] = parser2;
|
|
1517
1707
|
}
|
|
1518
1708
|
}
|
|
@@ -1569,44 +1759,130 @@ function buildReadsTrivia(def) {
|
|
|
1569
1759
|
const src = def.buildSrc ?? def.build.toString();
|
|
1570
1760
|
const arity = confirmedBuildArity(src);
|
|
1571
1761
|
if (arity === null) return true;
|
|
1572
|
-
return arity >=
|
|
1762
|
+
return arity >= 5;
|
|
1573
1763
|
}
|
|
1574
1764
|
function buildReadsState(def) {
|
|
1575
1765
|
if (!def.build) return true;
|
|
1576
1766
|
const src = def.buildSrc ?? def.build.toString();
|
|
1577
1767
|
const arity = confirmedBuildArity(src);
|
|
1578
1768
|
if (arity === null) return true;
|
|
1579
|
-
return arity >=
|
|
1769
|
+
return arity >= 6;
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
// src/compiler/fields.ts
|
|
1773
|
+
function buildReadsFields(def) {
|
|
1774
|
+
if (!def.build) return true;
|
|
1775
|
+
const src = def.buildSrc ?? def.build.toString();
|
|
1776
|
+
const arity = confirmedBuildArity(src);
|
|
1777
|
+
if (arity === null) return true;
|
|
1778
|
+
return arity >= 2;
|
|
1779
|
+
}
|
|
1780
|
+
function parserHasOwnFields(p, seen = /* @__PURE__ */ new Set()) {
|
|
1781
|
+
if (seen.has(p)) return false;
|
|
1782
|
+
seen.add(p);
|
|
1783
|
+
const d = p._def;
|
|
1784
|
+
switch (d.tag) {
|
|
1785
|
+
case "field":
|
|
1786
|
+
return true;
|
|
1787
|
+
case "node":
|
|
1788
|
+
return false;
|
|
1789
|
+
case "lazy": {
|
|
1790
|
+
try {
|
|
1791
|
+
return parserHasOwnFields(d.thunk(), seen);
|
|
1792
|
+
} catch {
|
|
1793
|
+
return false;
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
case "sequence":
|
|
1797
|
+
case "choice":
|
|
1798
|
+
return d.parsers.some((x) => parserHasOwnFields(x, seen));
|
|
1799
|
+
case "sepBy":
|
|
1800
|
+
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.separator, seen);
|
|
1801
|
+
case "skip":
|
|
1802
|
+
return parserHasOwnFields(d.main, seen) || parserHasOwnFields(d.skipped, seen);
|
|
1803
|
+
case "grammar":
|
|
1804
|
+
return parserHasOwnFields(d.parser, seen) || (d.triviaParser ? parserHasOwnFields(d.triviaParser, seen) : false);
|
|
1805
|
+
case "scanTo":
|
|
1806
|
+
return parserHasOwnFields(d.sentinel, seen) || d.skip.some((x) => parserHasOwnFields(x, seen));
|
|
1807
|
+
case "recover":
|
|
1808
|
+
return parserHasOwnFields(d.parser, seen) || parserHasOwnFields(d.sentinel, seen);
|
|
1809
|
+
case "many":
|
|
1810
|
+
case "oneOrMore":
|
|
1811
|
+
case "optional":
|
|
1812
|
+
case "transform":
|
|
1813
|
+
case "trivia":
|
|
1814
|
+
case "token":
|
|
1815
|
+
case "label":
|
|
1816
|
+
case "expect":
|
|
1817
|
+
case "withCtx":
|
|
1818
|
+
case "not":
|
|
1819
|
+
return parserHasOwnFields(d.parser, seen);
|
|
1820
|
+
default:
|
|
1821
|
+
return false;
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
function buildFieldMap(captures) {
|
|
1825
|
+
if (!captures?.length) return void 0;
|
|
1826
|
+
const out = {};
|
|
1827
|
+
for (const cap of captures) {
|
|
1828
|
+
const entry = { value: cap.value, span: cap.span };
|
|
1829
|
+
const current = out[cap.name];
|
|
1830
|
+
if (current === void 0) out[cap.name] = entry;
|
|
1831
|
+
else if (Array.isArray(current)) current.push(entry);
|
|
1832
|
+
else out[cap.name] = [current, entry];
|
|
1833
|
+
}
|
|
1834
|
+
return out;
|
|
1580
1835
|
}
|
|
1581
1836
|
|
|
1582
1837
|
// src/combinators/node.ts
|
|
1583
|
-
function
|
|
1838
|
+
function unwrapChild(child) {
|
|
1584
1839
|
return child !== null && typeof child === "object" && child._tag === "leaf" ? child.value : child;
|
|
1585
1840
|
}
|
|
1586
|
-
function
|
|
1841
|
+
function isCstChild(value) {
|
|
1842
|
+
return typeof value === "object" && value !== null && (value._tag === "node" || value._tag === "leaf" || value._tag === "error");
|
|
1843
|
+
}
|
|
1844
|
+
function missingInferredType() {
|
|
1845
|
+
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
1846
|
+
}
|
|
1847
|
+
function node(typeOrCombinator, combinatorOrBuild, buildOrOpts, maybeOpts) {
|
|
1848
|
+
const hasExplicitType = typeof typeOrCombinator === "string";
|
|
1849
|
+
const type = hasExplicitType ? typeOrCombinator : void 0;
|
|
1850
|
+
const combinator = hasExplicitType ? combinatorOrBuild : typeOrCombinator;
|
|
1851
|
+
const build = hasExplicitType ? buildOrOpts : combinatorOrBuild;
|
|
1852
|
+
const opts = hasExplicitType ? maybeOpts : buildOrOpts;
|
|
1853
|
+
const baseDef = { tag: "node", parser: combinator, ...type === void 0 ? {} : { type }, ...build === void 0 ? {} : { build } };
|
|
1587
1854
|
const meta = {
|
|
1588
1855
|
firstSet: combinator._meta.firstSet,
|
|
1589
1856
|
canMatchNewline: combinator._meta.canMatchNewline,
|
|
1590
1857
|
isTrivia: false
|
|
1591
1858
|
};
|
|
1859
|
+
const unwrap = opts?.unwrap === true;
|
|
1592
1860
|
const collapse = opts?.collapse === true;
|
|
1593
|
-
|
|
1861
|
+
if (unwrap && collapse) {
|
|
1862
|
+
throw new Error("node() options cannot set both unwrap and collapse");
|
|
1863
|
+
}
|
|
1864
|
+
const def = unwrap || collapse ? { ...baseDef, ...unwrap ? { unwrap: true } : {}, ...collapse ? { collapse: true } : {} } : baseDef;
|
|
1594
1865
|
const capturesTrivia = build ? buildReadsTrivia(def) : true;
|
|
1595
1866
|
const clonesState = build ? buildReadsState(def) : true;
|
|
1867
|
+
const capturesFields = parserHasOwnFields(combinator) && (build ? buildReadsFields(def) : true);
|
|
1596
1868
|
return {
|
|
1597
1869
|
_tag: "node",
|
|
1598
1870
|
_meta: meta,
|
|
1599
1871
|
_def: def,
|
|
1600
1872
|
parse(input, pos, ctx) {
|
|
1601
1873
|
const saved = beginCstNodeCapture(ctx);
|
|
1874
|
+
const savedFields = ctx._fields;
|
|
1875
|
+
ctx._fields = capturesFields ? [] : void 0;
|
|
1602
1876
|
if (!capturesTrivia) ctx.captureTrivia = false;
|
|
1603
1877
|
const r = combinator.parse(input, pos, ctx);
|
|
1878
|
+
const fields = capturesFields ? buildFieldMap(ctx._fields) : void 0;
|
|
1879
|
+
ctx._fields = savedFields;
|
|
1604
1880
|
const { children, rawChildren, triviaLog } = endCstNodeCapture(ctx, saved);
|
|
1605
1881
|
if (!r.ok) return r;
|
|
1606
1882
|
const st = clonesState && ctx.state !== void 0 ? Object.assign({}, ctx.state) : void 0;
|
|
1607
|
-
const
|
|
1608
|
-
const
|
|
1609
|
-
const rawEntry =
|
|
1883
|
+
const nodeType = def.type ?? missingInferredType();
|
|
1884
|
+
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 };
|
|
1885
|
+
const rawEntry = isCstChild(built) ? built : { _tag: "leaf", value: typeof built === "string" ? built : "", span: r.span };
|
|
1610
1886
|
if (saved.buf !== void 0 || saved.ch !== void 0) {
|
|
1611
1887
|
pushCstChild(ctx, built, rawEntry);
|
|
1612
1888
|
}
|
|
@@ -1667,6 +1943,19 @@ function label(name, combinator) {
|
|
|
1667
1943
|
}
|
|
1668
1944
|
};
|
|
1669
1945
|
}
|
|
1946
|
+
function field(name, combinator) {
|
|
1947
|
+
return {
|
|
1948
|
+
_tag: combinator._tag,
|
|
1949
|
+
_meta: combinator._meta,
|
|
1950
|
+
_def: { tag: "field", name, parser: combinator },
|
|
1951
|
+
parse(input, pos, ctx) {
|
|
1952
|
+
const result = combinator.parse(input, pos, ctx);
|
|
1953
|
+
if (!result.ok) return result;
|
|
1954
|
+
ctx._fields?.push({ name, value: result.value, span: result.span });
|
|
1955
|
+
return result;
|
|
1956
|
+
}
|
|
1957
|
+
};
|
|
1958
|
+
}
|
|
1670
1959
|
|
|
1671
1960
|
// src/compiler/line-index.ts
|
|
1672
1961
|
function buildLineIndex(input) {
|
|
@@ -1876,77 +2165,11 @@ function expect(combinator, label2) {
|
|
|
1876
2165
|
|
|
1877
2166
|
// src/compiler/scannable-run.ts
|
|
1878
2167
|
var BACKSLASH = 92;
|
|
1879
|
-
var CLASS_ESCAPES2 = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
|
|
1880
2168
|
var META = new Set("()[]{}*+?|^$.".split(""));
|
|
1881
|
-
var SPACE_RANGES2 = [
|
|
1882
|
-
[9, 13],
|
|
1883
|
-
[32, 32],
|
|
1884
|
-
[160, 160],
|
|
1885
|
-
[5760, 5760],
|
|
1886
|
-
[8192, 8202],
|
|
1887
|
-
[8232, 8232],
|
|
1888
|
-
[8233, 8233],
|
|
1889
|
-
[8239, 8239],
|
|
1890
|
-
[8287, 8287],
|
|
1891
|
-
[12288, 12288],
|
|
1892
|
-
[65279, 65279]
|
|
1893
|
-
];
|
|
1894
|
-
function shorthandRanges2(ch) {
|
|
1895
|
-
if (ch === "d") return [[48, 57]];
|
|
1896
|
-
if (ch === "s") return SPACE_RANGES2;
|
|
1897
|
-
return [[48, 57], [65, 90], [97, 122], [95, 95]];
|
|
1898
|
-
}
|
|
1899
|
-
function readUnicodeEscape(body, i) {
|
|
1900
|
-
if (body[i] !== "\\" || body[i + 1] !== "u") return null;
|
|
1901
|
-
const hex = body.slice(i + 2, i + 6);
|
|
1902
|
-
if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
|
|
1903
|
-
return { cp: Number.parseInt(hex, 16), next: i + 6 };
|
|
1904
|
-
}
|
|
1905
|
-
function parseClassRanges(body) {
|
|
1906
|
-
const ranges = [];
|
|
1907
|
-
let i = 0;
|
|
1908
|
-
const readAtom = () => {
|
|
1909
|
-
const ch = body[i];
|
|
1910
|
-
if (ch === void 0) return null;
|
|
1911
|
-
if (ch === "\\") {
|
|
1912
|
-
const uni = readUnicodeEscape(body, i);
|
|
1913
|
-
if (uni) {
|
|
1914
|
-
i = uni.next;
|
|
1915
|
-
return { cp: uni.cp };
|
|
1916
|
-
}
|
|
1917
|
-
const e = body[i + 1];
|
|
1918
|
-
if (e === void 0) return null;
|
|
1919
|
-
i += 2;
|
|
1920
|
-
if (e in CLASS_ESCAPES2) return { cp: CLASS_ESCAPES2[e] };
|
|
1921
|
-
if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges2(e) };
|
|
1922
|
-
if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
|
|
1923
|
-
return { cp: e.codePointAt(0) };
|
|
1924
|
-
}
|
|
1925
|
-
i += ch.length;
|
|
1926
|
-
return { cp: ch.codePointAt(0) };
|
|
1927
|
-
};
|
|
1928
|
-
while (i < body.length) {
|
|
1929
|
-
const lo = readAtom();
|
|
1930
|
-
if (lo === null) return null;
|
|
1931
|
-
if ("set" in lo) {
|
|
1932
|
-
ranges.push(...lo.set);
|
|
1933
|
-
continue;
|
|
1934
|
-
}
|
|
1935
|
-
if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
|
|
1936
|
-
i += 1;
|
|
1937
|
-
const hi = readAtom();
|
|
1938
|
-
if (hi === null || "set" in hi) return null;
|
|
1939
|
-
ranges.push([lo.cp, hi.cp]);
|
|
1940
|
-
} else {
|
|
1941
|
-
ranges.push([lo.cp, lo.cp]);
|
|
1942
|
-
}
|
|
1943
|
-
}
|
|
1944
|
-
return ranges.length ? ranges : null;
|
|
1945
|
-
}
|
|
1946
2169
|
function classToRanges(cls) {
|
|
1947
|
-
if (cls === "\\d") return
|
|
1948
|
-
if (cls === "\\w") return
|
|
1949
|
-
if (cls === "\\s") return
|
|
2170
|
+
if (cls === "\\d") return shorthandRanges("d");
|
|
2171
|
+
if (cls === "\\w") return shorthandRanges("w");
|
|
2172
|
+
if (cls === "\\s") return shorthandRanges("s");
|
|
1950
2173
|
const body = cls.slice(1, -1);
|
|
1951
2174
|
if (body.startsWith("^")) return null;
|
|
1952
2175
|
return parseClassRanges(body);
|
|
@@ -1964,7 +2187,7 @@ function literalCodePoints(frag) {
|
|
|
1964
2187
|
if (ch === "\\") {
|
|
1965
2188
|
const e = frag[i + 1];
|
|
1966
2189
|
if (e === void 0) return null;
|
|
1967
|
-
out.push(e in
|
|
2190
|
+
out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
|
|
1968
2191
|
i += 2;
|
|
1969
2192
|
continue;
|
|
1970
2193
|
}
|
|
@@ -2057,7 +2280,7 @@ function parseSeqParts(source) {
|
|
|
2057
2280
|
if (e === "d" || e === "w" || e === "s") {
|
|
2058
2281
|
flush();
|
|
2059
2282
|
i += 2;
|
|
2060
|
-
i += runFrom(
|
|
2283
|
+
i += runFrom(shorthandRanges(e), false, source[i]);
|
|
2061
2284
|
continue;
|
|
2062
2285
|
}
|
|
2063
2286
|
const uni = readUnicodeEscape(source, i);
|
|
@@ -2066,8 +2289,8 @@ function parseSeqParts(source) {
|
|
|
2066
2289
|
cp2 = uni.cp;
|
|
2067
2290
|
i = uni.next;
|
|
2068
2291
|
} else if (e === void 0) return null;
|
|
2069
|
-
else if (e in
|
|
2070
|
-
cp2 =
|
|
2292
|
+
else if (e in CLASS_ESCAPES) {
|
|
2293
|
+
cp2 = CLASS_ESCAPES[e];
|
|
2071
2294
|
i += 2;
|
|
2072
2295
|
} else if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
|
|
2073
2296
|
else {
|
|
@@ -2174,7 +2397,7 @@ function rangesSubset(sub, sup) {
|
|
|
2174
2397
|
}
|
|
2175
2398
|
function parseClassOperand(body) {
|
|
2176
2399
|
if (body === "\\d" || body === "\\w" || body === "\\s") {
|
|
2177
|
-
return { ranges:
|
|
2400
|
+
return { ranges: shorthandRanges(body[1]), negated: false };
|
|
2178
2401
|
}
|
|
2179
2402
|
if (body.length >= 2 && body[0] === "[" && body[body.length - 1] === "]") {
|
|
2180
2403
|
let inner = body.slice(1, -1);
|
|
@@ -2607,7 +2830,7 @@ function parseScanShapeCore(source) {
|
|
|
2607
2830
|
}
|
|
2608
2831
|
m = /^\\([dws])([+*])$/.exec(source);
|
|
2609
2832
|
if (m) {
|
|
2610
|
-
return { kind: "chars", ranges:
|
|
2833
|
+
return { kind: "chars", ranges: shorthandRanges(m[1]), minOne: m[2] === "+" };
|
|
2611
2834
|
}
|
|
2612
2835
|
m = /^(\[(?:\\.|[^\]])+\]|\\[dws])(\[(?:\\.|[^\]])+\]|\\[dws])\*$/.exec(source);
|
|
2613
2836
|
if (m) {
|
|
@@ -3149,21 +3372,22 @@ function emitScannableTerminal(shape, c) {
|
|
|
3149
3372
|
}
|
|
3150
3373
|
|
|
3151
3374
|
// src/compiler/inline-build.ts
|
|
3152
|
-
var MK_BUILD_RE = /^\(\s*(
|
|
3375
|
+
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*$/;
|
|
3153
3376
|
function escapeRegExp(s) {
|
|
3154
3377
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3155
3378
|
}
|
|
3156
3379
|
function looseMkBuildRe(type) {
|
|
3157
3380
|
return new RegExp(
|
|
3158
|
-
String.raw`^\(\s*(
|
|
3381
|
+
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*$`
|
|
3159
3382
|
);
|
|
3160
3383
|
}
|
|
3161
3384
|
function analyzeMkInlineBuild(def) {
|
|
3162
3385
|
if (!def.build) return null;
|
|
3386
|
+
if (def.type === void 0) return null;
|
|
3163
3387
|
const src = (def.buildSrc ?? def.build.toString()).trim();
|
|
3164
3388
|
const strict = src.match(MK_BUILD_RE);
|
|
3165
3389
|
if (strict) {
|
|
3166
|
-
const mkType = strict[
|
|
3390
|
+
const mkType = strict[6];
|
|
3167
3391
|
return mkType === def.type ? def.type : null;
|
|
3168
3392
|
}
|
|
3169
3393
|
if (looseMkBuildRe(def.type).test(src)) return def.type;
|
|
@@ -3490,8 +3714,9 @@ function planDisjointDispatch(parsers) {
|
|
|
3490
3714
|
}
|
|
3491
3715
|
return total >= SWITCH_MIN_CASES ? { kind: "switch", cases } : { kind: "if" };
|
|
3492
3716
|
}
|
|
3493
|
-
function captureRestoreBody(mL, mR, mTl, mLg) {
|
|
3494
|
-
const
|
|
3717
|
+
function captureRestoreBody(mL, mR, mTl, mLg, mF = null) {
|
|
3718
|
+
const fieldRestore = mF ? `; if (_ctx._fields) _ctx._fields.length = ${mF}` : "";
|
|
3719
|
+
const base = `if (_ctx._cstLeaves) _ctx._cstLeaves.length = ${mL}; if (_ctx._cstRawChildren) _ctx._cstRawChildren.length = ${mR}; if (_ctx._cstTriviaLog) _ctx._cstTriviaLog.length = ${mTl}${fieldRestore}`;
|
|
3495
3720
|
return mLg ? `${base}; if (_ctx._triviaLog) _ctx._triviaLog.length = ${mLg}` : base;
|
|
3496
3721
|
}
|
|
3497
3722
|
function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
@@ -3539,6 +3764,7 @@ function mayLeavePartialCapture(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
3539
3764
|
// Delegating wrappers: defer to the wrapped parser.
|
|
3540
3765
|
case "transform":
|
|
3541
3766
|
case "label":
|
|
3767
|
+
case "field":
|
|
3542
3768
|
case "expect":
|
|
3543
3769
|
case "withCtx":
|
|
3544
3770
|
case "grammar":
|
|
@@ -3585,6 +3811,7 @@ function capturesLeaf(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
3585
3811
|
case "optional":
|
|
3586
3812
|
case "transform":
|
|
3587
3813
|
case "label":
|
|
3814
|
+
case "field":
|
|
3588
3815
|
case "expect":
|
|
3589
3816
|
case "withCtx":
|
|
3590
3817
|
case "grammar":
|
|
@@ -3622,22 +3849,25 @@ function emitFallible(inner, ctx, pos, swallow = false) {
|
|
|
3622
3849
|
ctx.recordFail = savedRecord;
|
|
3623
3850
|
const ind0 = ind(ctx);
|
|
3624
3851
|
const needsRollback = ctx.capturing && mayLeavePartialCapture(inner);
|
|
3852
|
+
const needsFieldRollback = needsRollback && parserHasOwnFields(inner);
|
|
3625
3853
|
const mL = needsRollback ? v(ctx, "_fcl") : null;
|
|
3626
3854
|
const mR = needsRollback ? v(ctx, "_fcr") : null;
|
|
3627
3855
|
const mTl = needsRollback ? v(ctx, "_fctl") : null;
|
|
3856
|
+
const mF = needsFieldRollback ? v(ctx, "_fcf") : null;
|
|
3628
3857
|
const stmts = [
|
|
3629
3858
|
`${ind0}let ${okV} = false, ${valV}, ${endV} = ${pos}`,
|
|
3630
3859
|
...mL ? [
|
|
3631
3860
|
`${ind0}const ${mL} = _ctx._cstLeaves?.length ?? 0`,
|
|
3632
3861
|
`${ind0}const ${mR} = _ctx._cstRawChildren?.length ?? 0`,
|
|
3633
|
-
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0
|
|
3862
|
+
`${ind0}const ${mTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
3863
|
+
...mF ? [`${ind0}const ${mF} = _ctx._fields?.length ?? 0`] : []
|
|
3634
3864
|
] : [],
|
|
3635
3865
|
`${ind0}${lbl}: {`,
|
|
3636
3866
|
...r.stmts,
|
|
3637
3867
|
`${ind0} ${valV} = ${r.valueVar}; ${endV} = ${r.endVar}; ${okV} = true`,
|
|
3638
3868
|
`${ind0}}`,
|
|
3639
3869
|
...mL ? [
|
|
3640
|
-
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null)} }`
|
|
3870
|
+
`${ind0}if (!${okV}) { ${captureRestoreBody(mL, mR, mTl, null, mF)} }`
|
|
3641
3871
|
] : []
|
|
3642
3872
|
];
|
|
3643
3873
|
return { stmts, okVar: okV, valVar: valV, endVar: endV };
|
|
@@ -3864,6 +4094,7 @@ function failsAtStart(p) {
|
|
|
3864
4094
|
return true;
|
|
3865
4095
|
case "transform":
|
|
3866
4096
|
case "label":
|
|
4097
|
+
case "field":
|
|
3867
4098
|
return failsAtStart(d.parser);
|
|
3868
4099
|
default:
|
|
3869
4100
|
return false;
|
|
@@ -3883,6 +4114,7 @@ function canMatchEmptyAtStart(p) {
|
|
|
3883
4114
|
return true;
|
|
3884
4115
|
case "transform":
|
|
3885
4116
|
case "label":
|
|
4117
|
+
case "field":
|
|
3886
4118
|
return canMatchEmptyAtStart(d.parser);
|
|
3887
4119
|
case "literal":
|
|
3888
4120
|
return d.value.length === 0;
|
|
@@ -4065,11 +4297,13 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4065
4297
|
const skipCond = gateCond ? `!${resOkV} && ${gateCond}` : `!${resOkV}`;
|
|
4066
4298
|
const armHasAutoNot = !!(autoNot && autoNot.length > 0);
|
|
4067
4299
|
const armNeedsRollback = ctx.capturing && (mayLeavePartialCapture(p) || armHasAutoNot && capturesLeaf(p));
|
|
4300
|
+
const armNeedsFieldRollback = armNeedsRollback && parserHasOwnFields(p);
|
|
4068
4301
|
const markLeaves = armNeedsRollback ? v(ctx, "_cml") : null;
|
|
4069
4302
|
const markRaw = armNeedsRollback ? v(ctx, "_cmr") : null;
|
|
4070
4303
|
const markTl = armNeedsRollback ? v(ctx, "_cmtl") : null;
|
|
4071
4304
|
const markLog = armNeedsRollback ? v(ctx, "_cmlg") : null;
|
|
4072
|
-
const
|
|
4305
|
+
const markFields = armNeedsFieldRollback ? v(ctx, "_cmf") : null;
|
|
4306
|
+
const rollback = markLeaves ? captureRestoreBody(markLeaves, markRaw, markTl, markLog, markFields) : "";
|
|
4073
4307
|
const failSlot = atStart ? staticFx : "_ctx._fx";
|
|
4074
4308
|
stmts.push(`${ind0}if (${skipCond}) {`);
|
|
4075
4309
|
if (fsGuard) stmts.push(`${ind(ctx)}if (${fsGuard}) {`);
|
|
@@ -4079,7 +4313,8 @@ function emitFirstMatch(def, ctx, pos) {
|
|
|
4079
4313
|
`${ind(ctx)}const ${markLeaves} = _ctx._cstLeaves?.length ?? 0`,
|
|
4080
4314
|
`${ind(ctx)}const ${markRaw} = _ctx._cstRawChildren?.length ?? 0`,
|
|
4081
4315
|
`${ind(ctx)}const ${markTl} = _ctx._cstTriviaLog?.length ?? 0`,
|
|
4082
|
-
`${ind(ctx)}const ${markLog} = _ctx._triviaLog?.length ?? 0
|
|
4316
|
+
`${ind(ctx)}const ${markLog} = _ctx._triviaLog?.length ?? 0`,
|
|
4317
|
+
...markFields ? [`${ind(ctx)}const ${markFields} = _ctx._fields?.length ?? 0`] : []
|
|
4083
4318
|
);
|
|
4084
4319
|
}
|
|
4085
4320
|
const { stmts: armStmts, okVar, valVar, endVar } = emitFallible(p, ctx, pos, atStart);
|
|
@@ -4472,6 +4707,9 @@ function emitToken(def, ctx, pos) {
|
|
|
4472
4707
|
};
|
|
4473
4708
|
}
|
|
4474
4709
|
function emitNode(def, ctx, pos) {
|
|
4710
|
+
if (def.type === void 0) {
|
|
4711
|
+
throw new Error('node(): inferred node type requires a rules() key; pass node("Type", parser) outside rules()');
|
|
4712
|
+
}
|
|
4475
4713
|
const structural = def.build === void 0;
|
|
4476
4714
|
const mkType = structural ? null : analyzeMkInlineBuild(def);
|
|
4477
4715
|
let buildIdx = null;
|
|
@@ -4483,25 +4721,36 @@ function emitNode(def, ctx, pos) {
|
|
|
4483
4721
|
const i = ind(ctx);
|
|
4484
4722
|
const capturesTrivia = mkType !== null || !structural && buildReadsTrivia(def);
|
|
4485
4723
|
const clonesState = !structural && buildReadsState(def);
|
|
4724
|
+
const hasFields = parserHasOwnFields(def.parser);
|
|
4725
|
+
const capturesFields = hasFields && !structural && buildReadsFields(def);
|
|
4486
4726
|
const chV = v(ctx, "_ch");
|
|
4487
4727
|
const rawV = v(ctx, "_raw");
|
|
4488
4728
|
const capTLv = structural ? v(ctx, "_ctl") : null;
|
|
4489
4729
|
const capSTv = structural ? v(ctx, "_cst") : null;
|
|
4730
|
+
const capFv = structural && hasFields ? v(ctx, "_cf") : null;
|
|
4490
4731
|
const tlV = capturesTrivia || structural ? v(ctx, "_tl") : "_EMPTY_TL";
|
|
4491
4732
|
if (!capturesTrivia) ctx.needsEmptyTl = true;
|
|
4492
4733
|
const sc = v(ctx, "_sc"), sl = v(ctx, "_sl"), sr = v(ctx, "_sr"), st = v(ctx, "_st"), stl = v(ctx, "_stl");
|
|
4493
4734
|
if (structural) ctx.needsHostReads = true;
|
|
4494
|
-
const
|
|
4735
|
+
const hostTriviaGate = `_ctx.build !== undefined && (_ctx.build._parsemanCaptureTrivia !== undefined ? _ctx.build._parsemanCaptureTrivia(${JSON.stringify(def.type)}) : (_ctx._pmCapTL ??= _hostReads(_ctx.build, 5)))`;
|
|
4736
|
+
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)` : ""}
|
|
4495
4737
|
${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capturesTrivia ? `${i}const ${chV} = [], ${rawV} = [], ${tlV} = []` : `${i}const ${chV} = [], ${rawV} = []`;
|
|
4496
4738
|
const innerTl = structural ? `${capTLv} ? ${tlV} : undefined` : capturesTrivia ? tlV : "undefined";
|
|
4739
|
+
const fieldsOn = structural ? capFv ?? "false" : capturesFields ? "true" : "false";
|
|
4740
|
+
const sf = hasFields ? v(ctx, "_sf") : null;
|
|
4741
|
+
const fArr = hasFields ? v(ctx, "_fa") : null;
|
|
4742
|
+
const fObj = hasFields ? v(ctx, "_fields") : "undefined";
|
|
4497
4743
|
const stmts = [
|
|
4498
4744
|
allocStmt,
|
|
4499
|
-
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog`,
|
|
4500
|
-
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}`
|
|
4745
|
+
`${i}const ${sc} = _ctx._cstChildren, ${sl} = _ctx._cstLeaves, ${sr} = _ctx._cstRawChildren, ${st} = _ctx.captureTrivia, ${stl} = _ctx._cstTriviaLog${sf ? `, ${sf} = _ctx._fields` : ""}`,
|
|
4746
|
+
`${i}_ctx._cstChildren = ${chV}; _ctx._cstLeaves = ${chV}; _ctx._cstRawChildren = ${rawV}; _ctx.captureTrivia = true; _ctx._cstTriviaLog = ${innerTl}${sf ? `; _ctx._fields = ${fieldsOn} ? [] : undefined` : ""}`
|
|
4501
4747
|
];
|
|
4502
4748
|
const { stmts: innerStmts, okVar, endVar } = emitFallible(def.parser, ctx, pos);
|
|
4503
4749
|
stmts.push(...innerStmts);
|
|
4504
|
-
|
|
4750
|
+
if (sf && fArr) {
|
|
4751
|
+
stmts.push(`${i}const ${fArr} = _ctx._fields`);
|
|
4752
|
+
}
|
|
4753
|
+
stmts.push(`${i}_ctx._cstChildren = ${sc}; _ctx._cstLeaves = ${sl}; _ctx._cstRawChildren = ${sr}; _ctx.captureTrivia = ${st}; _ctx._cstTriviaLog = ${stl}${sf ? `; _ctx._fields = ${sf}` : ""}`);
|
|
4505
4754
|
stmts.push(...emitIfFail(ctx, `!${okVar}`, propagateFailBody(ctx)));
|
|
4506
4755
|
let stV = "undefined";
|
|
4507
4756
|
if (structural) {
|
|
@@ -4511,14 +4760,33 @@ ${i}const ${chV} = [], ${rawV} = [], ${tlV} = ${capTLv} ? [] : _EMPTY_TL` : capt
|
|
|
4511
4760
|
stV = v(ctx, "_nst");
|
|
4512
4761
|
stmts.push(`${i}const ${stV} = _ctx.state !== undefined ? Object.assign({}, _ctx.state) : undefined`);
|
|
4513
4762
|
}
|
|
4763
|
+
if (sf && fArr) {
|
|
4764
|
+
const fe = v(ctx, "_fe");
|
|
4765
|
+
const cur = v(ctx, "_fc");
|
|
4766
|
+
stmts.push(
|
|
4767
|
+
`${i}let ${fObj} = undefined`,
|
|
4768
|
+
`${i}if (${fArr} && ${fArr}.length) {`,
|
|
4769
|
+
`${i} ${fObj} = {}`,
|
|
4770
|
+
`${i} for (const ${fe} of ${fArr}) {`,
|
|
4771
|
+
`${i} const ${cur} = ${fObj}[${fe}.name], _entry = { value: ${fe}.value, span: ${fe}.span }`,
|
|
4772
|
+
`${i} if (${cur} === undefined) ${fObj}[${fe}.name] = _entry`,
|
|
4773
|
+
`${i} else if (Array.isArray(${cur})) ${cur}.push(_entry)`,
|
|
4774
|
+
`${i} else ${fObj}[${fe}.name] = [${cur}, _entry]`,
|
|
4775
|
+
`${i} }`,
|
|
4776
|
+
`${i}}`
|
|
4777
|
+
);
|
|
4778
|
+
}
|
|
4514
4779
|
const ndV = v(ctx, "_nd");
|
|
4515
|
-
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}, ${
|
|
4516
|
-
const ndExpr = ctx.ns || structural ? `_ctx.build !== undefined ? _ctx.build(${JSON.stringify(def.type)}, ${chV}, ${
|
|
4517
|
-
const
|
|
4780
|
+
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})`;
|
|
4781
|
+
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;
|
|
4782
|
+
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;
|
|
4783
|
+
const unwrapExpr = `${chV}.length === 1 ? (${chV}[0] !== null && typeof ${chV}[0] === 'object' && ${chV}[0]._tag === 'leaf' ? ${chV}[0].value : ${chV}[0]) : (${ndExpr})`;
|
|
4784
|
+
const collapseExpr = `${chV}.length === 1 ? ${chV}[0] : (${ndExpr})`;
|
|
4785
|
+
const finalExpr = def.unwrap ? unwrapExpr : def.collapse ? collapseExpr : hostCollapseExpr;
|
|
4518
4786
|
stmts.push(
|
|
4519
4787
|
`${i}const ${ndV} = ${finalExpr}`,
|
|
4520
4788
|
`${i}if (${sc}) ${sc}.push(${ndV})`,
|
|
4521
|
-
`${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} } })`
|
|
4789
|
+
`${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} } })`
|
|
4522
4790
|
);
|
|
4523
4791
|
return { stmts, valueVar: ndV, endVar };
|
|
4524
4792
|
}
|
|
@@ -4733,6 +5001,17 @@ function emitDispatch(p, ctx, pos) {
|
|
|
4733
5001
|
endVar: inner.endVar
|
|
4734
5002
|
};
|
|
4735
5003
|
}
|
|
5004
|
+
case "field": {
|
|
5005
|
+
const inner = emit(def.parser, ctx, pos);
|
|
5006
|
+
return {
|
|
5007
|
+
stmts: [
|
|
5008
|
+
...inner.stmts,
|
|
5009
|
+
`${ind(ctx)}if (_ctx._fields) _ctx._fields.push({ name: ${JSON.stringify(def.name)}, value: ${inner.valueVar}, span: { start: ${pos}, end: ${inner.endVar} } })`
|
|
5010
|
+
],
|
|
5011
|
+
valueVar: inner.valueVar,
|
|
5012
|
+
endVar: inner.endVar
|
|
5013
|
+
};
|
|
5014
|
+
}
|
|
4736
5015
|
case "grammar": {
|
|
4737
5016
|
const savedTrivia = ctx.activeTrivia;
|
|
4738
5017
|
const savedKindLabels = ctx.triviaKindLabels;
|
|
@@ -4834,6 +5113,7 @@ function hasNodeDef(p, seen = /* @__PURE__ */ new Set()) {
|
|
|
4834
5113
|
case "trivia":
|
|
4835
5114
|
case "token":
|
|
4836
5115
|
case "label":
|
|
5116
|
+
case "field":
|
|
4837
5117
|
case "optional":
|
|
4838
5118
|
case "many":
|
|
4839
5119
|
case "oneOrMore":
|
|
@@ -4870,6 +5150,7 @@ function childrenOf(def) {
|
|
|
4870
5150
|
case "trivia":
|
|
4871
5151
|
case "token":
|
|
4872
5152
|
case "label":
|
|
5153
|
+
case "field":
|
|
4873
5154
|
case "grammar":
|
|
4874
5155
|
case "not":
|
|
4875
5156
|
case "node":
|
|
@@ -5111,6 +5392,11 @@ function assertRuleName(name) {
|
|
|
5111
5392
|
);
|
|
5112
5393
|
}
|
|
5113
5394
|
}
|
|
5395
|
+
function publicRuleWrapperSource(rule, fnSource) {
|
|
5396
|
+
const labels = rule._meta.triviaKindLabels;
|
|
5397
|
+
if (labels === void 0) return fnSource;
|
|
5398
|
+
return `Object.assign(${fnSource}, { _meta: { triviaKindLabels: ${JSON.stringify(labels)} } })`;
|
|
5399
|
+
}
|
|
5114
5400
|
function compileLinkable(ruleMapArg, ns) {
|
|
5115
5401
|
if (!ns) throw new Error("compileLinkable: ns must be a non-empty namespace");
|
|
5116
5402
|
for (const [, rule] of ruleMapArg) markUnusedValues(rule);
|
|
@@ -5213,7 +5499,7 @@ function compileLinkable(ruleMapArg, ns) {
|
|
|
5213
5499
|
ctx.recordFail = savedRec;
|
|
5214
5500
|
pushNamedFnDecl(ctx, fn, body.stmts, body.valueVar, body.endVar);
|
|
5215
5501
|
}
|
|
5216
|
-
perEntry.push({ key, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
5502
|
+
perEntry.push({ key, rule, r: emitNamedFnCall(ctx, fn, "_pos") });
|
|
5217
5503
|
}
|
|
5218
5504
|
if (ctx.runtimeParsers.length !== 0) return null;
|
|
5219
5505
|
const mfSrcs = ctx.mapFns.length > 0 && ctx.mapFnSrcs.every((s) => s !== null) ? ctx.mapFnSrcs : null;
|
|
@@ -5236,14 +5522,14 @@ function compileLinkable(ruleMapArg, ns) {
|
|
|
5236
5522
|
...privateFns
|
|
5237
5523
|
].filter(Boolean);
|
|
5238
5524
|
const wrappers = /* @__PURE__ */ new Map();
|
|
5239
|
-
for (const { key, r } of perEntry) {
|
|
5240
|
-
wrappers.set(key, [
|
|
5525
|
+
for (const { key, rule, r } of perEntry) {
|
|
5526
|
+
wrappers.set(key, publicRuleWrapperSource(rule, [
|
|
5241
5527
|
`function(input, _pos, _ctx) {`,
|
|
5242
5528
|
` let pos = _pos`,
|
|
5243
5529
|
...r.stmts,
|
|
5244
5530
|
` return { ok: true, value: ${r.valueVar}, span: { start: _pos, end: ${r.endVar} } }`,
|
|
5245
5531
|
`}`
|
|
5246
|
-
].join("\n"));
|
|
5532
|
+
].join("\n")));
|
|
5247
5533
|
}
|
|
5248
5534
|
const firstSets = /* @__PURE__ */ new Map();
|
|
5249
5535
|
for (const [key, rule] of ruleMap) {
|
|
@@ -5446,6 +5732,7 @@ function evalRuleMapIR(ir) {
|
|
|
5446
5732
|
"skip",
|
|
5447
5733
|
"trivia",
|
|
5448
5734
|
"label",
|
|
5735
|
+
"field",
|
|
5449
5736
|
"expect",
|
|
5450
5737
|
"_tf",
|
|
5451
5738
|
"_nd",
|
|
@@ -5472,6 +5759,7 @@ function evalRuleMapIR(ir) {
|
|
|
5472
5759
|
skip,
|
|
5473
5760
|
trivia,
|
|
5474
5761
|
label,
|
|
5762
|
+
field,
|
|
5475
5763
|
expect,
|
|
5476
5764
|
_tf,
|
|
5477
5765
|
_nd
|
|
@@ -5486,9 +5774,26 @@ function linkable(rulesMap, ns) {
|
|
|
5486
5774
|
if (!pieces) throw new Error("linkable(): this grammar cannot be compiled to a linkable artifact (contains a runtime-only parser fallback)");
|
|
5487
5775
|
return pieces;
|
|
5488
5776
|
}
|
|
5489
|
-
function
|
|
5777
|
+
function normalizeCstCollapse(collapse) {
|
|
5778
|
+
if (collapse === true) return () => true;
|
|
5779
|
+
if (Array.isArray(collapse)) {
|
|
5780
|
+
const types = new Set(collapse);
|
|
5781
|
+
return (type) => types.has(type);
|
|
5782
|
+
}
|
|
5783
|
+
return typeof collapse === "function" ? collapse : void 0;
|
|
5784
|
+
}
|
|
5785
|
+
function buildCstNode(type, children, _fields, span, _rawChildren, _triviaLog, state) {
|
|
5490
5786
|
return { _tag: "node", type, span: { start: span.start, end: span.end }, state: state ?? null, children: [...children] };
|
|
5491
5787
|
}
|
|
5788
|
+
function cstBuildHost(typeOrOptions, children, _fields, span, rawChildren, triviaLog, state) {
|
|
5789
|
+
if (typeof typeOrOptions === "string") {
|
|
5790
|
+
return buildCstNode(typeOrOptions, children ?? [], _fields, span ?? { start: 0, end: 0 }, rawChildren, triviaLog, state);
|
|
5791
|
+
}
|
|
5792
|
+
const collapse = normalizeCstCollapse(typeOrOptions?.collapse);
|
|
5793
|
+
const host = (type, children2, fields, span2, rawChildren2, triviaLog2, state2) => buildCstNode(type, children2, fields, span2, rawChildren2, triviaLog2, state2);
|
|
5794
|
+
if (collapse) host._parsemanCstCollapse = collapse;
|
|
5795
|
+
return host;
|
|
5796
|
+
}
|
|
5492
5797
|
function pick(grammar, names) {
|
|
5493
5798
|
const p = grammar.ruleFns instanceof Map ? grammar : linkable(grammar);
|
|
5494
5799
|
const keep = /* @__PURE__ */ new Set();
|
|
@@ -5520,8 +5825,9 @@ function fusedBody(pieces) {
|
|
|
5520
5825
|
}
|
|
5521
5826
|
}
|
|
5522
5827
|
const contributing = new Set(winner.values());
|
|
5523
|
-
const
|
|
5524
|
-
const
|
|
5828
|
+
const contributingPieces = [...contributing];
|
|
5829
|
+
const needsEmptyTl = contributingPieces.some((p) => p.needsEmptyTl);
|
|
5830
|
+
const needsHostReads = contributingPieces.some((p) => p.needsHostReads);
|
|
5525
5831
|
const lines = [
|
|
5526
5832
|
// Shared sentinel protocol (must match NAMED_FN_FAIL / NAMED_FN_END in codegen).
|
|
5527
5833
|
"const _pfFail = {}",
|
|
@@ -5529,7 +5835,7 @@ function fusedBody(pieces) {
|
|
|
5529
5835
|
...needsEmptyTl ? ["const _EMPTY_TL = Object.freeze([])"] : [],
|
|
5530
5836
|
...needsHostReads ? [HOST_READS_DECL] : [],
|
|
5531
5837
|
// Each contributing artifact's namespaced private prelude (regexes, _pf, …).
|
|
5532
|
-
...[...
|
|
5838
|
+
...[...new Set(contributingPieces.flatMap((p) => p.prelude))],
|
|
5533
5839
|
// The winning `_r_<Name>` function for each rule (one per name → no redeclare).
|
|
5534
5840
|
...[...winner].map(([k, p]) => p.ruleFns.get(k))
|
|
5535
5841
|
];
|
|
@@ -5552,7 +5858,7 @@ function fusedBody(pieces) {
|
|
|
5552
5858
|
}
|
|
5553
5859
|
);
|
|
5554
5860
|
const env = {};
|
|
5555
|
-
for (const p of
|
|
5861
|
+
for (const p of contributingPieces) {
|
|
5556
5862
|
if (p.mfFns.length) env[`${p.ns}mf`] = p.mfFns;
|
|
5557
5863
|
if (p.buildFns.length) env[`${p.ns}build`] = p.buildFns;
|
|
5558
5864
|
}
|
|
@@ -5572,14 +5878,23 @@ function materializePiece(p) {
|
|
|
5572
5878
|
if (!pieces) throw new Error(`compose: carried IR for ns "${p.ns}" could not be re-lowered`);
|
|
5573
5879
|
return pieces;
|
|
5574
5880
|
}
|
|
5575
|
-
function
|
|
5881
|
+
function nextComposeNs(used) {
|
|
5882
|
+
let ns;
|
|
5883
|
+
do {
|
|
5884
|
+
ns = `_lk${_nsCounter++}_`;
|
|
5885
|
+
} while (used.has(ns));
|
|
5886
|
+
used.add(ns);
|
|
5887
|
+
return ns;
|
|
5888
|
+
}
|
|
5889
|
+
function itemPieces(item, used) {
|
|
5576
5890
|
const carried = item[COMPOSED_PIECES];
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
return
|
|
5891
|
+
const pieces = Array.isArray(carried) ? carried.map(materializePiece) : item.ruleFns instanceof Map ? [item] : [linkable(item, nextComposeNs(used))];
|
|
5892
|
+
for (const p of pieces) used.add(p.ns);
|
|
5893
|
+
return pieces;
|
|
5580
5894
|
}
|
|
5581
5895
|
function compose(items) {
|
|
5582
|
-
const
|
|
5896
|
+
const used = /* @__PURE__ */ new Set();
|
|
5897
|
+
const pieces = items.flatMap((item) => itemPieces(item, used));
|
|
5583
5898
|
const map = fuseRules(pieces);
|
|
5584
5899
|
Object.defineProperty(map, COMPOSED_PIECES, { value: pieces, enumerable: false });
|
|
5585
5900
|
return map;
|
|
@@ -6305,6 +6620,7 @@ export {
|
|
|
6305
6620
|
createVisitor,
|
|
6306
6621
|
cstBuildHost,
|
|
6307
6622
|
expect,
|
|
6623
|
+
field,
|
|
6308
6624
|
gapIsSignificant,
|
|
6309
6625
|
gapText,
|
|
6310
6626
|
guard,
|