clarity-pattern-parser 8.4.15 → 9.0.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.
Files changed (100) hide show
  1. package/TODO.md +4 -1
  2. package/dist/grammar/Grammar.d.ts +18 -10
  3. package/dist/grammar/patterns/andLiteral.d.ts +2 -0
  4. package/dist/grammar/patterns/anonymousPattern.d.ts +2 -0
  5. package/dist/grammar/patterns/inlinePattern.d.ts +1 -0
  6. package/dist/grammar/patterns/literals.d.ts +3 -0
  7. package/dist/grammar/patterns/pattern.d.ts +2 -2
  8. package/dist/grammar/patterns.d.ts +2 -0
  9. package/dist/index.browser.js +471 -184
  10. package/dist/index.browser.js.map +1 -1
  11. package/dist/index.d.ts +3 -1
  12. package/dist/index.esm.js +470 -185
  13. package/dist/index.esm.js.map +1 -1
  14. package/dist/index.js +471 -184
  15. package/dist/index.js.map +1 -1
  16. package/dist/patterns/And.d.ts +4 -1
  17. package/dist/patterns/Cursor.d.ts +5 -0
  18. package/dist/patterns/CursorHistory.d.ts +7 -0
  19. package/dist/patterns/FiniteRepeat.d.ts +4 -1
  20. package/dist/patterns/InfiniteRepeat.d.ts +5 -4
  21. package/dist/patterns/Literal.d.ts +6 -5
  22. package/dist/patterns/Not.d.ts +5 -4
  23. package/dist/patterns/Or.d.ts +5 -4
  24. package/dist/patterns/Pattern.d.ts +4 -2
  25. package/dist/patterns/Reference.d.ts +5 -4
  26. package/dist/patterns/Regex.d.ts +5 -4
  27. package/dist/patterns/Repeat.d.ts +3 -0
  28. package/dist/patterns/arePatternsEqual.d.ts +2 -0
  29. package/package.json +1 -1
  30. package/src/grammar/Grammar.test.ts +117 -74
  31. package/src/grammar/Grammar.ts +241 -158
  32. package/src/grammar/patterns/anonymousPattern.ts +23 -0
  33. package/src/grammar/patterns/body.ts +9 -6
  34. package/src/grammar/patterns/comment.ts +3 -2
  35. package/src/grammar/patterns/grammar.ts +15 -12
  36. package/src/grammar/patterns/import.ts +18 -12
  37. package/src/grammar/patterns/literal.ts +2 -1
  38. package/src/grammar/patterns/literals.ts +20 -0
  39. package/src/grammar/patterns/optionsLiteral.ts +19 -0
  40. package/src/grammar/patterns/pattern.ts +23 -9
  41. package/src/grammar/patterns/regexLiteral.ts +1 -0
  42. package/src/grammar/patterns/repeatLiteral.ts +30 -25
  43. package/src/grammar/patterns/sequenceLiteral.ts +24 -0
  44. package/src/grammar/patterns/spaces.ts +8 -6
  45. package/src/grammar/patterns/statement.ts +8 -20
  46. package/src/grammar/patterns.test.ts +38 -0
  47. package/src/grammar/patterns.ts +24 -0
  48. package/src/grammar/spec.md +4 -12
  49. package/src/index.ts +11 -5
  50. package/src/intellisense/AutoComplete.test.ts +41 -40
  51. package/src/intellisense/css/method.ts +2 -2
  52. package/src/intellisense/css/unit.ts +2 -2
  53. package/src/intellisense/css/value.ts +1 -1
  54. package/src/intellisense/javascript/Javascript.test.ts +31 -32
  55. package/src/intellisense/javascript/arrayLiteral.ts +7 -6
  56. package/src/intellisense/javascript/assignment.ts +6 -6
  57. package/src/intellisense/javascript/deleteStatement.ts +2 -2
  58. package/src/intellisense/javascript/escapedCharacter.ts +6 -6
  59. package/src/intellisense/javascript/exponent.ts +6 -6
  60. package/src/intellisense/javascript/expression.ts +18 -17
  61. package/src/intellisense/javascript/fraction.ts +3 -3
  62. package/src/intellisense/javascript/infixOperator.ts +10 -10
  63. package/src/intellisense/javascript/integer.ts +1 -1
  64. package/src/intellisense/javascript/invocation.ts +8 -7
  65. package/src/intellisense/javascript/literal.ts +3 -3
  66. package/src/intellisense/javascript/numberLiteral.ts +5 -4
  67. package/src/intellisense/javascript/objectAccess.ts +2 -3
  68. package/src/intellisense/javascript/objectLiteral.ts +8 -7
  69. package/src/intellisense/javascript/optionalSpaces.ts +2 -1
  70. package/src/intellisense/javascript/parameters.ts +5 -5
  71. package/src/intellisense/javascript/prefixOperator.ts +3 -4
  72. package/src/intellisense/javascript/propertyAccess.ts +9 -8
  73. package/src/intellisense/javascript/stringLiteral.ts +14 -15
  74. package/src/patterns/Cursor.ts +42 -4
  75. package/src/patterns/CursorHistory.ts +20 -4
  76. package/src/patterns/FiniteRepeat.test.ts +52 -51
  77. package/src/patterns/FiniteRepeat.ts +60 -38
  78. package/src/patterns/InfiniteRepeat.test.ts +36 -49
  79. package/src/patterns/InfiniteRepeat.ts +70 -37
  80. package/src/patterns/Literal.test.ts +16 -27
  81. package/src/patterns/Literal.ts +34 -27
  82. package/src/patterns/Not.test.ts +7 -7
  83. package/src/patterns/Not.ts +24 -6
  84. package/src/patterns/Optional.test.ts +164 -0
  85. package/src/patterns/Optional.ts +143 -0
  86. package/src/patterns/{Or.test.ts → Options.test.ts} +51 -49
  87. package/src/patterns/{Or.ts → Options.ts} +32 -23
  88. package/src/patterns/Pattern.ts +6 -5
  89. package/src/patterns/Reference.test.ts +21 -22
  90. package/src/patterns/Reference.ts +26 -15
  91. package/src/patterns/Regex.test.ts +15 -15
  92. package/src/patterns/Regex.ts +29 -19
  93. package/src/patterns/Repeat.test.ts +12 -22
  94. package/src/patterns/Repeat.ts +22 -21
  95. package/src/patterns/{And.test.ts → Sequence.test.ts} +78 -78
  96. package/src/patterns/{And.ts → Sequence.ts} +40 -29
  97. package/src/patterns/arePatternsEqual.ts +12 -0
  98. package/src/patterns/clonePatterns.ts +2 -2
  99. package/src/grammar/patterns/andLiteral.ts +0 -8
  100. package/src/grammar/patterns/orLiteral.ts +0 -8
package/dist/index.js CHANGED
@@ -247,6 +247,7 @@ class CursorHistory {
247
247
  this._patterns = [];
248
248
  this._nodes = [];
249
249
  this._errors = [];
250
+ this._trace = [];
250
251
  }
251
252
  get isRecording() {
252
253
  return this._isRecording;
@@ -275,6 +276,9 @@ class CursorHistory {
275
276
  get patterns() {
276
277
  return this._patterns;
277
278
  }
279
+ get trace() {
280
+ return this._trace;
281
+ }
278
282
  recordMatch(pattern, node) {
279
283
  if (this._isRecording) {
280
284
  this._patterns.push(pattern);
@@ -329,6 +333,11 @@ class CursorHistory {
329
333
  resolveError() {
330
334
  this._currentError = null;
331
335
  }
336
+ pushStackTrace(trace) {
337
+ if (this._isRecording) {
338
+ this._trace.push(trace);
339
+ }
340
+ }
332
341
  }
333
342
 
334
343
  class Cursor {
@@ -385,6 +394,7 @@ class Cursor {
385
394
  this._index = 0;
386
395
  this._length = text.length;
387
396
  this._history = new CursorHistory();
397
+ this._stackTrace = [];
388
398
  }
389
399
  hasNext() {
390
400
  return this._index + 1 < this._length;
@@ -434,9 +444,42 @@ class Cursor {
434
444
  stopRecording() {
435
445
  this._history.stopRecording();
436
446
  }
447
+ startParseWith(pattern) {
448
+ const patternName = pattern.name;
449
+ const trace = {
450
+ pattern,
451
+ cursorIndex: this.index
452
+ };
453
+ if (this._stackTrace.find(t => t.pattern.id === pattern.id && this.index === t.cursorIndex)) {
454
+ throw new Error(`Cyclical Pattern: ${this._stackTrace.map(t => `${t.pattern.name}#${t.pattern.id}{${t.cursorIndex}}`).join(" -> ")} -> ${patternName}#${pattern.id}{${this.index}}.`);
455
+ }
456
+ this._history.pushStackTrace(trace);
457
+ this._stackTrace.push(trace);
458
+ }
459
+ endParse() {
460
+ this._stackTrace.pop();
461
+ }
462
+ audit() {
463
+ return this._history.trace.map(t => {
464
+ const onChar = this.getChars(t.cursorIndex, t.cursorIndex);
465
+ const restChars = this.getChars(t.cursorIndex + 1, t.cursorIndex + 5);
466
+ const context = `{${t.cursorIndex}}[${onChar}]${restChars}`;
467
+ return `${this._buildPatternContext(t.pattern)}-->${context}`;
468
+ });
469
+ }
470
+ _buildPatternContext(pattern) {
471
+ if (pattern.parent != null) {
472
+ return `${pattern.parent.name}.${pattern.name}`;
473
+ }
474
+ return pattern.name;
475
+ }
437
476
  }
438
477
 
478
+ let idIndex$8 = 0;
439
479
  class Literal {
480
+ get id() {
481
+ return this._id;
482
+ }
440
483
  get type() {
441
484
  return this._type;
442
485
  }
@@ -459,9 +502,10 @@ class Literal {
459
502
  if (value.length === 0) {
460
503
  throw new Error("Value Cannot be empty.");
461
504
  }
505
+ this._id = `literal-${idIndex$8++}`;
462
506
  this._type = "literal";
463
507
  this._name = name;
464
- this._literal = value;
508
+ this._text = value;
465
509
  this._runes = Array.from(value);
466
510
  this._isOptional = isOptional;
467
511
  this._parent = null;
@@ -474,8 +518,9 @@ class Literal {
474
518
  const ast = this.parse(cursor);
475
519
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
476
520
  }
477
- exec(text) {
521
+ exec(text, record = false) {
478
522
  const cursor = new Cursor(text);
523
+ record && cursor.startRecording();
479
524
  const ast = this.parse(cursor);
480
525
  return {
481
526
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -483,20 +528,24 @@ class Literal {
483
528
  };
484
529
  }
485
530
  parse(cursor) {
531
+ cursor.startParseWith(this);
486
532
  this._firstIndex = cursor.index;
487
533
  const passed = this._tryToParse(cursor);
488
534
  if (passed) {
489
535
  cursor.resolveError();
490
536
  const node = this._createNode();
491
537
  cursor.recordMatch(this, node);
538
+ cursor.endParse();
492
539
  return node;
493
540
  }
494
541
  if (!this._isOptional) {
495
542
  cursor.recordErrorAt(this._firstIndex, this._endIndex, this);
543
+ cursor.endParse();
496
544
  return null;
497
545
  }
498
546
  cursor.resolveError();
499
547
  cursor.moveTo(this._firstIndex);
548
+ cursor.endParse();
500
549
  return null;
501
550
  }
502
551
  _tryToParse(cursor) {
@@ -510,7 +559,7 @@ class Literal {
510
559
  break;
511
560
  }
512
561
  if (i + 1 === literalRuneLength) {
513
- this._lastIndex = this._firstIndex + this._literal.length - 1;
562
+ this._lastIndex = this._firstIndex + this._text.length - 1;
514
563
  passed = true;
515
564
  break;
516
565
  }
@@ -523,14 +572,15 @@ class Literal {
523
572
  return passed;
524
573
  }
525
574
  _createNode() {
526
- return new Node("literal", this._name, this._firstIndex, this._lastIndex, undefined, this._literal);
575
+ return new Node("literal", this._name, this._firstIndex, this._lastIndex, undefined, this._text);
527
576
  }
528
577
  clone(name = this._name, isOptional = this._isOptional) {
529
- const clone = new Literal(name, this._literal, isOptional);
578
+ const clone = new Literal(name, this._text, isOptional);
579
+ clone._id = this._id;
530
580
  return clone;
531
581
  }
532
582
  getTokens() {
533
- return [this._literal];
583
+ return [this._text];
534
584
  }
535
585
  getTokensAfter(_lastMatched) {
536
586
  return [];
@@ -556,9 +606,16 @@ class Literal {
556
606
  find(_predicate) {
557
607
  return null;
558
608
  }
609
+ isEqual(pattern) {
610
+ return pattern.type === this.type && pattern._text === this._text;
611
+ }
559
612
  }
560
613
 
614
+ let idIndex$7 = 0;
561
615
  class Regex {
616
+ get id() {
617
+ return this._id;
618
+ }
562
619
  get type() {
563
620
  return this._type;
564
621
  }
@@ -583,6 +640,7 @@ class Regex {
583
640
  this._firstIndex = -1;
584
641
  this._substring = "";
585
642
  this._tokens = [];
643
+ this._id = `regex-${idIndex$7++}`;
586
644
  this._type = "regex";
587
645
  this._name = name;
588
646
  this._isOptional = isOptional;
@@ -607,8 +665,9 @@ class Regex {
607
665
  const ast = this.parse(cursor);
608
666
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
609
667
  }
610
- exec(text) {
668
+ exec(text, record = false) {
611
669
  const cursor = new Cursor(text);
670
+ record && cursor.startRecording();
612
671
  const ast = this.parse(cursor);
613
672
  return {
614
673
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -616,9 +675,11 @@ class Regex {
616
675
  };
617
676
  }
618
677
  parse(cursor) {
678
+ cursor.startParseWith(this);
619
679
  this._firstIndex = cursor.index;
620
680
  this.resetState(cursor);
621
681
  this.tryToParse(cursor);
682
+ cursor.endParse();
622
683
  return this._node;
623
684
  }
624
685
  resetState(cursor) {
@@ -650,9 +711,10 @@ class Regex {
650
711
  this._node = null;
651
712
  }
652
713
  clone(name = this._name, isOptional = this._isOptional) {
653
- const pattern = new Regex(name, this._originalRegexString, isOptional);
654
- pattern._tokens = this._tokens.slice();
655
- return pattern;
714
+ const clone = new Regex(name, this._originalRegexString, isOptional);
715
+ clone._tokens = this._tokens.slice();
716
+ clone._id = this._id;
717
+ return clone;
656
718
  }
657
719
  getTokens() {
658
720
  return this._tokens;
@@ -684,6 +746,9 @@ class Regex {
684
746
  setTokens(tokens) {
685
747
  this._tokens = tokens;
686
748
  }
749
+ isEqual(pattern) {
750
+ return pattern.type === this.type && pattern._originalRegexString === this._originalRegexString;
751
+ }
687
752
  }
688
753
 
689
754
  function findPattern(pattern, predicate) {
@@ -708,7 +773,11 @@ function findPattern(pattern, predicate) {
708
773
  }
709
774
  }
710
775
 
776
+ let idIndex$6 = 0;
711
777
  class Reference {
778
+ get id() {
779
+ return this._id;
780
+ }
712
781
  get type() {
713
782
  return this._type;
714
783
  }
@@ -728,6 +797,7 @@ class Reference {
728
797
  return this._isOptional;
729
798
  }
730
799
  constructor(name, isOptional = false) {
800
+ this._id = `reference-${idIndex$6++}`;
731
801
  this._type = "reference";
732
802
  this._name = name;
733
803
  this._parent = null;
@@ -740,8 +810,9 @@ class Reference {
740
810
  const ast = this.parse(cursor);
741
811
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
742
812
  }
743
- exec(text) {
813
+ exec(text, record = false) {
744
814
  const cursor = new Cursor(text);
815
+ record && cursor.startRecording();
745
816
  const ast = this.parse(cursor);
746
817
  return {
747
818
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -817,7 +888,12 @@ class Reference {
817
888
  return null;
818
889
  }
819
890
  clone(name = this._name, isOptional = this._isOptional) {
820
- return new Reference(name, isOptional);
891
+ const clone = new Reference(name, isOptional);
892
+ clone._id = this._id;
893
+ return clone;
894
+ }
895
+ isEqual(pattern) {
896
+ return pattern.type === this.type && pattern.name === this.name;
821
897
  }
822
898
  }
823
899
 
@@ -825,7 +901,11 @@ function clonePatterns(patterns, isOptional) {
825
901
  return patterns.map(p => p.clone(p.name, isOptional));
826
902
  }
827
903
 
904
+ let idIndex$5 = 0;
828
905
  class Or {
906
+ get id() {
907
+ return this._id;
908
+ }
829
909
  get type() {
830
910
  return this._type;
831
911
  }
@@ -850,6 +930,7 @@ class Or {
850
930
  }
851
931
  const children = clonePatterns(options, false);
852
932
  this._assignChildrenToParent(children);
933
+ this._id = `or-${idIndex$5++}`;
853
934
  this._type = "or";
854
935
  this._name = name;
855
936
  this._parent = null;
@@ -868,8 +949,9 @@ class Or {
868
949
  const ast = this.parse(cursor);
869
950
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
870
951
  }
871
- exec(text) {
952
+ exec(text, record = false) {
872
953
  const cursor = new Cursor(text);
954
+ record && cursor.startRecording();
873
955
  const ast = this.parse(cursor);
874
956
  return {
875
957
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -877,19 +959,23 @@ class Or {
877
959
  };
878
960
  }
879
961
  parse(cursor) {
962
+ cursor.startParseWith(this);
880
963
  this._firstIndex = cursor.index;
881
964
  const node = this._tryToParse(cursor);
882
965
  if (node != null) {
883
966
  cursor.moveTo(node.lastIndex);
884
967
  cursor.resolveError();
968
+ cursor.endParse();
885
969
  return node;
886
970
  }
887
971
  if (!this._isOptional) {
888
972
  cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
973
+ cursor.endParse();
889
974
  return null;
890
975
  }
891
976
  cursor.resolveError();
892
977
  cursor.moveTo(this._firstIndex);
978
+ cursor.endParse();
893
979
  return null;
894
980
  }
895
981
  _tryToParse(cursor) {
@@ -952,11 +1038,19 @@ class Or {
952
1038
  }
953
1039
  clone(name = this._name, isOptional = this._isOptional) {
954
1040
  const or = new Or(name, this._children, isOptional, this._isGreedy);
1041
+ or._id = this._id;
955
1042
  return or;
956
1043
  }
1044
+ isEqual(pattern) {
1045
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
1046
+ }
957
1047
  }
958
1048
 
1049
+ let idIndex$4 = 0;
959
1050
  class FiniteRepeat {
1051
+ get id() {
1052
+ return this._id;
1053
+ }
960
1054
  get type() {
961
1055
  return this._type;
962
1056
  }
@@ -982,6 +1076,7 @@ class FiniteRepeat {
982
1076
  return this._max;
983
1077
  }
984
1078
  constructor(name, pattern, repeatAmount, options = {}) {
1079
+ this._id = `finite-repeat-${idIndex$4++}`;
985
1080
  this._type = "finite-repeat";
986
1081
  this._name = name;
987
1082
  this._parent = null;
@@ -998,6 +1093,7 @@ class FiniteRepeat {
998
1093
  }
999
1094
  }
1000
1095
  parse(cursor) {
1096
+ cursor.startParseWith(this);
1001
1097
  const startIndex = cursor.index;
1002
1098
  const nodes = [];
1003
1099
  const modulo = this._hasDivider ? 2 : 1;
@@ -1032,16 +1128,19 @@ class FiniteRepeat {
1032
1128
  const lastIndex = cursor.index;
1033
1129
  cursor.moveTo(startIndex);
1034
1130
  cursor.recordErrorAt(startIndex, lastIndex, this);
1131
+ cursor.endParse();
1035
1132
  return null;
1036
1133
  }
1037
1134
  else if (nodes.length === 0) {
1038
1135
  cursor.resolveError();
1039
1136
  cursor.moveTo(startIndex);
1137
+ cursor.endParse();
1040
1138
  return null;
1041
1139
  }
1042
1140
  const firstIndex = nodes[0].firstIndex;
1043
1141
  const lastIndex = nodes[nodes.length - 1].lastIndex;
1044
1142
  cursor.moveTo(lastIndex);
1143
+ cursor.endParse();
1045
1144
  return new Node(this._type, this.name, firstIndex, lastIndex, nodes);
1046
1145
  }
1047
1146
  test(text) {
@@ -1049,8 +1148,9 @@ class FiniteRepeat {
1049
1148
  const ast = this.parse(cursor);
1050
1149
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1051
1150
  }
1052
- exec(text) {
1151
+ exec(text, record = false) {
1053
1152
  const cursor = new Cursor(text);
1153
+ record && cursor.startRecording();
1054
1154
  const ast = this.parse(cursor);
1055
1155
  return {
1056
1156
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -1067,11 +1167,13 @@ class FiniteRepeat {
1067
1167
  min = Math.max(this._min, 1);
1068
1168
  }
1069
1169
  }
1070
- return new FiniteRepeat(name, this._children[0], this._max, {
1170
+ const clone = new FiniteRepeat(name, this._children[0], this._max, {
1071
1171
  divider: this._hasDivider ? this._children[1] : undefined,
1072
1172
  min,
1073
1173
  trimDivider: this._trimDivider
1074
1174
  });
1175
+ clone._id = this._id;
1176
+ return clone;
1075
1177
  }
1076
1178
  getTokens() {
1077
1179
  return this._children[0].getTokens();
@@ -1119,9 +1221,16 @@ class FiniteRepeat {
1119
1221
  find(predicate) {
1120
1222
  return findPattern(this, predicate);
1121
1223
  }
1224
+ isEqual(pattern) {
1225
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
1226
+ }
1122
1227
  }
1123
1228
 
1229
+ let idIndex$3 = 0;
1124
1230
  class InfiniteRepeat {
1231
+ get id() {
1232
+ return this._id;
1233
+ }
1125
1234
  get type() {
1126
1235
  return this._type;
1127
1236
  }
@@ -1154,6 +1263,7 @@ class InfiniteRepeat {
1154
1263
  children = [pattern.clone(pattern.name, false)];
1155
1264
  }
1156
1265
  this._assignChildrenToParent(children);
1266
+ this._id = `infinite-repeat-${idIndex$3++}`;
1157
1267
  this._type = "infinite-repeat";
1158
1268
  this._name = name;
1159
1269
  this._min = min;
@@ -1175,8 +1285,9 @@ class InfiniteRepeat {
1175
1285
  const ast = this.parse(cursor);
1176
1286
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1177
1287
  }
1178
- exec(text) {
1288
+ exec(text, record = false) {
1179
1289
  const cursor = new Cursor(text);
1290
+ record && cursor.startRecording();
1180
1291
  const ast = this.parse(cursor);
1181
1292
  return {
1182
1293
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -1184,6 +1295,7 @@ class InfiniteRepeat {
1184
1295
  };
1185
1296
  }
1186
1297
  parse(cursor) {
1298
+ cursor.startParseWith(this);
1187
1299
  this._firstIndex = cursor.index;
1188
1300
  this._nodes = [];
1189
1301
  const passed = this._tryToParse(cursor);
@@ -1194,12 +1306,15 @@ class InfiniteRepeat {
1194
1306
  cursor.moveTo(node.lastIndex);
1195
1307
  cursor.recordMatch(this, node);
1196
1308
  }
1309
+ cursor.endParse();
1197
1310
  return node;
1198
1311
  }
1199
1312
  if (this._min > 0) {
1313
+ cursor.endParse();
1200
1314
  return null;
1201
1315
  }
1202
1316
  cursor.resolveError();
1317
+ cursor.endParse();
1203
1318
  return null;
1204
1319
  }
1205
1320
  _meetsMin() {
@@ -1353,15 +1468,24 @@ class InfiniteRepeat {
1353
1468
  min = Math.max(this._min, 1);
1354
1469
  }
1355
1470
  }
1356
- return new InfiniteRepeat(name, this._pattern, {
1471
+ const clone = new InfiniteRepeat(name, this._pattern, {
1357
1472
  divider: this._divider == null ? undefined : this._divider,
1358
1473
  min: min,
1359
1474
  trimDivider: this._trimDivider
1360
1475
  });
1476
+ clone._id = this._id;
1477
+ return clone;
1478
+ }
1479
+ isEqual(pattern) {
1480
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
1361
1481
  }
1362
1482
  }
1363
1483
 
1484
+ let idIndex$2 = 0;
1364
1485
  class Repeat {
1486
+ get id() {
1487
+ return this._id;
1488
+ }
1365
1489
  get type() {
1366
1490
  return this._repeatPattern.type;
1367
1491
  }
@@ -1381,6 +1505,7 @@ class Repeat {
1381
1505
  return this._repeatPattern.isOptional;
1382
1506
  }
1383
1507
  constructor(name, pattern, options = {}) {
1508
+ this._id = `repeat-${idIndex$2++}`;
1384
1509
  this._pattern = pattern;
1385
1510
  this._parent = null;
1386
1511
  this._options = Object.assign(Object.assign({}, options), { min: options.min == null ? 1 : options.min, max: options.max == null ? Infinity : options.max });
@@ -1412,7 +1537,9 @@ class Repeat {
1412
1537
  min = Math.max(this._options.min, 1);
1413
1538
  }
1414
1539
  }
1415
- return new Repeat(name, this._pattern, Object.assign(Object.assign({}, this._options), { min }));
1540
+ const clone = new Repeat(name, this._pattern, Object.assign(Object.assign({}, this._options), { min }));
1541
+ clone._id = this._id;
1542
+ return clone;
1416
1543
  }
1417
1544
  getTokens() {
1418
1545
  return this._repeatPattern.getTokens();
@@ -1447,6 +1574,9 @@ class Repeat {
1447
1574
  find(predicate) {
1448
1575
  return this._repeatPattern.find(predicate);
1449
1576
  }
1577
+ isEqual(pattern) {
1578
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
1579
+ }
1450
1580
  }
1451
1581
 
1452
1582
  const comment = new Regex("comment", "#[^\r\n]+");
@@ -1461,7 +1591,11 @@ function filterOutNull(nodes) {
1461
1591
  return filteredNodes;
1462
1592
  }
1463
1593
 
1594
+ let idIndex$1 = 0;
1464
1595
  class And {
1596
+ get id() {
1597
+ return this._id;
1598
+ }
1465
1599
  get type() {
1466
1600
  return this._type;
1467
1601
  }
@@ -1486,6 +1620,7 @@ class And {
1486
1620
  }
1487
1621
  const children = clonePatterns(sequence);
1488
1622
  this._assignChildrenToParent(children);
1623
+ this._id = `and-${idIndex$1++}`;
1489
1624
  this._type = "and";
1490
1625
  this._name = name;
1491
1626
  this._isOptional = isOptional;
@@ -1504,8 +1639,9 @@ class And {
1504
1639
  const ast = this.parse(cursor);
1505
1640
  return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
1506
1641
  }
1507
- exec(text) {
1642
+ exec(text, record = false) {
1508
1643
  const cursor = new Cursor(text);
1644
+ record && cursor.startRecording();
1509
1645
  const ast = this.parse(cursor);
1510
1646
  return {
1511
1647
  ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
@@ -1513,6 +1649,7 @@ class And {
1513
1649
  };
1514
1650
  }
1515
1651
  parse(cursor) {
1652
+ cursor.startParseWith(this);
1516
1653
  this._firstIndex = cursor.index;
1517
1654
  this._nodes = [];
1518
1655
  const passed = this.tryToParse(cursor);
@@ -1521,11 +1658,13 @@ class And {
1521
1658
  if (node !== null) {
1522
1659
  cursor.recordMatch(this, node);
1523
1660
  }
1661
+ cursor.endParse();
1524
1662
  return node;
1525
1663
  }
1526
1664
  if (this._isOptional) {
1527
1665
  cursor.resolveError();
1528
1666
  }
1667
+ cursor.endParse();
1529
1668
  return null;
1530
1669
  }
1531
1670
  tryToParse(cursor) {
@@ -1684,7 +1823,12 @@ class And {
1684
1823
  return findPattern(this, predicate);
1685
1824
  }
1686
1825
  clone(name = this._name, isOptional = this._isOptional) {
1687
- return new And(name, this._children, isOptional);
1826
+ const clone = new And(name, this._children, isOptional);
1827
+ clone._id = this._id;
1828
+ return clone;
1829
+ }
1830
+ isEqual(pattern) {
1831
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
1688
1832
  }
1689
1833
  }
1690
1834
 
@@ -1701,34 +1845,45 @@ const allSpaces = new Regex("all-spaces", "\\s+", true);
1701
1845
 
1702
1846
  const name$1 = new Regex("name", "[a-zA-Z_-]+[a-zA-Z0-9_-]*");
1703
1847
 
1704
- const optionalNot = new Literal("not", "!", true);
1705
- const optionalIsOptional = new Literal("is-optional", "?", true);
1706
- const patternName$1 = name$1.clone("pattern-name");
1707
- const pattern = new And("pattern", [
1708
- optionalNot,
1709
- patternName$1,
1710
- optionalIsOptional,
1711
- ]);
1712
-
1713
- const divider$1 = new Regex("and-divider", "\\s*[&]\\s*");
1714
- divider$1.setTokens([" & "]);
1715
- const andLiteral = new Repeat("and-literal", pattern, { divider: divider$1, min: 2, trimDivider: true });
1848
+ const regexLiteral = new Regex("regex-literal", "/(\\\\/|[^/\\n\\r])*/");
1716
1849
 
1717
- const divider = new Regex("or-divider", "\\s*[|]\\s*");
1718
- divider.setTokens([" | "]);
1719
- const orLiteral = new Repeat("or-literal", name$1.clone("pattern-name"), { divider, min: 2, trimDivider: true });
1850
+ const patternName$3 = name$1.clone("pattern-name");
1851
+ const anonymousLiterals = new Or("anonymous-literals", [
1852
+ literal,
1853
+ regexLiteral,
1854
+ patternName$3,
1855
+ new Reference("repeat-literal"),
1856
+ ]);
1857
+ const anonymousWrappedLiterals = new Or("anonymous-wrapped-literals", [
1858
+ new Reference("or-literal"),
1859
+ new Reference("and-literal"),
1860
+ new Reference("complex-anonymous-pattern")
1861
+ ]);
1720
1862
 
1721
- const regexLiteral = new Regex("regex-literal", "/(\\\\/|[^/\\n\\r])*/");
1863
+ const inlinePatternOpenParen = new Literal("anonymous-pattern-open-paren", "(");
1864
+ const inlinePatternCloseParen = new Literal("anonymous-pattern-close-paren", ")");
1865
+ const optionalLineSpaces$1 = lineSpaces$1.clone(undefined, true);
1866
+ const complexAnonymousPattern = new And("complex-anonymous-pattern", [
1867
+ inlinePatternOpenParen,
1868
+ optionalLineSpaces$1,
1869
+ anonymousWrappedLiterals,
1870
+ optionalLineSpaces$1,
1871
+ inlinePatternCloseParen,
1872
+ ]);
1873
+ const anonymousPattern = new Or("anonymous-pattern", [
1874
+ anonymousLiterals,
1875
+ complexAnonymousPattern
1876
+ ]);
1722
1877
 
1723
- const patternName = name$1.clone("pattern-name");
1724
1878
  const optionalSpaces$2 = spaces$1.clone("optional-spaces", true);
1725
- const dividerPattern = name$1.clone("divider-pattern");
1726
1879
  const openBracket$1 = new Literal("open-bracket", "{");
1727
1880
  const closeBracket$1 = new Literal("close-bracket", "}");
1728
1881
  const comma = new Literal("comma", ",");
1729
1882
  const integer = new Regex("integer", "([1-9][0-9]*)|0");
1730
1883
  integer.setTokens(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
1731
1884
  const optionalInteger = integer.clone("integer", true);
1885
+ const trimKeyword = new Literal("trim-keyword", "trim", true);
1886
+ const trimFlag = new And("trim-flag", [lineSpaces$1, trimKeyword], true);
1732
1887
  const bounds = new And("bounds", [
1733
1888
  openBracket$1,
1734
1889
  optionalSpaces$2,
@@ -1737,7 +1892,6 @@ const bounds = new And("bounds", [
1737
1892
  comma,
1738
1893
  optionalSpaces$2,
1739
1894
  optionalInteger.clone("max"),
1740
- optionalSpaces$2,
1741
1895
  closeBracket$1
1742
1896
  ]);
1743
1897
  const exactCount = new And("exact-count", [
@@ -1754,41 +1908,67 @@ const quantifier = new Or("quantifier", [
1754
1908
  exactCount,
1755
1909
  bounds
1756
1910
  ]);
1757
- const optional = new Literal("is-optional", "?", true);
1758
- const trimDivider = new Literal("trim-divider", "-t");
1759
- const openParen = new Literal("open-paren", "(");
1760
- const closeParen = new Literal("close-paren", ")");
1911
+ const openParen = new Literal("repeat-open-paren", "(");
1912
+ const closeParen = new Literal("repeat-close-paren", ")");
1761
1913
  const dividerComma = new Regex("divider-comma", "\\s*,\\s*");
1762
1914
  dividerComma.setTokens([", "]);
1915
+ const patternName$2 = name$1.clone("pattern-name");
1916
+ const patterns$3 = new Or("or-patterns", [patternName$2, anonymousPattern]);
1917
+ const dividerPattern = patterns$3.clone("divider-pattern");
1763
1918
  const repeatLiteral = new And("repeat-literal", [
1764
1919
  openParen,
1765
1920
  optionalSpaces$2,
1766
- patternName,
1767
- optional,
1768
- new And("optional-divider-section", [dividerComma, dividerPattern], true),
1921
+ patterns$3,
1922
+ new And("optional-divider-section", [dividerComma, dividerPattern, trimFlag], true),
1769
1923
  optionalSpaces$2,
1770
1924
  closeParen,
1771
- new And("quantifier-section", [optionalSpaces$2, quantifier]),
1772
- new And("optional-trim-divider-section", [spaces$1, trimDivider], true)
1925
+ new And("quantifier-section", [quantifier]),
1773
1926
  ]);
1774
1927
 
1775
- const optionalSpaces$1 = spaces$1.clone("optional-spaces", true);
1776
- const assignOperator = new Literal("assign-operator", "=");
1777
- const statements = new Or("statements", [
1928
+ const optionalNot = new Literal("not", "!", true);
1929
+ const optionalIsOptional$1 = new Literal("is-optional", "?", true);
1930
+ const patternName$1 = name$1.clone("pattern-name");
1931
+ const patterns$2 = new Or("and-patterns", [patternName$1, anonymousPattern]);
1932
+ const pattern$1 = new And("and-child-pattern", [
1933
+ optionalNot,
1934
+ patterns$2,
1935
+ optionalIsOptional$1,
1936
+ ]);
1937
+ const divider$1 = new Regex("and-divider", "\\s*[+]\\s*");
1938
+ divider$1.setTokens([" + "]);
1939
+ const andLiteral = new Repeat("and-literal", pattern$1, { divider: divider$1, min: 2, trimDivider: true });
1940
+
1941
+ const patternName = name$1.clone("pattern-name");
1942
+ const patterns$1 = new Or("or-patterns", [patternName, anonymousPattern]);
1943
+ const defaultDivider = new Regex("default-divider", "\\s*[|]\\s*");
1944
+ const greedyDivider = new Regex("greedy-divider", "\\s*[<][|][>]\\s*");
1945
+ const divider = new Or("or-divider", [defaultDivider, greedyDivider]);
1946
+ defaultDivider.setTokens([" | "]);
1947
+ greedyDivider.setTokens([" <|> "]);
1948
+ const orLiteral = new Repeat("or-literal", patterns$1, { divider, min: 2, trimDivider: true });
1949
+
1950
+ const aliasLiteral = name$1.clone("alias-literal");
1951
+ const optionalIsOptional = new Literal("is-optional", "?", true);
1952
+ const configurableAnonymousPattern = new And("configurable-anonymous-pattern", [anonymousPattern, optionalIsOptional]);
1953
+ const pattern = new Or("pattern", [
1778
1954
  literal,
1779
1955
  regexLiteral,
1956
+ repeatLiteral,
1957
+ aliasLiteral,
1780
1958
  orLiteral,
1781
1959
  andLiteral,
1782
- repeatLiteral,
1783
- name$1.clone("alias-literal"),
1784
- ]);
1960
+ configurableAnonymousPattern,
1961
+ ], false, true);
1962
+
1963
+ const optionalSpaces$1 = spaces$1.clone("optional-spaces", true);
1964
+ const assignOperator = new Literal("assign-operator", "=");
1785
1965
  const assignStatement = new And("assign-statement", [
1786
1966
  optionalSpaces$1,
1787
1967
  name$1,
1788
1968
  optionalSpaces$1,
1789
1969
  assignOperator,
1790
1970
  optionalSpaces$1,
1791
- statements
1971
+ pattern
1792
1972
  ]);
1793
1973
  const statement = new Or("statement", [assignStatement, name$1.clone("export-name")]);
1794
1974
 
@@ -1883,7 +2063,11 @@ const grammar = new And("grammar", [
1883
2063
  allSpaces
1884
2064
  ]);
1885
2065
 
2066
+ let idIndex = 0;
1886
2067
  class Not {
2068
+ get id() {
2069
+ return this._id;
2070
+ }
1887
2071
  get type() {
1888
2072
  return this._type;
1889
2073
  }
@@ -1903,6 +2087,7 @@ class Not {
1903
2087
  return false;
1904
2088
  }
1905
2089
  constructor(name, pattern) {
2090
+ this._id = `not-${idIndex++}`;
1906
2091
  this._type = "not";
1907
2092
  this._name = name;
1908
2093
  this._parent = null;
@@ -1914,15 +2099,17 @@ class Not {
1914
2099
  this.parse(cursor);
1915
2100
  return !cursor.hasError;
1916
2101
  }
1917
- exec(text) {
2102
+ exec(text, record = false) {
1918
2103
  const cursor = new Cursor(text);
2104
+ record && cursor.startRecording();
1919
2105
  const ast = this.parse(cursor);
1920
2106
  return {
1921
- ast,
2107
+ ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
1922
2108
  cursor
1923
2109
  };
1924
2110
  }
1925
2111
  parse(cursor) {
2112
+ cursor.startParseWith(this);
1926
2113
  const firstIndex = cursor.index;
1927
2114
  this._children[0].parse(cursor);
1928
2115
  if (cursor.hasError) {
@@ -1934,10 +2121,12 @@ class Not {
1934
2121
  cursor.resolveError();
1935
2122
  cursor.recordErrorAt(firstIndex, firstIndex, this);
1936
2123
  }
2124
+ cursor.endParse();
1937
2125
  return null;
1938
2126
  }
1939
2127
  clone(name = this._name) {
1940
2128
  const not = new Not(name, this._children[0]);
2129
+ not._id = this._id;
1941
2130
  return not;
1942
2131
  }
1943
2132
  getTokens() {
@@ -1979,6 +2168,9 @@ class Not {
1979
2168
  find(predicate) {
1980
2169
  return predicate(this._children[0]) ? this._children[0] : null;
1981
2170
  }
2171
+ isEqual(pattern) {
2172
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
2173
+ }
1982
2174
  }
1983
2175
 
1984
2176
  const defaultOptions = { greedyPatternNames: [], customTokens: {} };
@@ -2183,6 +2375,16 @@ function getFurthestOptions(options) {
2183
2375
  return furthestOptions;
2184
2376
  }
2185
2377
 
2378
+ let anonymousIndexId = 0;
2379
+ const patternNodes = {
2380
+ "literal": true,
2381
+ "regex-literal": true,
2382
+ "or-literal": true,
2383
+ "and-literal": true,
2384
+ "repeat-literal": true,
2385
+ "alias-literal": true,
2386
+ "configurable-anonymous-pattern": true
2387
+ };
2186
2388
  class ParseContext {
2187
2389
  constructor(params) {
2188
2390
  this.patternsByName = new Map();
@@ -2227,7 +2429,7 @@ class Grammar {
2227
2429
  const ast = this._tryToParse(expression);
2228
2430
  yield this._resolveImports(ast);
2229
2431
  this._buildPatterns(ast);
2230
- return this._parseContext.patternsByName;
2432
+ return Object.fromEntries(this._parseContext.patternsByName);
2231
2433
  });
2232
2434
  }
2233
2435
  parseString(expression) {
@@ -2237,7 +2439,7 @@ class Grammar {
2237
2439
  throw new Error("Cannot use imports on parseString, use parse instead.");
2238
2440
  }
2239
2441
  this._buildPatterns(ast);
2240
- return this._parseContext.patternsByName;
2442
+ return Object.fromEntries(this._parseContext.patternsByName);
2241
2443
  }
2242
2444
  _tryToParse(expression) {
2243
2445
  const { ast, cursor, options, isComplete } = this._autoComplete.suggestFor(expression);
@@ -2267,41 +2469,207 @@ class Grammar {
2267
2469
  if (body == null) {
2268
2470
  return;
2269
2471
  }
2270
- body.findAll(n => n.name === "assign-statement" || n.name === "export-name").forEach((n) => {
2271
- const typeNode = n.find(n => n.name.includes("literal"));
2272
- const type = n.name === "export-name" ? "export-name" : (typeNode === null || typeNode === void 0 ? void 0 : typeNode.name) || "unknown";
2273
- switch (type) {
2472
+ body.findAll(n => n.name === "assign-statement").forEach((n) => {
2473
+ const patternNode = n.children.find(n => patternNodes[n.name] != null);
2474
+ if (patternNode == null) {
2475
+ return;
2476
+ }
2477
+ switch (patternNode.name) {
2274
2478
  case "literal": {
2275
- this._buildLiteral(n);
2479
+ this._saveLiteral(n);
2276
2480
  break;
2277
2481
  }
2278
2482
  case "regex-literal": {
2279
- this._buildRegex(n);
2483
+ this._saveRegex(n);
2280
2484
  break;
2281
2485
  }
2282
2486
  case "or-literal": {
2283
- this._buildOr(n);
2487
+ this._saveOr(n);
2284
2488
  break;
2285
2489
  }
2286
2490
  case "and-literal": {
2287
- this._buildAnd(n);
2491
+ this._saveAnd(n);
2288
2492
  break;
2289
2493
  }
2290
2494
  case "repeat-literal": {
2291
- this._buildRepeat(n);
2495
+ this._saveRepeat(n);
2292
2496
  break;
2293
2497
  }
2294
2498
  case "alias-literal": {
2295
- this._buildAlias(n);
2499
+ this._saveAlias(n);
2296
2500
  break;
2297
2501
  }
2298
- case "export-name": {
2299
- const pattern = this._getPattern(n.value);
2300
- this._parseContext.patternsByName.set(n.value, pattern);
2502
+ case "configurable-anonymous-pattern": {
2503
+ this._saveConfigurableAnonymous(n);
2301
2504
  break;
2302
2505
  }
2303
2506
  }
2304
2507
  });
2508
+ body.findAll(n => n.name === "export-name").forEach((n) => {
2509
+ const pattern = this._getPattern(n.value).clone();
2510
+ this._parseContext.patternsByName.set(n.value, pattern);
2511
+ });
2512
+ }
2513
+ _saveLiteral(statementNode) {
2514
+ const nameNode = statementNode.find(n => n.name === "name");
2515
+ const literalNode = statementNode.find(n => n.name === "literal");
2516
+ const name = nameNode.value;
2517
+ const literal = this._buildLiteral(name, literalNode);
2518
+ this._parseContext.patternsByName.set(name, literal);
2519
+ }
2520
+ _buildLiteral(name, node) {
2521
+ return new Literal(name, this._resolveStringValue(node.value));
2522
+ }
2523
+ _resolveStringValue(value) {
2524
+ return value.replace(/\\n/g, '\n')
2525
+ .replace(/\\r/g, '\r')
2526
+ .replace(/\\t/g, '\t')
2527
+ .replace(/\\b/g, '\b')
2528
+ .replace(/\\f/g, '\f')
2529
+ .replace(/\\v/g, '\v')
2530
+ .replace(/\\0/g, '\0')
2531
+ .replace(/\\x([0-9A-Fa-f]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
2532
+ .replace(/\\u([0-9A-Fa-f]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
2533
+ .replace(/\\(.)/g, '$1').slice(1, -1);
2534
+ }
2535
+ _saveRegex(statementNode) {
2536
+ const nameNode = statementNode.find(n => n.name === "name");
2537
+ const regexNode = statementNode.find(n => n.name === "regex-literal");
2538
+ const name = nameNode.value;
2539
+ const regex = this._buildRegex(name, regexNode);
2540
+ this._parseContext.patternsByName.set(name, regex);
2541
+ }
2542
+ _buildRegex(name, node) {
2543
+ const value = node.value.slice(1, node.value.length - 1);
2544
+ return new Regex(name, value);
2545
+ }
2546
+ _saveOr(statementNode) {
2547
+ const nameNode = statementNode.find(n => n.name === "name");
2548
+ const name = nameNode.value;
2549
+ const orNode = statementNode.find(n => n.name === "or-literal");
2550
+ const or = this._buildOr(name, orNode);
2551
+ this._parseContext.patternsByName.set(name, or);
2552
+ }
2553
+ _buildOr(name, node) {
2554
+ const patternNodes = node.children.filter(n => n.name !== "default-divider" && n.name !== "greedy-divider");
2555
+ const isGreedy = node.find(n => n.name === "greedy-divider") != null;
2556
+ const patterns = patternNodes.map(n => this._buildPattern(n));
2557
+ const or = new Or(name, patterns, false, isGreedy);
2558
+ return or;
2559
+ }
2560
+ _buildPattern(node) {
2561
+ const type = node.name;
2562
+ const name = `anonymous-pattern-${anonymousIndexId++}`;
2563
+ switch (type) {
2564
+ case "pattern-name": {
2565
+ return this._getPattern(node.value).clone();
2566
+ }
2567
+ case "literal": {
2568
+ return this._buildLiteral(node.value.slice(1, -1), node);
2569
+ }
2570
+ case "regex-literal": {
2571
+ return this._buildRegex(node.value.slice(1, -1), node);
2572
+ }
2573
+ case "repeat-literal": {
2574
+ return this._buildRepeat(name, node);
2575
+ }
2576
+ case "or-literal": {
2577
+ return this._buildOr(name, node);
2578
+ }
2579
+ case "and-literal": {
2580
+ return this._buildAnd(name, node);
2581
+ }
2582
+ case "complex-anonymous-pattern": {
2583
+ return this._buildComplexAnonymousPattern(node);
2584
+ }
2585
+ }
2586
+ throw new Error(`Couldn't build node: ${node.name}.`);
2587
+ }
2588
+ _saveAnd(statementNode) {
2589
+ const nameNode = statementNode.find(n => n.name === "name");
2590
+ const name = nameNode.value;
2591
+ const andNode = statementNode.find(n => n.name === "and-literal");
2592
+ const and = this._buildAnd(name, andNode);
2593
+ this._parseContext.patternsByName.set(name, and);
2594
+ }
2595
+ _buildAnd(name, node) {
2596
+ const patternNodes = node.children.filter(n => n.name !== "and-divider");
2597
+ const patterns = patternNodes.map(n => {
2598
+ const patternNode = n.children[0].name === "not" ? n.children[1] : n.children[0];
2599
+ const isNot = n.find(n => n.name === "not") != null;
2600
+ const isOptional = n.find(n => n.name === "is-optional");
2601
+ const pattern = this._buildPattern(patternNode).clone(undefined, isOptional == null ? undefined : true);
2602
+ if (isNot) {
2603
+ return new Not(`not-${pattern.name}`, pattern);
2604
+ }
2605
+ return pattern;
2606
+ });
2607
+ return new And(name, patterns);
2608
+ }
2609
+ _saveRepeat(statementNode) {
2610
+ const nameNode = statementNode.find(n => n.name === "name");
2611
+ const name = nameNode.value;
2612
+ const repeatNode = statementNode.find(n => n.name === "repeat-literal");
2613
+ const repeat = this._buildRepeat(name, repeatNode);
2614
+ this._parseContext.patternsByName.set(name, repeat);
2615
+ }
2616
+ _buildRepeat(name, repeatNode) {
2617
+ const bounds = repeatNode.find(n => n.name === "bounds");
2618
+ const exactCount = repeatNode.find(n => n.name === "exact-count");
2619
+ const quantifier = repeatNode.find(n => n.name === "quantifier-shorthand");
2620
+ const trimDivider = repeatNode.find(n => n.name === "trim-flag") != null;
2621
+ const patterNode = repeatNode.children[1].type === "optional-spaces" ? repeatNode.children[2] : repeatNode.children[1];
2622
+ const pattern = this._buildPattern(patterNode);
2623
+ const dividerSectionNode = repeatNode.find(n => n.name === "optional-divider-section");
2624
+ const options = {
2625
+ min: 1,
2626
+ max: Infinity
2627
+ };
2628
+ if (trimDivider) {
2629
+ options.trimDivider = trimDivider;
2630
+ }
2631
+ if (dividerSectionNode != null) {
2632
+ const dividerNode = dividerSectionNode.children[1];
2633
+ options.divider = this._buildPattern(dividerNode);
2634
+ }
2635
+ if (bounds != null) {
2636
+ const minNode = bounds.find(p => p.name === "min");
2637
+ const maxNode = bounds.find(p => p.name === "max");
2638
+ const min = minNode == null ? 0 : Number(minNode.value);
2639
+ const max = maxNode == null ? Infinity : Number(maxNode.value);
2640
+ options.min = min;
2641
+ options.max = max;
2642
+ }
2643
+ else if (exactCount != null) {
2644
+ const integerNode = exactCount.find(p => p.name === "integer");
2645
+ const integer = Number(integerNode.value);
2646
+ options.min = integer;
2647
+ options.max = integer;
2648
+ }
2649
+ else if (quantifier != null) {
2650
+ const type = quantifier.value;
2651
+ if (type === "+") {
2652
+ options.min = 1;
2653
+ options.max = Infinity;
2654
+ }
2655
+ else {
2656
+ options.min = 0;
2657
+ options.max = Infinity;
2658
+ }
2659
+ }
2660
+ return new Repeat(name, pattern.clone(pattern.name), options);
2661
+ }
2662
+ _saveConfigurableAnonymous(node) {
2663
+ const nameNode = node.find(n => n.name === "name");
2664
+ const name = nameNode.value;
2665
+ const anonymousNode = node.find(n => n.name === "complex-anonymous-pattern");
2666
+ const isOptional = node.children[1] != null;
2667
+ const anonymous = this._buildPattern(anonymousNode).clone(name, isOptional);
2668
+ this._parseContext.patternsByName.set(name, anonymous);
2669
+ }
2670
+ _buildComplexAnonymousPattern(node) {
2671
+ const wrappedNode = node.children[1].name === "line-spaces" ? node.children[2] : node.children[1];
2672
+ return this._buildPattern(wrappedNode);
2305
2673
  }
2306
2674
  _resolveImports(ast) {
2307
2675
  return __awaiter(this, void 0, void 0, function* () {
@@ -2330,7 +2698,7 @@ class Grammar {
2330
2698
  if (parseContext.importedPatternsByName.has(importName)) {
2331
2699
  throw new Error(`'${importName}' was already used within another import.`);
2332
2700
  }
2333
- const pattern = patterns.get(importName);
2701
+ const pattern = patterns[importName];
2334
2702
  if (pattern == null) {
2335
2703
  throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
2336
2704
  }
@@ -2344,7 +2712,7 @@ class Grammar {
2344
2712
  if (parseContext.importedPatternsByName.has(alias)) {
2345
2713
  throw new Error(`'${alias}' was already used within another import.`);
2346
2714
  }
2347
- const pattern = patterns.get(importName);
2715
+ const pattern = patterns[importName];
2348
2716
  if (pattern == null) {
2349
2717
  throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
2350
2718
  }
@@ -2375,48 +2743,11 @@ class Grammar {
2375
2743
  resolveImport: this._resolveImport
2376
2744
  });
2377
2745
  const patterns = grammar.parseString(expression);
2378
- params = Array.from(patterns.values());
2746
+ params = Array.from(Object.values(patterns));
2379
2747
  }
2380
2748
  }
2381
2749
  return params;
2382
2750
  }
2383
- _buildLiteral(statementNode) {
2384
- const nameNode = statementNode.find(n => n.name === "name");
2385
- const literalNode = statementNode.find(n => n.name === "literal");
2386
- const name = nameNode.value;
2387
- const value = this._resolveStringValue(literalNode.value.slice(1, -1));
2388
- const literal = new Literal(name, value);
2389
- this._parseContext.patternsByName.set(name, literal);
2390
- }
2391
- _resolveStringValue(value) {
2392
- return value.replace(/\\n/g, '\n')
2393
- .replace(/\\r/g, '\r')
2394
- .replace(/\\t/g, '\t')
2395
- .replace(/\\b/g, '\b')
2396
- .replace(/\\f/g, '\f')
2397
- .replace(/\\v/g, '\v')
2398
- .replace(/\\0/g, '\0')
2399
- .replace(/\\x([0-9A-Fa-f]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
2400
- .replace(/\\u([0-9A-Fa-f]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
2401
- .replace(/\\(.)/g, '$1');
2402
- }
2403
- _buildRegex(statementNode) {
2404
- const nameNode = statementNode.find(n => n.name === "name");
2405
- const regexNode = statementNode.find(n => n.name === "regex-literal");
2406
- const value = regexNode.value.slice(1, regexNode.value.length - 1);
2407
- const name = nameNode.value;
2408
- const regex = new Regex(name, value);
2409
- this._parseContext.patternsByName.set(name, regex);
2410
- }
2411
- _buildOr(statementNode) {
2412
- const nameNode = statementNode.find(n => n.name === "name");
2413
- const orNode = statementNode.find(n => n.name === "or-literal");
2414
- const patternNodes = orNode.children.filter(n => n.name === "pattern-name");
2415
- const name = nameNode.value;
2416
- const patterns = patternNodes.map(n => this._getPattern(n.value));
2417
- const or = new Or(name, patterns, false, true);
2418
- this._parseContext.patternsByName.set(name, or);
2419
- }
2420
2751
  _getPattern(name) {
2421
2752
  let pattern = this._parseContext.patternsByName.get(name);
2422
2753
  if (pattern == null) {
@@ -2430,82 +2761,12 @@ class Grammar {
2430
2761
  }
2431
2762
  return pattern;
2432
2763
  }
2433
- _buildAnd(statementNode) {
2434
- const nameNode = statementNode.find(n => n.name === "name");
2435
- const andNode = statementNode.find(n => n.name === "and-literal");
2436
- const patternNodes = andNode.children.filter(n => n.name === "pattern");
2437
- const name = nameNode.value;
2438
- const patterns = patternNodes.map(n => {
2439
- const nameNode = n.find(n => n.name === "pattern-name");
2440
- const isNot = n.find(n => n.name === "not") != null;
2441
- const isOptional = n.find(n => n.name === "is-optional") != null;
2442
- const name = nameNode.value;
2443
- const pattern = this._getPattern(name);
2444
- if (isNot) {
2445
- return new Not(`not-${name}`, pattern.clone(name, isOptional));
2446
- }
2447
- return pattern.clone(name, isOptional);
2448
- });
2449
- const and = new And(name, patterns);
2450
- this._parseContext.patternsByName.set(name, and);
2451
- }
2452
- _buildRepeat(statementNode) {
2453
- const nameNode = statementNode.find(n => n.name === "name");
2454
- const repeatNode = statementNode.find(n => n.name === "repeat-literal");
2455
- const patternNameNode = statementNode.find(n => n.name === "pattern-name");
2456
- const dividerNode = repeatNode.find(n => n.name === "divider-pattern");
2457
- const bounds = repeatNode.find(n => n.name === "bounds");
2458
- const exactCount = repeatNode.find(n => n.name === "exact-count");
2459
- const quantifier = repeatNode.find(n => n.name === "quantifier-shorthand");
2460
- const isPatternOptional = repeatNode.find(n => n.name === "is-optional") != null;
2461
- const trimDivider = repeatNode.find(n => n.name === "trim-divider") != null;
2462
- const name = nameNode.value;
2463
- const pattern = this._getPattern(patternNameNode.value);
2464
- const options = {
2465
- min: 1,
2466
- max: Infinity
2467
- };
2468
- if (trimDivider) {
2469
- options.trimDivider = trimDivider;
2470
- }
2471
- if (dividerNode != null) {
2472
- options.divider = this._getPattern(dividerNode.value);
2473
- }
2474
- if (bounds != null) {
2475
- const minNode = bounds.find(p => p.name === "min");
2476
- const maxNode = bounds.find(p => p.name === "max");
2477
- const min = minNode == null ? 0 : Number(minNode.value);
2478
- const max = maxNode == null ? Infinity : Number(maxNode.value);
2479
- options.min = min;
2480
- options.max = max;
2481
- }
2482
- else if (exactCount != null) {
2483
- const integerNode = exactCount.find(p => p.name === "integer");
2484
- const integer = Number(integerNode.value);
2485
- options.min = integer;
2486
- options.max = integer;
2487
- }
2488
- else if (quantifier != null) {
2489
- const type = quantifier.value;
2490
- if (type === "+") {
2491
- options.min = 1;
2492
- options.max = Infinity;
2493
- }
2494
- else {
2495
- options.min = 0;
2496
- options.max = Infinity;
2497
- }
2498
- }
2499
- const repeat = new Repeat(name, pattern.clone(pattern.name, isPatternOptional), options);
2500
- this._parseContext.patternsByName.set(name, repeat);
2501
- }
2502
- _buildAlias(statementNode) {
2764
+ _saveAlias(statementNode) {
2503
2765
  const nameNode = statementNode.find(n => n.name === "name");
2504
2766
  const aliasNode = statementNode.find(n => n.name === "alias-literal");
2505
2767
  const aliasName = aliasNode.value;
2506
2768
  const name = nameNode.value;
2507
- const pattern = this._getPattern(aliasName);
2508
- const alias = pattern.clone(name);
2769
+ const alias = this._getPattern(aliasName).clone(name);
2509
2770
  this._parseContext.patternsByName.set(name, alias);
2510
2771
  }
2511
2772
  static parse(expression, options) {
@@ -2522,6 +2783,30 @@ class Grammar {
2522
2783
  }
2523
2784
  }
2524
2785
 
2786
+ function arePatternsEqual(a, b) {
2787
+ if (a === b) {
2788
+ return true;
2789
+ }
2790
+ else if (a == null || b == null) {
2791
+ return false;
2792
+ }
2793
+ return a.isEqual(b);
2794
+ }
2795
+
2796
+ const kebabRegex = /-([a-z])/g; // Define the regex once
2797
+ function kebabToCamelCase(str) {
2798
+ return str.replace(kebabRegex, (_, char) => char.toUpperCase());
2799
+ }
2800
+ function patterns(strings, ...values) {
2801
+ const combinedString = strings.reduce((result, str, i) => result + str + (values[i] || ''), '');
2802
+ const result = {};
2803
+ const patterns = Grammar.parseString(combinedString);
2804
+ Object.keys(patterns).forEach(k => {
2805
+ result[kebabToCamelCase(k)] = patterns[k];
2806
+ });
2807
+ return result;
2808
+ }
2809
+
2525
2810
  exports.And = And;
2526
2811
  exports.AutoComplete = AutoComplete;
2527
2812
  exports.Cursor = Cursor;
@@ -2535,5 +2820,7 @@ exports.ParseError = ParseError;
2535
2820
  exports.Reference = Reference;
2536
2821
  exports.Regex = Regex;
2537
2822
  exports.Repeat = Repeat;
2823
+ exports.arePatternsEqual = arePatternsEqual;
2538
2824
  exports.grammar = grammar;
2825
+ exports.patterns = patterns;
2539
2826
  //# sourceMappingURL=index.js.map