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,19 +1,20 @@
1
1
  import { Cursor } from "./Cursor";
2
2
  import { Node } from "../ast/Node";
3
3
  import { Literal } from "./Literal";
4
- import { Or } from "./Or";
5
- import { And } from "./And";
4
+ import { Options } from "./Options";
5
+ import { Sequence } from "./Sequence";
6
6
  import { Pattern } from "./Pattern";
7
+ import { Optional } from "./Optional";
7
8
 
8
- describe("Or", () => {
9
+ describe("Options", () => {
9
10
  test("Empty Options", () => {
10
11
  expect(() => {
11
- new Or("bad", []);
12
+ new Options("bad", []);
12
13
  }).toThrowError();
13
14
  });
14
15
 
15
16
  test("One Option Successful", () => {
16
- const a = new Or("a", [new Literal("a", "A")]);
17
+ const a = new Options("a", [new Literal("a", "A")]);
17
18
  const cursor = new Cursor("A");
18
19
  const result = a.parse(cursor);
19
20
  const expected = new Node("literal", "a", 0, 0, [], "A")
@@ -22,7 +23,7 @@ describe("Or", () => {
22
23
  });
23
24
 
24
25
  test("One Option Failed", () => {
25
- const a = new Or("a", [new Literal("a", "A")]);
26
+ const a = new Options("a", [new Literal("a", "A")]);
26
27
  const cursor = new Cursor("B");
27
28
  const result = a.parse(cursor);
28
29
 
@@ -32,7 +33,7 @@ describe("Or", () => {
32
33
  });
33
34
 
34
35
  test("Two Option", () => {
35
- const a = new Or("a-b", [new Literal("a", "A"), new Literal("b", "B")]);
36
+ const a = new Options("a-b", [new Literal("a", "A"), new Literal("b", "B")]);
36
37
  const cursor = new Cursor("AB");
37
38
  let result = a.parse(cursor);
38
39
  let expected = new Node("literal", "a", 0, 0, [], "A")
@@ -47,17 +48,8 @@ describe("Or", () => {
47
48
  ], "B");
48
49
  });
49
50
 
50
- test("Failed (Optional)", () => {
51
- const a = new Or("a", [new Literal("a", "A")], true);
52
- const cursor = new Cursor("B");
53
- const result = a.parse(cursor);
54
-
55
- expect(result).toBeNull();
56
- expect(cursor.hasError).toBeFalsy();
57
- });
58
-
59
51
  test("Get Tokens", () => {
60
- const aOrB = new Or("a-b", [new Literal("a", "A"), new Literal("b", "B")]);
52
+ const aOrB = new Options("a-b", [new Literal("a", "A"), new Literal("b", "B")]);
61
53
  const tokens = aOrB.getTokens();
62
54
  const expected = ["A", "B"];
63
55
 
@@ -65,8 +57,8 @@ describe("Or", () => {
65
57
  });
66
58
 
67
59
  test("Get Tokens After", () => {
68
- const a = new Or("a", [new Literal("a", "A")]);
69
- const parent = new And("parent", [a, new Literal("b", "B")]);
60
+ const a = new Options("a", [new Literal("a", "A")]);
61
+ const parent = new Sequence("parent", [a, new Literal("b", "B")]);
70
62
  const tokens = parent.children[0].getTokensAfter(parent.children[0].children[0]);
71
63
  const expected = ["B"];
72
64
 
@@ -74,7 +66,7 @@ describe("Or", () => {
74
66
  });
75
67
 
76
68
  test("Get Tokens After Without A Parent", () => {
77
- const a = new Or("a", [new Literal("a", "A")]);
69
+ const a = new Options("a", [new Literal("a", "A")]);
78
70
  const tokens = a.getTokensAfter(a.children[0]);
79
71
  const expected: string[] = [];
80
72
 
@@ -82,36 +74,35 @@ describe("Or", () => {
82
74
  });
83
75
 
84
76
  test("Properties", () => {
85
- const a = new Or("a", [new Literal("a", "A")]);
77
+ const a = new Options("a", [new Literal("a", "A")]);
86
78
 
87
79
  expect(a.type).toBe("or");
88
80
  expect(a.name).toBe("a");
89
- expect(a.isOptional).toBeFalsy();
90
81
  expect(a.parent).toBeNull();
91
82
  expect(a.children[0].name).toBe("a");
92
83
  });
93
84
 
94
85
  test("Exec", () => {
95
- const a = new Or("a", [new Literal("a", "A")]);
86
+ const a = new Options("a", [new Literal("a", "A")]);
96
87
  const { ast: result } = a.exec("B");
97
88
  expect(result).toBeNull();
98
89
  });
99
90
 
100
91
  test("Test No Match", () => {
101
- const a = new Or("a", [new Literal("a", "A")]);
92
+ const a = new Options("a", [new Literal("a", "A")]);
102
93
  const result = a.test("B");
103
94
  expect(result).toBeFalsy();
104
95
  });
105
96
 
106
97
  test("Test With Match", () => {
107
- const a = new Or("a", [new Literal("a", "A")]);
98
+ const a = new Options("a", [new Literal("a", "A")]);
108
99
  const result = a.test("A");
109
100
  expect(result).toBeTruthy();
110
101
  });
111
102
 
112
103
  test("Get Next Tokens", () => {
113
- const sequence = new And("sequence", [
114
- new Or("a-or-b", [
104
+ const sequence = new Sequence("sequence", [
105
+ new Options("a-or-b", [
115
106
  new Literal("a", "A"),
116
107
  new Literal("b", "B")
117
108
  ]),
@@ -126,7 +117,7 @@ describe("Or", () => {
126
117
  });
127
118
 
128
119
  test("Get Next Tokens With Null Parent", () => {
129
- const or = new Or("a-or-b", [
120
+ const or = new Options("a-or-b", [
130
121
  new Literal("a", "A"),
131
122
  new Literal("b", "B")
132
123
  ])
@@ -137,8 +128,8 @@ describe("Or", () => {
137
128
 
138
129
 
139
130
  test("Get Tokens After", () => {
140
- const sequence = new And("sequence", [
141
- new Or("a-or-b", [
131
+ const sequence = new Sequence("sequence", [
132
+ new Options("a-or-b", [
142
133
  new Literal("a", "A"),
143
134
  new Literal("b", "B")
144
135
  ]),
@@ -154,7 +145,7 @@ describe("Or", () => {
154
145
  });
155
146
 
156
147
  test("Get Patterns", () => {
157
- const aOrB = new Or("a-b", [new Literal("a", "A"), new Literal("b", "B")]);
148
+ const aOrB = new Options("a-b", [new Literal("a", "A"), new Literal("b", "B")]);
158
149
  const patterns = aOrB.getPatterns();
159
150
  const expected = [
160
151
  aOrB.find(p => p.name === "a"),
@@ -165,8 +156,8 @@ describe("Or", () => {
165
156
  });
166
157
 
167
158
  test("Get Patterns After", () => {
168
- const sequence = new And("sequence", [
169
- new Or("a-or-b", [
159
+ const sequence = new Sequence("sequence", [
160
+ new Options("a-or-b", [
170
161
  new Literal("a", "A"),
171
162
  new Literal("b", "B")
172
163
  ]),
@@ -182,7 +173,7 @@ describe("Or", () => {
182
173
  });
183
174
 
184
175
  test("Get Patterns After With Null Parent", () => {
185
- const or = new Or("a-or-b", [
176
+ const or = new Options("a-or-b", [
186
177
  new Literal("a", "A"),
187
178
  new Literal("b", "B")
188
179
  ])
@@ -193,8 +184,8 @@ describe("Or", () => {
193
184
  });
194
185
 
195
186
  test("Get Next Patterns", () => {
196
- const sequence = new And("sequence", [
197
- new Or("a-or-b", [
187
+ const sequence = new Sequence("sequence", [
188
+ new Options("a-or-b", [
198
189
  new Literal("a", "A"),
199
190
  new Literal("b", "B")
200
191
  ]),
@@ -209,7 +200,7 @@ describe("Or", () => {
209
200
  });
210
201
 
211
202
  test("Get Next Patterns With Null Parent", () => {
212
- const or = new Or("a-or-b", [
203
+ const or = new Options("a-or-b", [
213
204
  new Literal("a", "A"),
214
205
  new Literal("b", "B")
215
206
  ])
@@ -225,11 +216,11 @@ describe("Or", () => {
225
216
  const smith = new Literal("smith", "Smith");
226
217
  const space = new Literal("space", " ");
227
218
 
228
- const firstName = new Or("first-name", [john, jane], false, true);
229
- const lastName = new Or("last-name", [doe, smith], false, true);
219
+ const firstName = new Options("first-name", [john, jane], true);
220
+ const lastName = new Options("last-name", [doe, smith], true);
230
221
  const johnJohnson = new Literal("john-johnson", "John Johnson");
231
- const fullName = new And("full-name", [firstName, space, lastName]);
232
- const names = new Or("names", [fullName, johnJohnson], false, true);
222
+ const fullName = new Sequence("full-name", [firstName, space, lastName]);
223
+ const names = new Options("names", [fullName, johnJohnson], true);
233
224
 
234
225
  const result = names.exec("John Johnson");
235
226
  expect(result.ast?.value).toBe("John Johnson");
@@ -242,11 +233,11 @@ describe("Or", () => {
242
233
  const smith = new Literal("smith", "Smith");
243
234
  const space = new Literal("space", " ");
244
235
 
245
- const firstName = new Or("first-name", [john, jane], false, true);
246
- const lastName = new Or("last-name", [doe, smith], false, true);
236
+ const firstName = new Options("first-name", [john, jane], true);
237
+ const lastName = new Options("last-name", [doe, smith], true);
247
238
  const johnJohnson = new Literal("john-johnson", "John Johnson");
248
- const fullName = new And("full-name", [firstName, space, lastName]);
249
- const names = new Or("names", [johnJohnson, fullName], false, true);
239
+ const fullName = new Sequence("full-name", [firstName, space, lastName]);
240
+ const names = new Options("names", [johnJohnson, fullName], true);
250
241
 
251
242
  const result = names.exec("John Johnson");
252
243
  expect(result.ast?.value).toBe("John Johnson");
@@ -259,14 +250,25 @@ describe("Or", () => {
259
250
  const smith = new Literal("smith", "Smith");
260
251
  const space = new Literal("space", " ");
261
252
 
262
- const firstName = new Or("first-name", [john, jane], false, true);
263
- const lastName = new Or("last-name", [doe, smith], false, true);
253
+ const firstName = new Options("first-name", [john, jane], true);
254
+ const lastName = new Options("last-name", [doe, smith], true);
264
255
  const johnJohnson = new Literal("john-johnson", "John Johnson");
265
256
  const johnStockton = new Literal("john-stockton", "John Stockton");
266
- const fullName = new And("full-name", [firstName, space, lastName]);
267
- const names = new Or("names", [johnStockton, johnJohnson, fullName], false, true);
257
+ const fullName = new Sequence("full-name", [firstName, space, lastName]);
258
+ const names = new Options("names", [johnStockton, johnJohnson, fullName], true);
268
259
 
269
260
  const result = names.exec("John Johnson");
270
261
  expect(result.ast?.value).toBe("John Johnson");
271
262
  });
263
+
264
+ // This doesn't make sense, but every pattern needs to handle a null result with no error.
265
+ test("Optional option", () => {
266
+ const john = new Optional("optional-john", new Literal("john", "John"));
267
+ const jane = new Literal("jane", "Jane");
268
+
269
+ const firstName = new Options("first-name", [john, jane], true);
270
+
271
+ const result = firstName.exec("Jane");
272
+ expect(result.ast?.value).toBe("Jane");
273
+ });
272
274
  });
@@ -3,16 +3,23 @@ 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";
6
7
 
7
- export class Or implements Pattern {
8
+ let idIndex = 0;
9
+
10
+ export class Options implements Pattern {
11
+ private _id: string;
8
12
  private _type: string;
9
13
  private _name: string;
10
14
  private _parent: Pattern | null;
11
15
  private _children: Pattern[];
12
- private _isOptional: boolean;
13
16
  private _isGreedy: boolean;
14
17
  private _firstIndex: number;
15
18
 
19
+ get id(): string {
20
+ return this._id;
21
+ }
22
+
16
23
  get type(): string {
17
24
  return this._type;
18
25
  }
@@ -33,23 +40,19 @@ export class Or implements Pattern {
33
40
  return this._children;
34
41
  }
35
42
 
36
- get isOptional(): boolean {
37
- return this._isOptional;
38
- }
39
-
40
- constructor(name: string, options: Pattern[], isOptional = false, isGreedy = false) {
43
+ constructor(name: string, options: Pattern[], isGreedy = false) {
41
44
  if (options.length === 0) {
42
45
  throw new Error("Need at least one pattern with an 'or' pattern.");
43
46
  }
44
47
 
45
- const children = clonePatterns(options, false);
48
+ const children = clonePatterns(options);
46
49
  this._assignChildrenToParent(children);
47
50
 
51
+ this._id = `or-${idIndex++}`;
48
52
  this._type = "or";
49
53
  this._name = name;
50
54
  this._parent = null;
51
55
  this._children = children;
52
- this._isOptional = isOptional;
53
56
  this._firstIndex = 0;
54
57
  this._isGreedy = isGreedy;
55
58
  }
@@ -67,8 +70,10 @@ export class Or implements Pattern {
67
70
  return ast?.value === text;
68
71
  }
69
72
 
70
- exec(text: string) {
73
+ exec(text: string, record = false): ParseResult {
71
74
  const cursor = new Cursor(text);
75
+ record && cursor.startRecording();
76
+
72
77
  const ast = this.parse(cursor);
73
78
 
74
79
  return {
@@ -78,6 +83,7 @@ export class Or implements Pattern {
78
83
  }
79
84
 
80
85
  parse(cursor: Cursor): Node | null {
86
+ cursor.startParseWith(this);
81
87
  this._firstIndex = cursor.index;
82
88
 
83
89
  const node = this._tryToParse(cursor);
@@ -85,16 +91,13 @@ export class Or implements Pattern {
85
91
  if (node != null) {
86
92
  cursor.moveTo(node.lastIndex);
87
93
  cursor.resolveError();
88
- return node
89
- }
90
94
 
91
- if (!this._isOptional) {
92
- cursor.recordErrorAt(this._firstIndex, this._firstIndex, this)
93
- return null;
95
+ cursor.endParse();
96
+ return node;
94
97
  }
95
98
 
96
- cursor.resolveError();
97
- cursor.moveTo(this._firstIndex);
99
+ cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
100
+ cursor.endParse();
98
101
  return null;
99
102
  }
100
103
 
@@ -104,11 +107,12 @@ export class Or implements Pattern {
104
107
  for (const pattern of this._children) {
105
108
  cursor.moveTo(this._firstIndex);
106
109
  const result = pattern.parse(cursor);
110
+
107
111
  if (this._isGreedy) {
108
112
  results.push(result);
109
113
  }
110
114
 
111
- if (!cursor.hasError && !this._isGreedy) {
115
+ if (result != null && !this._isGreedy) {
112
116
  return result;
113
117
  }
114
118
 
@@ -141,7 +145,7 @@ export class Or implements Pattern {
141
145
 
142
146
  getNextTokens(): string[] {
143
147
  if (this._parent == null) {
144
- return []
148
+ return [];
145
149
  }
146
150
 
147
151
  return this._parent.getTokensAfter(this);
@@ -162,7 +166,7 @@ export class Or implements Pattern {
162
166
  return [];
163
167
  }
164
168
 
165
- return this._parent.getPatternsAfter(this)
169
+ return this._parent.getPatternsAfter(this);
166
170
  }
167
171
 
168
172
  getNextPatterns(): Pattern[] {
@@ -170,15 +174,20 @@ export class Or implements Pattern {
170
174
  return [];
171
175
  }
172
176
 
173
- return this.parent.getPatternsAfter(this)
177
+ return this.parent.getPatternsAfter(this);
174
178
  }
175
179
 
176
180
  find(predicate: (p: Pattern) => boolean): Pattern | null {
177
181
  return findPattern(this, predicate);
178
182
  }
179
183
 
180
- clone(name = this._name, isOptional = this._isOptional): Pattern {
181
- const or = new Or(name, this._children, isOptional, this._isGreedy);
184
+ clone(name = this._name): Pattern {
185
+ const or = new Options(name, this._children, this._isGreedy);
186
+ or._id = this._id;
182
187
  return or;
183
188
  }
189
+
190
+ isEqual(pattern: Options): boolean {
191
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
192
+ }
184
193
  }
@@ -1,18 +1,18 @@
1
1
  import { Cursor } from "./Cursor";
2
2
  import { Node } from "../ast/Node";
3
- import { ParseResult } from "./ParseResult"
3
+ import { ParseResult } from "./ParseResult";
4
4
 
5
5
  export interface Pattern {
6
+ id: string;
6
7
  type: string;
7
8
  name: string;
8
9
  parent: Pattern | null;
9
10
  children: Pattern[];
10
- isOptional: boolean;
11
11
 
12
12
  parse(cursor: Cursor): Node | null;
13
- exec(text: string): ParseResult;
14
- test(text: string): boolean;
15
- clone(name?: string, isOptional?: boolean): Pattern;
13
+ exec(text: string, record?: boolean): ParseResult;
14
+ test(text: string, record?: boolean): boolean;
15
+ clone(name?: string): Pattern;
16
16
  getTokens(): string[];
17
17
  getTokensAfter(childReference: Pattern): string[];
18
18
  getNextTokens(): string[];
@@ -20,4 +20,5 @@ export interface Pattern {
20
20
  getPatternsAfter(childReference: Pattern): Pattern[];
21
21
  getNextPatterns(): Pattern[];
22
22
  find(predicate: (p: Pattern) => boolean): Pattern | null;
23
+ isEqual(pattern: Pattern): boolean;
23
24
  }
@@ -1,9 +1,9 @@
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
- import { Or } from "./Or";
6
+ import { Options } from "./Options";
7
7
  import { Pattern } from "./Pattern";
8
8
  import { Reference } from "./Reference";
9
9
  import { Regex } from "./Regex";
@@ -20,8 +20,8 @@ function createValuePattern() {
20
20
 
21
21
  const valueRef = new Reference("value");
22
22
  const values = new Repeat("values", valueRef, { divider });
23
- const array = new And("array", [openBracket, values, closeBracket]);
24
- const value = new Or("value", [number, array]);
23
+ const array = new Sequence("array", [openBracket, values, closeBracket]);
24
+ const value = new Options("value", [number, array]);
25
25
 
26
26
  return value;
27
27
  }
@@ -32,7 +32,7 @@ describe("Reference", () => {
32
32
  const cursor = new Cursor("[1, 2]");
33
33
  const result = value.parse(cursor);
34
34
 
35
- const expected = new Node("and", "array", 0, 5, [
35
+ const expected = new Node("sequence", "array", 0, 5, [
36
36
  new Node("literal", "open-bracket", 0, 0, [], "["),
37
37
  new Node("infinite-repeat", "values", 1, 4, [
38
38
  new Node("regex", "number", 1, 1, [], "1"),
@@ -40,7 +40,7 @@ describe("Reference", () => {
40
40
  new Node("regex", "number", 4, 4, [], "2")
41
41
  ]),
42
42
  new Node("literal", "close-bracket", 5, 5, [], "]"),
43
- ])
43
+ ]);
44
44
 
45
45
  expect(result).toEqual(expected);
46
46
  });
@@ -49,8 +49,8 @@ describe("Reference", () => {
49
49
  const ref = new Reference("bad-reference");
50
50
 
51
51
  expect(() => {
52
- ref.parse(new Cursor("text"))
53
- }).toThrowError()
52
+ ref.parse(new Cursor("text"));
53
+ }).toThrowError();
54
54
  });
55
55
 
56
56
  test("Get Tokens", () => {
@@ -76,7 +76,7 @@ describe("Reference", () => {
76
76
 
77
77
  test("Get Tokens After With No Parent", () => {
78
78
  const ref = new Reference("bad-reference");
79
- const tokens = ref.getTokensAfter(new Literal("bogus", "bogus"))
79
+ const tokens = ref.getTokensAfter(new Literal("bogus", "bogus"));
80
80
 
81
81
  expect(tokens).toEqual([]);
82
82
  });
@@ -86,30 +86,29 @@ describe("Reference", () => {
86
86
 
87
87
  expect(ref.type).toBe("reference");
88
88
  expect(ref.name).toBe("ref");
89
- expect(ref.isOptional).toBeFalsy();
90
- expect(ref.parent).toBe(null)
91
- expect(ref.children).toEqual([])
89
+ expect(ref.parent).toBe(null);
90
+ expect(ref.children).toEqual([]);
92
91
  });
93
92
 
94
93
  test("Exec", () => {
95
94
  const value = createValuePattern();
96
- const reference = findPattern(value, p => p.type === "reference") as Reference
95
+ const reference = findPattern(value, p => p.type === "reference") as Reference;
97
96
  const { ast: result } = reference.exec("B");
98
- expect(result).toBeNull()
97
+ expect(result).toBeNull();
99
98
  });
100
99
 
101
100
  test("Test With Match", () => {
102
101
  const value = createValuePattern();
103
- const reference = findPattern(value, p => p.type === "reference") as Reference
102
+ const reference = findPattern(value, p => p.type === "reference") as Reference;
104
103
  const result = reference.test("[1]");
105
- expect(result).toBeTruthy()
104
+ expect(result).toBeTruthy();
106
105
  });
107
106
 
108
107
  test("Test No Match", () => {
109
108
  const value = createValuePattern();
110
- const reference = findPattern(value, p => p.type === "reference") as Reference
109
+ const reference = findPattern(value, p => p.type === "reference") as Reference;
111
110
  const result = reference.test("B");
112
- expect(result).toBeFalsy()
111
+ expect(result).toBeFalsy();
113
112
  });
114
113
 
115
114
  test("Find Pattern", () => {
@@ -134,7 +133,7 @@ describe("Reference", () => {
134
133
  const reference = new Reference("ref-name");
135
134
  const tokens = reference.getNextTokens();
136
135
 
137
- expect(tokens).toEqual([])
136
+ expect(tokens).toEqual([]);
138
137
  });
139
138
 
140
139
  test("Get Tokens After", () => {
@@ -149,7 +148,7 @@ describe("Reference", () => {
149
148
  const reference = new Reference("ref-name");
150
149
  const tokens = reference.getTokensAfter(new Literal("bogus", "Bogus"));
151
150
 
152
- expect(tokens).toEqual([])
151
+ expect(tokens).toEqual([]);
153
152
  });
154
153
 
155
154
  test("Get Patterns", () => {
@@ -178,7 +177,7 @@ describe("Reference", () => {
178
177
  const reference = new Reference("ref-name");
179
178
  const patterns = reference.getPatternsAfter(new Literal("bogus", "Bogus"));
180
179
 
181
- expect(patterns).toEqual([])
180
+ expect(patterns).toEqual([]);
182
181
  });
183
182
 
184
183
  test("Get Next Patterns", () => {
@@ -197,7 +196,7 @@ describe("Reference", () => {
197
196
  const reference = new Reference("ref-name");
198
197
  const patterns = reference.getNextPatterns();
199
198
 
200
- expect(patterns).toEqual([])
199
+ expect(patterns).toEqual([]);
201
200
  });
202
201
 
203
202
  });
@@ -2,15 +2,22 @@ import { Node } from "../ast/Node";
2
2
  import { Cursor } from "./Cursor";
3
3
  import { Pattern } from "./Pattern";
4
4
  import { findPattern } from "./findPattern";
5
+ import { ParseResult } from "./ParseResult";
6
+
7
+ let idIndex = 0;
5
8
 
6
9
  export class Reference implements Pattern {
10
+ private _id: string;
7
11
  private _type: string;
8
12
  private _name: string;
9
13
  private _parent: Pattern | null;
10
- private _isOptional: boolean;
11
14
  private _pattern: Pattern | null;
12
15
  private _children: Pattern[];
13
16
 
17
+ get id(): string {
18
+ return this._id;
19
+ }
20
+
14
21
  get type(): string {
15
22
  return this._type;
16
23
  }
@@ -28,18 +35,14 @@ export class Reference implements Pattern {
28
35
  }
29
36
 
30
37
  get children(): Pattern[] {
31
- return this._children
32
- }
33
-
34
- get isOptional(): boolean {
35
- return this._isOptional;
38
+ return this._children;
36
39
  }
37
40
 
38
- constructor(name: string, isOptional = false) {
41
+ constructor(name: string) {
42
+ this._id = `reference-${idIndex++}`;
39
43
  this._type = "reference";
40
44
  this._name = name;
41
45
  this._parent = null;
42
- this._isOptional = isOptional;
43
46
  this._pattern = null;
44
47
  this._children = [];
45
48
  }
@@ -51,8 +54,10 @@ export class Reference implements Pattern {
51
54
  return ast?.value === text;
52
55
  }
53
56
 
54
- exec(text: string) {
57
+ exec(text: string, record = false): ParseResult {
55
58
  const cursor = new Cursor(text);
59
+ record && cursor.startRecording();
60
+
56
61
  const ast = this.parse(cursor);
57
62
 
58
63
  return {
@@ -73,7 +78,7 @@ export class Reference implements Pattern {
73
78
  throw new Error(`Couldn't find '${this._name}' pattern within tree.`);
74
79
  }
75
80
 
76
- const clonedPattern = pattern.clone(this._name, this._isOptional);
81
+ const clonedPattern = pattern.clone();
77
82
  clonedPattern.parent = this;
78
83
 
79
84
  this._pattern = clonedPattern;
@@ -100,7 +105,7 @@ export class Reference implements Pattern {
100
105
  if (parent == null) {
101
106
  break;
102
107
  } else {
103
- node = parent
108
+ node = parent;
104
109
  }
105
110
  }
106
111
 
@@ -121,7 +126,7 @@ export class Reference implements Pattern {
121
126
 
122
127
  getNextTokens(): string[] {
123
128
  if (this.parent == null) {
124
- return []
129
+ return [];
125
130
  }
126
131
 
127
132
  return this.parent.getTokensAfter(this);
@@ -144,14 +149,20 @@ export class Reference implements Pattern {
144
149
  return [];
145
150
  }
146
151
 
147
- return this.parent.getPatternsAfter(this)
152
+ return this.parent.getPatternsAfter(this);
148
153
  }
149
154
 
150
155
  find(_predicate: (p: Pattern) => boolean): Pattern | null {
151
156
  return null;
152
157
  }
153
158
 
154
- clone(name = this._name, isOptional = this._isOptional): Pattern {
155
- return new Reference(name, isOptional);
159
+ clone(name = this._name): Pattern {
160
+ const clone = new Reference(name);
161
+ clone._id = this._id;
162
+ return clone;
163
+ }
164
+
165
+ isEqual(pattern: Reference): boolean {
166
+ return pattern.type === this.type && pattern.name === this.name;
156
167
  }
157
168
  }