parseman 0.19.0 → 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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,cAAc,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,oBAAoB,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAE1P,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAClD,YAAY,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAE9D,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAQ9C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AACpE,YAAY,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAA;AAEhE,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAChD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAC1E,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAA;AAC/C,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAA;AAC1C,OAAO,EAAE,GAAG,EAAE,MAAM,sBAAsB,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAA;AAC5C,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AAEnE,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAA;AAC5E,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAA;AAClE,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAC3F,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAE9C,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAA;AAC/C,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC3E,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAClE,YAAY,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAE1E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AACxF,YAAY,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAA;AAEzD,OAAO,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAClD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAChE,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAA;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAC5D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAC1D,YAAY,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAA;AAEzE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAE5G,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAC9C,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAA;AACtF,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAA;AACzC,YAAY,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAA;AAC1E,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AACzF,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AACnD,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACrF,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AACvD,YAAY,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAA;AAEhE,OAAO,EACL,WAAW,EACX,gBAAgB,EAChB,gBAAgB,EAChB,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,WAAW,EACX,WAAW,EACX,UAAU,EACV,gBAAgB,GACjB,MAAM,uBAAuB,CAAA;AAC9B,YAAY,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EACL,UAAU,EACV,UAAU,EACV,cAAc,EACd,aAAa,EACb,SAAS,GACV,MAAM,yBAAyB,CAAA;AAChC,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -327,9 +327,9 @@ function asciiFoldEq(a, b) {
327
327
  }
328
328
  function literal(value, opts = {}) {
329
329
  const caseInsensitive = opts.caseInsensitive ?? false;
330
- const firstSet = value.length > 0 ? fromChar(value.codePointAt(0)) : empty();
330
+ const firstSet2 = value.length > 0 ? fromChar(value.codePointAt(0)) : empty();
331
331
  const meta = {
332
- firstSet,
332
+ firstSet: firstSet2,
333
333
  canMatchNewline: value.includes("\n"),
334
334
  isTrivia: false
335
335
  };
@@ -341,7 +341,7 @@ function literal(value, opts = {}) {
341
341
  meta.firstSet = firstLower !== void 0 && firstUpper !== void 0 ? firstLower === firstUpper ? { kind: "ranges", ranges: [{ lo: firstLower, hi: firstLower }] } : { kind: "ranges", ranges: [
342
342
  { lo: firstLower, hi: firstLower },
343
343
  { lo: firstUpper, hi: firstUpper }
344
- ] } : firstSet;
344
+ ] } : firstSet2;
345
345
  }
346
346
  return {
347
347
  _tag: "literal",
@@ -364,68 +364,66 @@ function literal(value, opts = {}) {
364
364
  };
365
365
  }
366
366
 
367
- // src/combinators/regex.ts
368
- var firstSetAnalyzer = null;
369
- function registerRegexAnalyzer(analyzer) {
370
- firstSetAnalyzer = analyzer;
371
- }
372
- var permissiveFirstSet = () => ({ firstSet: any(), canMatchNewline: true });
373
- 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 };
374
369
  var SPACE_RANGES = [
375
370
  [9, 13],
376
371
  [32, 32],
377
372
  [160, 160],
378
373
  [5760, 5760],
379
374
  [8192, 8202],
380
- [8232, 8233],
375
+ [8232, 8232],
376
+ [8233, 8233],
381
377
  [8239, 8239],
382
378
  [8287, 8287],
383
379
  [12288, 12288],
384
380
  [65279, 65279]
385
381
  ];
386
- var CLASS_ESCAPES = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
387
382
  function shorthandRanges(ch) {
388
383
  if (ch === "d") return [[48, 57]];
389
384
  if (ch === "s") return SPACE_RANGES;
390
385
  return [[48, 57], [65, 90], [97, 122], [95, 95]];
391
386
  }
392
- function inRanges(cp, ranges) {
393
- for (let i = 0; i < ranges.length; i++) {
394
- const [lo, hi] = ranges[i];
395
- if (cp >= lo && cp <= hi) return true;
396
- }
397
- 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 };
398
392
  }
399
- function readClassRanges(body) {
400
- if (body.startsWith("^")) return null;
393
+ function parseClassRanges(body) {
401
394
  const ranges = [];
402
395
  let i = 0;
403
396
  const readAtom = () => {
404
397
  const ch = body[i];
405
398
  if (ch === void 0) return null;
406
399
  if (ch === "\\") {
407
- const esc = body[i + 1];
408
- if (esc === void 0) return null;
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;
409
407
  i += 2;
410
- if (esc === "d" || esc === "w" || esc === "s") return { ranges: shorthandRanges(esc) };
411
- if (esc in CLASS_ESCAPES) return { cp: CLASS_ESCAPES[esc] };
412
- if (esc >= "a" && esc <= "z" || esc >= "A" && esc <= "Z") return null;
413
- return { cp: esc.charCodeAt(0) };
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) };
414
412
  }
415
- i++;
416
- return { cp: ch.charCodeAt(0) };
413
+ i += ch.length;
414
+ return { cp: ch.codePointAt(0) };
417
415
  };
418
416
  while (i < body.length) {
419
417
  const lo = readAtom();
420
- if (!lo) return null;
421
- if ("ranges" in lo) {
422
- ranges.push(...lo.ranges);
418
+ if (lo === null) return null;
419
+ if ("set" in lo) {
420
+ ranges.push(...lo.set);
423
421
  continue;
424
422
  }
425
423
  if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
426
- i++;
424
+ i += 1;
427
425
  const hi = readAtom();
428
- if (!hi || "ranges" in hi) return null;
426
+ if (hi === null || "set" in hi) return null;
429
427
  ranges.push([lo.cp, hi.cp]);
430
428
  } else {
431
429
  ranges.push([lo.cp, lo.cp]);
@@ -433,6 +431,25 @@ function readClassRanges(body) {
433
431
  }
434
432
  return ranges.length ? ranges : null;
435
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
+ }
436
453
  function shortScanner(source, flags) {
437
454
  if (/[imsuvy]/.test(flags)) return null;
438
455
  let ranges = null;
@@ -466,8 +483,8 @@ function regex(pattern, flags = "") {
466
483
  const resolvedFlags = typeof pattern === "string" ? flags : pattern.flags;
467
484
  const anchored = new RegExp(source, "y" + resolvedFlags.replace(/[gy]/g, ""));
468
485
  const scan = shortScanner(source, resolvedFlags);
469
- const { firstSet, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
470
- const meta = { firstSet, canMatchNewline, isTrivia: false };
486
+ const { firstSet: firstSet2, canMatchNewline } = (firstSetAnalyzer ?? permissiveFirstSet)(source);
487
+ const meta = { firstSet: firstSet2, canMatchNewline, isTrivia: false };
471
488
  return {
472
489
  _tag: "regex",
473
490
  _meta: meta,
@@ -495,111 +512,266 @@ function regex(pattern, flags = "") {
495
512
  };
496
513
  }
497
514
 
498
- // src/combinators/regex-analyze.ts
499
- import regexpTree from "regexp-tree";
500
- function firstSetFromRegex(pattern) {
501
- try {
502
- const ast = regexpTree.parse(`/${pattern}/`);
503
- return extractFirstSet(ast.body);
504
- } catch {
505
- return { firstSet: any(), canMatchNewline: true };
506
- }
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 };
507
520
  }
508
- function canBeEmpty(node2) {
509
- if (!node2) return true;
510
- switch (node2.type) {
511
- case "Repetition": {
512
- const q = node2.quantifier;
513
- return q.kind === "*" || q.kind === "?" || q.kind === "Range" && (q.from ?? 1) === 0;
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());
514
537
  }
515
- case "Alternative": {
516
- const exprs = node2.expressions;
517
- return !exprs || exprs.length === 0 || exprs.every((e) => canBeEmpty(e));
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();
518
565
  }
519
- case "Group":
520
- return canBeEmpty(node2.expression);
521
- case "Disjunction":
522
- return canBeEmpty(node2.left) || canBeEmpty(node2.right);
523
- default:
524
- return false;
525
- }
526
- }
527
- function extractFirstSet(node2) {
528
- if (!node2) return { firstSet: empty(), canMatchNewline: false };
529
- switch (node2.type) {
530
- case "Disjunction": {
531
- const left = extractFirstSet(node2.left);
532
- const right = extractFirstSet(node2.right);
533
- return {
534
- firstSet: union(left.firstSet, right.firstSet),
535
- canMatchNewline: left.canMatchNewline || right.canMatchNewline
536
- };
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");
537
603
  }
538
- case "Alternative": {
539
- const exprs = node2.expressions;
540
- if (!exprs || exprs.length === 0) return { firstSet: empty(), canMatchNewline: false };
541
- let fs = empty();
542
- let canNL = false;
543
- for (const expr of exprs) {
544
- const r = extractFirstSet(expr);
545
- fs = union(fs, r.firstSet);
546
- canNL = canNL || r.canMatchNewline;
547
- if (!canBeEmpty(expr)) break;
548
- }
549
- return { firstSet: fs, canMatchNewline: canNL };
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;
550
625
  }
551
- case "Char": {
552
- const kind = node2.kind;
553
- if (kind === "simple") {
554
- const code = node2.codePoint ?? node2.value.codePointAt(0) ?? 0;
555
- return { firstSet: fromRange(code, code), canMatchNewline: code === 10 };
556
- }
557
- if (kind === "meta") {
558
- const val = node2.value;
559
- if (val === ".") return { firstSet: any(), canMatchNewline: false };
560
- if (val === "d") return { firstSet: fromRange(48, 57), canMatchNewline: false };
561
- if (val === "D") return { firstSet: any(), canMatchNewline: true };
562
- if (val === "w") return {
563
- firstSet: union(
564
- union(fromRange(48, 57), fromRange(65, 90)),
565
- union(fromRange(97, 122), fromRange(95, 95))
566
- ),
567
- canMatchNewline: false
568
- };
569
- if (val === "s") return { firstSet: fromRange(9, 13), canMatchNewline: true };
570
- 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++;
571
643
  }
572
- return { firstSet: any(), canMatchNewline: true };
573
644
  }
574
- case "CharacterClass": {
575
- const expressions = node2.expressions;
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": {
730
+ let fs = empty();
731
+ for (const arm of n.arms) fs = union(fs, firstSet(arm));
732
+ return fs;
733
+ }
734
+ case "seq": {
576
735
  let fs = empty();
577
- let canNL = false;
578
- for (const expr of expressions) {
579
- if (expr.type === "ClassRange") {
580
- const from = expr.from.codePoint;
581
- const to = expr.to.codePoint;
582
- fs = union(fs, fromRange(from, to));
583
- if (from <= 10 && 10 <= to) canNL = true;
584
- } else if (expr.type === "Char") {
585
- const r = extractFirstSet(expr);
586
- fs = union(fs, r.firstSet);
587
- canNL = canNL || r.canMatchNewline;
588
- }
736
+ for (const part of n.parts) {
737
+ fs = union(fs, firstSet(part));
738
+ if (!nullable(part)) break;
589
739
  }
590
- if (node2.negative) return { firstSet: any(), canMatchNewline: true };
591
- return { firstSet: fs, canMatchNewline: canNL };
740
+ return fs;
592
741
  }
593
- case "Repetition": {
594
- return extractFirstSet(node2.expression);
595
- }
596
- case "Group": {
597
- return extractFirstSet(node2.expression);
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;
598
762
  }
599
- default:
600
- return { firstSet: any(), canMatchNewline: true };
601
763
  }
602
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
+ }
603
775
 
604
776
  // src/combinators/keywords.ts
605
777
  function word(str, boundary = "_0-9A-Za-z") {
@@ -617,19 +789,19 @@ function keywords(words, opts = {}) {
617
789
  const boundary = opts.boundary ? `(?![${opts.boundary}])` : "";
618
790
  const flags = opts.caseInsensitive ? "iuy" : "uy";
619
791
  const re = new RegExp(`(?:${alt})${boundary}`, flags);
620
- let firstSet = empty();
792
+ let firstSet2 = empty();
621
793
  for (const w of sorted) {
622
794
  if (w.length === 0) continue;
623
795
  const cp = w.codePointAt(0);
624
- firstSet = union(firstSet, fromChar(cp));
796
+ firstSet2 = union(firstSet2, fromChar(cp));
625
797
  if (opts.caseInsensitive) {
626
798
  const u = String.fromCodePoint(cp).toUpperCase().codePointAt(0);
627
799
  const l = String.fromCodePoint(cp).toLowerCase().codePointAt(0);
628
- if (u !== void 0) firstSet = union(firstSet, fromChar(u));
629
- if (l !== void 0) firstSet = union(firstSet, fromChar(l));
800
+ if (u !== void 0) firstSet2 = union(firstSet2, fromChar(u));
801
+ if (l !== void 0) firstSet2 = union(firstSet2, fromChar(l));
630
802
  }
631
803
  }
632
- const meta = { firstSet, canMatchNewline: false, isTrivia: false };
804
+ const meta = { firstSet: firstSet2, canMatchNewline: false, isTrivia: false };
633
805
  return {
634
806
  _tag: "keywords",
635
807
  _meta: meta,
@@ -1993,77 +2165,11 @@ function expect(combinator, label2) {
1993
2165
 
1994
2166
  // src/compiler/scannable-run.ts
1995
2167
  var BACKSLASH = 92;
1996
- var CLASS_ESCAPES2 = { t: 9, n: 10, r: 13, f: 12, v: 11, "0": 0 };
1997
2168
  var META = new Set("()[]{}*+?|^$.".split(""));
1998
- var SPACE_RANGES2 = [
1999
- [9, 13],
2000
- [32, 32],
2001
- [160, 160],
2002
- [5760, 5760],
2003
- [8192, 8202],
2004
- [8232, 8232],
2005
- [8233, 8233],
2006
- [8239, 8239],
2007
- [8287, 8287],
2008
- [12288, 12288],
2009
- [65279, 65279]
2010
- ];
2011
- function shorthandRanges2(ch) {
2012
- if (ch === "d") return [[48, 57]];
2013
- if (ch === "s") return SPACE_RANGES2;
2014
- return [[48, 57], [65, 90], [97, 122], [95, 95]];
2015
- }
2016
- function readUnicodeEscape(body, i) {
2017
- if (body[i] !== "\\" || body[i + 1] !== "u") return null;
2018
- const hex = body.slice(i + 2, i + 6);
2019
- if (!/^[0-9a-fA-F]{4}$/.test(hex)) return null;
2020
- return { cp: Number.parseInt(hex, 16), next: i + 6 };
2021
- }
2022
- function parseClassRanges(body) {
2023
- const ranges = [];
2024
- let i = 0;
2025
- const readAtom = () => {
2026
- const ch = body[i];
2027
- if (ch === void 0) return null;
2028
- if (ch === "\\") {
2029
- const uni = readUnicodeEscape(body, i);
2030
- if (uni) {
2031
- i = uni.next;
2032
- return { cp: uni.cp };
2033
- }
2034
- const e = body[i + 1];
2035
- if (e === void 0) return null;
2036
- i += 2;
2037
- if (e in CLASS_ESCAPES2) return { cp: CLASS_ESCAPES2[e] };
2038
- if (e === "d" || e === "w" || e === "s") return { set: shorthandRanges2(e) };
2039
- if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
2040
- return { cp: e.codePointAt(0) };
2041
- }
2042
- i += ch.length;
2043
- return { cp: ch.codePointAt(0) };
2044
- };
2045
- while (i < body.length) {
2046
- const lo = readAtom();
2047
- if (lo === null) return null;
2048
- if ("set" in lo) {
2049
- ranges.push(...lo.set);
2050
- continue;
2051
- }
2052
- if (body[i] === "-" && body[i + 1] !== void 0 && body[i + 1] !== "]") {
2053
- i += 1;
2054
- const hi = readAtom();
2055
- if (hi === null || "set" in hi) return null;
2056
- ranges.push([lo.cp, hi.cp]);
2057
- } else {
2058
- ranges.push([lo.cp, lo.cp]);
2059
- }
2060
- }
2061
- return ranges.length ? ranges : null;
2062
- }
2063
2169
  function classToRanges(cls) {
2064
- if (cls === "\\d") return shorthandRanges2("d");
2065
- if (cls === "\\w") return shorthandRanges2("w");
2066
- if (cls === "\\s") return shorthandRanges2("s");
2170
+ if (cls === "\\d") return shorthandRanges("d");
2171
+ if (cls === "\\w") return shorthandRanges("w");
2172
+ if (cls === "\\s") return shorthandRanges("s");
2067
2173
  const body = cls.slice(1, -1);
2068
2174
  if (body.startsWith("^")) return null;
2069
2175
  return parseClassRanges(body);
@@ -2081,7 +2187,7 @@ function literalCodePoints(frag) {
2081
2187
  if (ch === "\\") {
2082
2188
  const e = frag[i + 1];
2083
2189
  if (e === void 0) return null;
2084
- out.push(e in CLASS_ESCAPES2 ? CLASS_ESCAPES2[e] : e.codePointAt(0));
2190
+ out.push(e in CLASS_ESCAPES ? CLASS_ESCAPES[e] : e.codePointAt(0));
2085
2191
  i += 2;
2086
2192
  continue;
2087
2193
  }
@@ -2174,7 +2280,7 @@ function parseSeqParts(source) {
2174
2280
  if (e === "d" || e === "w" || e === "s") {
2175
2281
  flush();
2176
2282
  i += 2;
2177
- i += runFrom(shorthandRanges2(e), false, source[i]);
2283
+ i += runFrom(shorthandRanges(e), false, source[i]);
2178
2284
  continue;
2179
2285
  }
2180
2286
  const uni = readUnicodeEscape(source, i);
@@ -2183,8 +2289,8 @@ function parseSeqParts(source) {
2183
2289
  cp2 = uni.cp;
2184
2290
  i = uni.next;
2185
2291
  } else if (e === void 0) return null;
2186
- else if (e in CLASS_ESCAPES2) {
2187
- cp2 = CLASS_ESCAPES2[e];
2292
+ else if (e in CLASS_ESCAPES) {
2293
+ cp2 = CLASS_ESCAPES[e];
2188
2294
  i += 2;
2189
2295
  } else if (e >= "a" && e <= "z" || e >= "A" && e <= "Z") return null;
2190
2296
  else {
@@ -2291,7 +2397,7 @@ function rangesSubset(sub, sup) {
2291
2397
  }
2292
2398
  function parseClassOperand(body) {
2293
2399
  if (body === "\\d" || body === "\\w" || body === "\\s") {
2294
- return { ranges: shorthandRanges2(body[1]), negated: false };
2400
+ return { ranges: shorthandRanges(body[1]), negated: false };
2295
2401
  }
2296
2402
  if (body.length >= 2 && body[0] === "[" && body[body.length - 1] === "]") {
2297
2403
  let inner = body.slice(1, -1);
@@ -2724,7 +2830,7 @@ function parseScanShapeCore(source) {
2724
2830
  }
2725
2831
  m = /^\\([dws])([+*])$/.exec(source);
2726
2832
  if (m) {
2727
- return { kind: "chars", ranges: shorthandRanges2(m[1]), minOne: m[2] === "+" };
2833
+ return { kind: "chars", ranges: shorthandRanges(m[1]), minOne: m[2] === "+" };
2728
2834
  }
2729
2835
  m = /^(\[(?:\\.|[^\]])+\]|\\[dws])(\[(?:\\.|[^\]])+\]|\\[dws])\*$/.exec(source);
2730
2836
  if (m) {