clarity-pattern-parser 8.4.14 → 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 +472 -185
  10. package/dist/index.browser.js.map +1 -1
  11. package/dist/index.d.ts +3 -1
  12. package/dist/index.esm.js +471 -186
  13. package/dist/index.esm.js.map +1 -1
  14. package/dist/index.js +472 -185
  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 +126 -72
  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 -3
  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
@@ -1,11 +1,13 @@
1
1
  import { Node } from "../ast/Node";
2
- import { And } from "./And";
2
+ import { Sequence } from "./Sequence";
3
3
  import { Cursor } from "./Cursor";
4
4
  import { findPattern } from "./findPattern";
5
5
  import { Literal } from "./Literal";
6
6
  import { Pattern } from "./Pattern";
7
7
  import { Regex } from "./Regex";
8
8
  import { InfiniteRepeat } from "./InfiniteRepeat";
9
+ import { arePatternsEqual } from "./arePatternsEqual";
10
+ import { Optional } from "./Optional";
9
11
 
10
12
  describe("InfiniteRepeat", () => {
11
13
  test("Successful Parse", () => {
@@ -19,8 +21,8 @@ describe("InfiniteRepeat", () => {
19
21
  new Node("regex", "digit", 2, 2, [], "7"),
20
22
  ]);
21
23
 
22
- expect(result).toEqual(expected)
23
- expect(cursor.hasError).toBeFalsy()
24
+ expect(result).toEqual(expected);
25
+ expect(cursor.hasError).toBeFalsy();
24
26
  });
25
27
 
26
28
  test("Bounds", () => {
@@ -51,8 +53,8 @@ describe("InfiniteRepeat", () => {
51
53
  const cursor = new Cursor("John");
52
54
  const result = integer.parse(cursor);
53
55
 
54
- expect(result).toBeNull()
55
- expect(cursor.hasError).toBeTruthy()
56
+ expect(result).toBeNull();
57
+ expect(cursor.hasError).toBeTruthy();
56
58
  });
57
59
 
58
60
  test("Successful Parse With Divider", () => {
@@ -69,8 +71,8 @@ describe("InfiniteRepeat", () => {
69
71
  new Node("regex", "digit", 4, 4, [], "7"),
70
72
  ]);
71
73
 
72
- expect(result).toEqual(expected)
73
- expect(cursor.hasError).toBeFalsy()
74
+ expect(result).toEqual(expected);
75
+ expect(cursor.hasError).toBeFalsy();
74
76
  });
75
77
 
76
78
  test("Successful Parse Text Ends With Divider", () => {
@@ -87,8 +89,8 @@ describe("InfiniteRepeat", () => {
87
89
  new Node("regex", "digit", 4, 4, [], "7"),
88
90
  ]);
89
91
 
90
- expect(result).toEqual(expected)
91
- expect(cursor.hasError).toBeFalsy()
92
+ expect(result).toEqual(expected);
93
+ expect(cursor.hasError).toBeFalsy();
92
94
  });
93
95
 
94
96
  test("Successful Parse Trailing Comma", () => {
@@ -105,18 +107,18 @@ describe("InfiniteRepeat", () => {
105
107
  new Node("regex", "digit", 4, 4, [], "7"),
106
108
  ]);
107
109
 
108
- expect(result).toEqual(expected)
109
- expect(cursor.hasError).toBeFalsy()
110
+ expect(result).toEqual(expected);
111
+ expect(cursor.hasError).toBeFalsy();
110
112
  });
111
113
 
112
114
  test("Failed (Optional)", () => {
113
- const digit = new Regex("digit", "\\d");
115
+ const digit = new Optional("optional-digit", new Regex("digit", "\\d"));
114
116
  const integer = new InfiniteRepeat("number", digit, { min: 0 });
115
117
  const cursor = new Cursor("John");
116
118
  const result = integer.parse(cursor);
117
119
 
118
- expect(result).toBeNull()
119
- expect(cursor.hasError).toBeFalsy()
120
+ expect(result).toBeNull();
121
+ expect(cursor.hasError).toBeFalsy();
120
122
  });
121
123
 
122
124
  test("Get Tokens", () => {
@@ -125,7 +127,7 @@ describe("InfiniteRepeat", () => {
125
127
  const tokens = manyA.getTokens();
126
128
  const expected = ["A"];
127
129
 
128
- expect(tokens).toEqual(expected)
130
+ expect(tokens).toEqual(expected);
129
131
  });
130
132
 
131
133
  test("Get Tokens After With Bogus Pattern", () => {
@@ -134,7 +136,7 @@ describe("InfiniteRepeat", () => {
134
136
  const tokens = manyA.getTokensAfter(new Literal("bogus", "bogus"));
135
137
  const expected: string[] = [];
136
138
 
137
- expect(tokens).toEqual(expected)
139
+ expect(tokens).toEqual(expected);
138
140
  });
139
141
 
140
142
  test("Get Tokens After With Divider", () => {
@@ -142,31 +144,31 @@ describe("InfiniteRepeat", () => {
142
144
  const b = new Literal("b", "B");
143
145
  const divider = new Literal("divider", ",");
144
146
  const manyA = new InfiniteRepeat("many-a", a, { divider });
145
- const parent = new And("parent", [manyA, b]);
147
+ const parent = new Sequence("parent", [manyA, b]);
146
148
 
147
- const clonedManyA = findPattern(parent, p => p.name == "many-a");
149
+ const clonedManyA = findPattern(parent, p => p.name === "many-a");
148
150
  let tokens = clonedManyA?.getTokensAfter(clonedManyA.children[0]);
149
151
  let expected = [",", "B"];
150
152
 
151
- expect(tokens).toEqual(expected)
153
+ expect(tokens).toEqual(expected);
152
154
 
153
155
  tokens = clonedManyA?.getTokensAfter(clonedManyA.children[1]);
154
156
  expected = ["A"];
155
157
 
156
- expect(tokens).toEqual(expected)
158
+ expect(tokens).toEqual(expected);
157
159
  });
158
160
 
159
161
  test("Get Tokens After Without Divider", () => {
160
162
  const a = new Literal("a", "A");
161
163
  const b = new Literal("b", "B");
162
164
  const manyA = new InfiniteRepeat("many-a", a);
163
- const parent = new And("parent", [manyA, b]);
165
+ const parent = new Sequence("parent", [manyA, b]);
164
166
 
165
- const clonedManyA = findPattern(parent, p => p.name == "many-a");
167
+ const clonedManyA = findPattern(parent, p => p.name === "many-a");
166
168
  const tokens = clonedManyA?.getTokensAfter(clonedManyA.children[0]);
167
169
  const expected = ["A", "B"];
168
170
 
169
- expect(tokens).toEqual(expected)
171
+ expect(tokens).toEqual(expected);
170
172
  });
171
173
 
172
174
  test("Properties", () => {
@@ -175,7 +177,6 @@ describe("InfiniteRepeat", () => {
175
177
  expect(integer.type).toBe("infinite-repeat");
176
178
  expect(integer.name).toBe("integer");
177
179
  expect(integer.min).toBe(1);
178
- expect(integer.isOptional).toBeFalsy()
179
180
  expect(integer.parent).toBeNull();
180
181
  expect(integer.children[0].name).toBe("digit");
181
182
  });
@@ -183,28 +184,28 @@ describe("InfiniteRepeat", () => {
183
184
  test("Exec", () => {
184
185
  const integer = new InfiniteRepeat("integer", new Regex("digit", "\\d"));
185
186
  const { ast: result } = integer.exec("B");
186
- expect(result).toBeNull()
187
+ expect(result).toBeNull();
187
188
  });
188
189
 
189
190
  test("Test With Match", () => {
190
191
  const integer = new InfiniteRepeat("integer", new Regex("digit", "\\d"));
191
192
  const result = integer.test("1");
192
- expect(result).toBeTruthy()
193
+ expect(result).toBeTruthy();
193
194
  });
194
195
 
195
196
  test("Test With No Match", () => {
196
197
  const integer = new InfiniteRepeat("integer", new Regex("digit", "\\d"));
197
198
  const result = integer.test("b");
198
- expect(result).toBeFalsy()
199
+ expect(result).toBeFalsy();
199
200
  });
200
201
 
201
202
  test("Get Next Tokens", () => {
202
203
  const integer = new InfiniteRepeat("integer", new Regex("digit", "\\d"));
203
- const parent = new And("parent", [integer, new Literal("pow", "!")]);
204
+ const parent = new Sequence("parent", [integer, new Literal("pow", "!")]);
204
205
  const integerClone = parent.find(p => p.name === "integer") as Pattern;
205
206
  const tokens = integerClone.getNextTokens();
206
207
 
207
- expect(tokens).toEqual(["!"])
208
+ expect(tokens).toEqual(["!"]);
208
209
  });
209
210
 
210
211
  test("Get Next Tokens With Null Parents", () => {
@@ -227,12 +228,12 @@ describe("InfiniteRepeat", () => {
227
228
  const patterns = manyA.getPatterns();
228
229
  const expected = [manyA.find(p => p.name === "a")];
229
230
 
230
- expect(patterns).toEqual(expected)
231
+ expect(patterns).toEqual(expected);
231
232
  });
232
233
 
233
234
  test("Get Next Patterns", () => {
234
235
  const integer = new InfiniteRepeat("integer", new Regex("digit", "\\d"));
235
- const parent = new And("parent", [integer, new Literal("pow", "!")]);
236
+ const parent = new Sequence("parent", [integer, new Literal("pow", "!")]);
236
237
  const integerClone = parent.find(p => p.name === "integer") as Pattern;
237
238
  const powClone = parent.find(p => p.name === "pow") as Pattern;
238
239
  const patterns = integerClone.getNextPatterns();
@@ -249,26 +250,11 @@ describe("InfiniteRepeat", () => {
249
250
  });
250
251
 
251
252
  test("Clone With Custom Overrides", () => {
252
- const numbers = new InfiniteRepeat("numbers", new Regex("number", "\\d"), { min: 0 });
253
+ const numbers = new InfiniteRepeat("numbers", new Regex("number", "\\d"), { min: 3, divider: new Literal("divider", "divider"), trimDivider: true });
253
254
  let clone = numbers.clone();
254
- let expected = new InfiniteRepeat("numbers", new Regex("number", "\\d"), { min: 0 });
255
-
256
- expect(clone).toEqual(expected);
257
-
258
- clone = numbers.clone("cloned-numbers");
259
- expected = new InfiniteRepeat("cloned-numbers", new Regex("number", "\\d"), { min: 0 });
260
-
261
- expect(clone).toEqual(expected);
262
-
263
- clone = numbers.clone("cloned-numbers", true);
264
- expected = new InfiniteRepeat("cloned-numbers", new Regex("number", "\\d"), { min: 0 });
265
-
266
- expect(clone).toEqual(expected);
267
-
268
- clone = numbers.clone("cloned-numbers", false);
269
- expected = new InfiniteRepeat("cloned-numbers", new Regex("number", "\\d"), { min: 1 });
255
+ let expected = new InfiniteRepeat("numbers", new Regex("number", "\\d"), { min: 3, divider: new Literal("divider", "divider"), trimDivider: true });
270
256
 
271
- expect(clone).toEqual(expected);
257
+ expect(arePatternsEqual(clone, expected)).toBeTruthy();
272
258
  });
273
259
 
274
260
  test("No Results, min is 0", () => {
@@ -276,6 +262,7 @@ describe("InfiniteRepeat", () => {
276
262
  const result = numbers.exec("j");
277
263
  expect(result.ast).toBeNull();
278
264
  expect(result.cursor.index).toBe(0);
265
+ expect(result.cursor.hasError).toBeTruthy();
279
266
  });
280
267
 
281
268
 
@@ -3,6 +3,9 @@ import { Cursor } from "./Cursor";
3
3
  import { Pattern } from "./Pattern";
4
4
  import { clonePatterns } from "./clonePatterns";
5
5
  import { findPattern } from "./findPattern";
6
+ import { ParseResult } from "./ParseResult";
7
+
8
+ let idIndex = 0;
6
9
 
7
10
  export interface InfiniteRepeatOptions {
8
11
  divider?: Pattern;
@@ -11,6 +14,7 @@ export interface InfiniteRepeatOptions {
11
14
  }
12
15
 
13
16
  export class InfiniteRepeat implements Pattern {
17
+ private _id: string;
14
18
  private _type: string;
15
19
  private _name: string;
16
20
  private _parent: Pattern | null;
@@ -22,6 +26,10 @@ export class InfiniteRepeat implements Pattern {
22
26
  private _min: number;
23
27
  private _trimDivider: boolean;
24
28
 
29
+ get id(): string {
30
+ return this._id;
31
+ }
32
+
25
33
  get type(): string {
26
34
  return this._type;
27
35
  }
@@ -42,27 +50,24 @@ export class InfiniteRepeat implements Pattern {
42
50
  return this._children;
43
51
  }
44
52
 
45
- get isOptional(): boolean {
46
- return this._min === 0;
47
- }
48
-
49
53
  get min(): number {
50
54
  return this._min;
51
55
  }
52
56
 
53
57
  constructor(name: string, pattern: Pattern, options: InfiniteRepeatOptions = {}) {
54
- const min = options.min != null ? options.min : 1;
58
+ const min = options.min != null ? Math.max(options.min, 1) : 1;
55
59
  const divider = options.divider;
56
60
  let children: Pattern[];
57
61
 
58
62
  if (divider != null) {
59
- children = [pattern.clone(pattern.name, false), divider.clone(divider.name, false)]
63
+ children = [pattern.clone(), divider.clone()];
60
64
  } else {
61
- children = [pattern.clone(pattern.name, false)]
65
+ children = [pattern.clone()];
62
66
  }
63
67
 
64
68
  this._assignChildrenToParent(children);
65
69
 
70
+ this._id = `infinite-repeat-${idIndex++}`;
66
71
  this._type = "infinite-repeat";
67
72
  this._name = name;
68
73
  this._min = min;
@@ -70,7 +75,7 @@ export class InfiniteRepeat implements Pattern {
70
75
  this._children = children;
71
76
  this._pattern = children[0];
72
77
  this._divider = children[1];
73
- this._firstIndex = -1
78
+ this._firstIndex = -1;
74
79
  this._nodes = [];
75
80
  this._trimDivider = options.trimDivider == null ? false : options.trimDivider;
76
81
  }
@@ -88,8 +93,10 @@ export class InfiniteRepeat implements Pattern {
88
93
  return ast?.value === text;
89
94
  }
90
95
 
91
- exec(text: string) {
96
+ exec(text: string, record = false): ParseResult {
92
97
  const cursor = new Cursor(text);
98
+ record && cursor.startRecording();
99
+
93
100
  const ast = this.parse(cursor);
94
101
 
95
102
  return {
@@ -99,6 +106,8 @@ export class InfiniteRepeat implements Pattern {
99
106
  }
100
107
 
101
108
  parse(cursor: Cursor): Node | null {
109
+ cursor.startParseWith(this);
110
+
102
111
  this._firstIndex = cursor.index;
103
112
  this._nodes = [];
104
113
 
@@ -113,14 +122,17 @@ export class InfiniteRepeat implements Pattern {
113
122
  cursor.recordMatch(this, node);
114
123
  }
115
124
 
125
+ cursor.endParse();
116
126
  return node;
117
127
  }
118
128
 
119
129
  if (this._min > 0) {
130
+ cursor.endParse();
120
131
  return null;
121
132
  }
122
133
 
123
134
  cursor.resolveError();
135
+ cursor.endParse();
124
136
  return null;
125
137
  }
126
138
 
@@ -137,9 +149,14 @@ export class InfiniteRepeat implements Pattern {
137
149
 
138
150
  while (true) {
139
151
  const runningCursorIndex = cursor.index;
140
- const repeatedNode = this._pattern.parse(cursor);
152
+ const repeatNode = this._pattern.parse(cursor);
153
+
154
+ const hasError = cursor.hasError;
155
+ const hasNoErrorAndNoResult = !cursor.hasError && repeatNode == null;
156
+ const hasDivider = this._divider != null;
157
+ const hasNoDivider = !hasDivider;
141
158
 
142
- if (cursor.hasError) {
159
+ if (hasError) {
143
160
  const lastValidNode = this._getLastValidNode();
144
161
 
145
162
  if (lastValidNode != null) {
@@ -152,8 +169,13 @@ export class InfiniteRepeat implements Pattern {
152
169
 
153
170
  break;
154
171
  } else {
155
- if (repeatedNode != null) {
156
- this._nodes.push(repeatedNode);
172
+ if (hasNoErrorAndNoResult && hasNoDivider) {
173
+ // If we didn't match and didn't error we need to get out. Nothing different will happen.
174
+ break;
175
+ }
176
+
177
+ if (repeatNode != null) {
178
+ this._nodes.push(repeatNode);
157
179
 
158
180
  if (!cursor.hasNext()) {
159
181
  passed = true;
@@ -164,20 +186,31 @@ export class InfiniteRepeat implements Pattern {
164
186
  }
165
187
 
166
188
  if (this._divider != null) {
189
+ const dividerStartIndex = cursor.index;
167
190
  const dividerNode = this._divider.parse(cursor);
168
191
 
169
192
  if (cursor.hasError) {
170
193
  passed = true;
171
194
  break;
172
- } else if (dividerNode != null) {
173
- this._nodes.push(dividerNode);
174
-
175
- if (!cursor.hasNext()) {
176
- passed = true;
177
- break;
195
+ } else {
196
+ if (dividerNode == null) {
197
+ cursor.moveTo(dividerStartIndex);
198
+
199
+ if (dividerNode == null && repeatNode == null) {
200
+ // If neither the repeat pattern or divider pattern matched get out.
201
+ passed = true;
202
+ break;
203
+ }
204
+ } else {
205
+ this._nodes.push(dividerNode);
206
+
207
+ if (!cursor.hasNext()) {
208
+ passed = true;
209
+ break;
210
+ }
211
+
212
+ cursor.next();
178
213
  }
179
-
180
- cursor.next();
181
214
  }
182
215
  }
183
216
  }
@@ -208,10 +241,10 @@ export class InfiniteRepeat implements Pattern {
208
241
  cursor.moveTo(dividerNode.firstIndex);
209
242
  }
210
243
 
211
- // if (this._nodes.length === 0) {
212
- // cursor.moveTo(this._firstIndex);
213
- // return null;
214
- // }
244
+ if (this._nodes.length === 0) {
245
+ cursor.moveTo(this._firstIndex);
246
+ return null;
247
+ }
215
248
 
216
249
  const lastIndex = this._nodes[this._nodes.length - 1].lastIndex;
217
250
  cursor.moveTo(lastIndex);
@@ -250,7 +283,7 @@ export class InfiniteRepeat implements Pattern {
250
283
 
251
284
  getNextTokens(): string[] {
252
285
  if (this._parent == null) {
253
- return []
286
+ return [];
254
287
  }
255
288
 
256
289
  return this._parent.getTokensAfter(this);
@@ -303,25 +336,17 @@ export class InfiniteRepeat implements Pattern {
303
336
  return [];
304
337
  }
305
338
 
306
- return this._parent.getPatternsAfter(this)
339
+ return this._parent.getPatternsAfter(this);
307
340
  }
308
341
 
309
342
  find(predicate: (p: Pattern) => boolean): Pattern | null {
310
343
  return findPattern(this, predicate);
311
344
  }
312
345
 
313
- clone(name = this._name, isOptional?: boolean): Pattern {
346
+ clone(name = this._name): Pattern {
314
347
  let min = this._min;
315
348
 
316
- if (isOptional != null) {
317
- if (isOptional) {
318
- min = 0
319
- } else {
320
- min = Math.max(this._min, 1);
321
- }
322
- }
323
-
324
- return new InfiniteRepeat(
349
+ const clone = new InfiniteRepeat(
325
350
  name,
326
351
  this._pattern,
327
352
  {
@@ -330,6 +355,14 @@ export class InfiniteRepeat implements Pattern {
330
355
  trimDivider: this._trimDivider
331
356
  }
332
357
  );
358
+
359
+ clone._id = this._id;
360
+
361
+ return clone;
362
+ }
363
+
364
+ isEqual(pattern: InfiniteRepeat): boolean {
365
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
333
366
  }
334
367
  }
335
368
 
@@ -1,13 +1,13 @@
1
1
  import { Node } from "../ast/Node";
2
- import { And } from "./And";
2
+ import { Sequence } from "./Sequence";
3
3
  import { Cursor } from "./Cursor";
4
4
  import { Literal } from "./Literal"
5
5
 
6
6
  describe("Literal", () => {
7
7
  test("Empty Value", () => {
8
8
  expect(() => {
9
- new Literal("empty", "")
10
- }).toThrowError()
9
+ new Literal("empty", "");
10
+ }).toThrowError();
11
11
  });
12
12
 
13
13
  test("Successful Parse", () => {
@@ -20,10 +20,10 @@ describe("Literal", () => {
20
20
  expect(result).toEqual(expected);
21
21
  expect(cursor.index).toBe(11);
22
22
  expect(cursor.error).toBeNull();
23
- expect(cursor.leafMatch.node).toEqual(expected)
24
- expect(cursor.leafMatch.pattern).toBe(literal)
25
- expect(cursor.rootMatch.node).toEqual(expected)
26
- expect(cursor.rootMatch.pattern).toBe(literal)
23
+ expect(cursor.leafMatch.node).toEqual(expected);
24
+ expect(cursor.leafMatch.pattern).toBe(literal);
25
+ expect(cursor.rootMatch.node).toEqual(expected);
26
+ expect(cursor.rootMatch.pattern).toBe(literal);
27
27
  });
28
28
 
29
29
  test("Failed Parse", () => {
@@ -36,7 +36,7 @@ describe("Literal", () => {
36
36
  expect(cursor.index).toBe(6);
37
37
  expect(cursor.error?.startIndex).toBe(0);
38
38
  expect(cursor.error?.endIndex).toBe(6);
39
- expect(cursor.error?.pattern).toBe(literal)
39
+ expect(cursor.error?.pattern).toBe(literal);
40
40
  });
41
41
 
42
42
  test("Failed Parse Because End Of Text", () => {
@@ -49,18 +49,7 @@ describe("Literal", () => {
49
49
  expect(cursor.index).toBe(10);
50
50
  expect(cursor.error?.startIndex).toBe(0);
51
51
  expect(cursor.error?.endIndex).toBe(11);
52
- expect(cursor.error?.pattern).toBe(literal)
53
- });
54
-
55
- test("Failed Parse (Optional)", () => {
56
- const literal = new Literal("greeting", "Hello World!", true);
57
-
58
- const cursor = new Cursor("Hello Saturn!");
59
- const result = literal.parse(cursor);
60
-
61
- expect(result).toEqual(null);
62
- expect(cursor.index).toBe(0);
63
- expect(cursor.error).toBeNull();
52
+ expect(cursor.error?.pattern).toBe(literal);
64
53
  });
65
54
 
66
55
  test("Clone", () => {
@@ -85,7 +74,7 @@ describe("Literal", () => {
85
74
  const tokens = literal.getTokensAfter(new Literal("bogus", "bogus"));
86
75
  const expected: string[] = [];
87
76
 
88
- expect(tokens).toEqual(expected)
77
+ expect(tokens).toEqual(expected);
89
78
  });
90
79
 
91
80
  test("Properties", () => {
@@ -100,7 +89,7 @@ describe("Literal", () => {
100
89
  test("Exec", () => {
101
90
  const literal = new Literal("a", "A");
102
91
  const { ast: result } = literal.exec("B");
103
- expect(result).toBeNull()
92
+ expect(result).toBeNull();
104
93
  });
105
94
 
106
95
  test("Test With No Match", () => {
@@ -118,8 +107,8 @@ describe("Literal", () => {
118
107
  });
119
108
 
120
109
  test("Get Next Tokens", () => {
121
- const sequence = new And("sequence", [new Literal("a", "A")]);
122
- const parent = new And("parent", [sequence, new Literal("b", "B")]);
110
+ const sequence = new Sequence("sequence", [new Literal("a", "A")]);
111
+ const parent = new Sequence("parent", [sequence, new Literal("b", "B")]);
123
112
 
124
113
  const a = parent.find(p => p.name === "a");
125
114
  const tokens = a?.getNextTokens() || [];
@@ -144,12 +133,12 @@ describe("Literal", () => {
144
133
  });
145
134
 
146
135
  test("Get Next Patterns", () => {
147
- const sequence = new And("sequence", [new Literal("a", "A")]);
148
- const parent = new And("parent", [sequence, new Literal("b", "B")]);
136
+ const sequence = new Sequence("sequence", [new Literal("a", "A")]);
137
+ const parent = new Sequence("parent", [sequence, new Literal("b", "B")]);
149
138
 
150
139
  const a = parent.find(p => p.name === "a");
151
140
  const nextPatterns = a?.getNextPatterns() || [];
152
- const b = parent.find(p => p.name === "b")
141
+ const b = parent.find(p => p.name === "b");
153
142
 
154
143
  expect(nextPatterns[0]).toBe(b);
155
144
  });