clarity-pattern-parser 5.0.0 → 6.0.2

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 (61) hide show
  1. package/README.md +328 -38
  2. package/TODO.md +63 -7
  3. package/dist/ast/Node.d.ts +8 -2
  4. package/dist/index.browser.js +520 -205
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.d.ts +6 -1
  7. package/dist/index.esm.js +519 -206
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.js +520 -205
  10. package/dist/index.js.map +1 -1
  11. package/dist/intellisense/AutoComplete.d.ts +34 -0
  12. package/dist/intellisense/Suggestion.d.ts +10 -0
  13. package/dist/intellisense/SuggestionOption.d.ts +4 -0
  14. package/dist/patterns/And.d.ts +8 -7
  15. package/dist/patterns/Cursor.d.ts +6 -4
  16. package/dist/patterns/CursorHistory.d.ts +2 -2
  17. package/dist/patterns/Literal.d.ts +8 -8
  18. package/dist/patterns/Not.d.ts +9 -5
  19. package/dist/patterns/Or.d.ts +8 -5
  20. package/dist/patterns/Pattern.d.ts +8 -4
  21. package/dist/patterns/Reference.d.ts +11 -7
  22. package/dist/patterns/Regex.d.ts +8 -8
  23. package/dist/patterns/Repeat.d.ts +8 -7
  24. package/package.json +1 -1
  25. package/src/ast/Node.test.ts +116 -0
  26. package/src/ast/Node.ts +71 -5
  27. package/src/index.ts +14 -3
  28. package/src/intellisense/AutoComplete.test.ts +168 -23
  29. package/src/intellisense/AutoComplete.ts +102 -21
  30. package/src/intellisense/Suggestion.ts +3 -4
  31. package/src/intellisense/javascript/Javascript.test.ts +86 -62
  32. package/src/intellisense/javascript/{expressionStatement.ts → assignment.ts} +7 -8
  33. package/src/intellisense/javascript/escapedCharacter.ts +0 -1
  34. package/src/intellisense/javascript/exponent.ts +0 -2
  35. package/src/intellisense/javascript/expression.ts +44 -26
  36. package/src/intellisense/javascript/fraction.ts +0 -2
  37. package/src/intellisense/javascript/infixOperator.ts +6 -2
  38. package/src/intellisense/javascript/keywords.ts +3 -0
  39. package/src/intellisense/javascript/objectAccess.ts +9 -0
  40. package/src/intellisense/javascript/objectLiteral.ts +3 -3
  41. package/src/intellisense/javascript/propertyAccess.ts +8 -3
  42. package/src/intellisense/javascript/stringLiteral.ts +16 -8
  43. package/src/patterns/And.test.ts +74 -50
  44. package/src/patterns/And.ts +72 -36
  45. package/src/patterns/Cursor.ts +17 -14
  46. package/src/patterns/CursorHistory.ts +8 -8
  47. package/src/patterns/Literal.test.ts +79 -38
  48. package/src/patterns/Literal.ts +34 -41
  49. package/src/patterns/Not.test.ts +99 -8
  50. package/src/patterns/Not.ts +58 -14
  51. package/src/patterns/Or.test.ts +128 -13
  52. package/src/patterns/Or.ts +46 -13
  53. package/src/patterns/Pattern.ts +8 -4
  54. package/src/patterns/Reference.test.ts +127 -28
  55. package/src/patterns/Reference.ts +62 -32
  56. package/src/patterns/Regex.test.ts +76 -35
  57. package/src/patterns/Regex.ts +35 -43
  58. package/src/patterns/Repeat.test.ts +72 -41
  59. package/src/patterns/Repeat.ts +55 -38
  60. package/src/patterns/getNextPattern.test.ts +0 -39
  61. package/src/patterns/getNextPattern.ts +0 -18
@@ -10,8 +10,10 @@ const greaterOrEqual = new Literal("greater-or-equal", ">=");
10
10
  const lessOrEqual = new Literal("less-or-equal", "<=");
11
11
  const greater = new Literal("greater", ">");
12
12
  const less = new Literal("less", "<");
13
- const equal = new Literal("equal", "===");
14
- const notEqual = new Literal("not-equal", "!==");
13
+ const equal = new Literal("equal", "==");
14
+ const notEqual = new Literal("not-equal", "!=");
15
+ const strictEqual = new Literal("strict-equal", "===");
16
+ const strictNotEqual = new Literal("strict-not-equal", "!==");
15
17
  const logicalOr = new Literal("logical-or", "||");
16
18
  const logicalAnd = new Literal("logical-and", "&&");
17
19
 
@@ -25,6 +27,8 @@ const infixOperator = new Or("infix-operator", [
25
27
  lessOrEqual,
26
28
  greater,
27
29
  less,
30
+ strictEqual,
31
+ strictNotEqual,
28
32
  equal,
29
33
  notEqual,
30
34
  logicalOr,
@@ -0,0 +1,3 @@
1
+ import { Literal } from "../../patterns/Literal";
2
+
3
+ export const nullKeyword = new Literal("null", "null");
@@ -0,0 +1,9 @@
1
+ import { And } from "../../patterns/And";
2
+ import { Reference } from "../../patterns/Reference";
3
+ import { name } from "./name";
4
+ import { propertyAccess } from "./propertyAccess";
5
+
6
+ export const objectAccess = new And("object-access", [
7
+ name.clone("variable-name"),
8
+ propertyAccess,
9
+ ]);
@@ -8,7 +8,7 @@ import { name } from "./name";
8
8
  import { optionalSpaces } from "./optionalSpaces";
9
9
  import { stringLiteral } from "./stringLiteral";
10
10
 
11
- const propertyName = new Or("property-name", [stringLiteral, name]);
11
+ const propertyName = new Or("property-name", [stringLiteral.clone("object-property"), name.clone("object-property")]);
12
12
  const property = new And("property", [
13
13
  propertyName,
14
14
  optionalSpaces,
@@ -17,12 +17,12 @@ const property = new And("property", [
17
17
  new Reference("expression"),
18
18
  ]);
19
19
  const divider = new Regex("property-divider", "\\s*,\\s*");
20
- const properties = new Repeat("properties", property, divider, true);
20
+ const optionalProperties = new Repeat("properties", property, divider, true);
21
21
 
22
22
  const objectLiteral = new And("object-literal", [
23
23
  new Literal("open-curly-bracket", "{"),
24
24
  optionalSpaces,
25
- properties,
25
+ optionalProperties,
26
26
  optionalSpaces,
27
27
  new Literal("close-curly-bracket", "}"),
28
28
  ]);
@@ -6,7 +6,7 @@ import { name } from "./name";
6
6
 
7
7
  const dotPropertyAccess = new And("dot-property-access", [
8
8
  new Literal("period", "."),
9
- name
9
+ name.clone("property-name")
10
10
  ]);
11
11
 
12
12
  const bracketPropertyAccess = new And("bracket-property-access", [
@@ -15,9 +15,14 @@ const bracketPropertyAccess = new And("bracket-property-access", [
15
15
  new Literal("close-square-bracket", "]"),
16
16
  ]);
17
17
 
18
- const propertyAccess = new Or("property-access", [
18
+ const propertyAccessTypes = new Or("property-access-types", [
19
19
  dotPropertyAccess,
20
- bracketPropertyAccess,
20
+ bracketPropertyAccess
21
+ ]);
22
+
23
+ const propertyAccess = new And("property-access", [
24
+ propertyAccessTypes,
25
+ new Reference("property-access", true)
21
26
  ]);
22
27
 
23
28
  export { propertyAccess }
@@ -7,19 +7,27 @@ import { escapedCharacter } from "./escapedCharacter";
7
7
 
8
8
  const doubleQuoteStringLiteral = new And("double-string-literal", [
9
9
  new Literal("double-quote", "\""),
10
- new Repeat("characters", new Or("characters", [
11
- new Regex("normal-characters", "[^\\\"]+"),
12
- escapedCharacter
13
- ])),
10
+ new Repeat("characters",
11
+ new Or("characters", [
12
+ new Regex("normal-characters", "[^\\\"]+"),
13
+ escapedCharacter
14
+ ]),
15
+ undefined,
16
+ true
17
+ ),
14
18
  new Literal("double-quote", "\""),
15
19
  ]);
16
20
 
17
21
  const singleQuoteStringLiteral = new And("single-string-literal", [
18
22
  new Literal("single-quote", "'"),
19
- new Repeat("characters", new Or("characters", [
20
- new Regex("normal-characters", "[^\\']+"),
21
- escapedCharacter
22
- ])),
23
+ new Repeat("characters",
24
+ new Or("characters", [
25
+ new Regex("normal-characters", "[^\\']+"),
26
+ escapedCharacter
27
+ ]),
28
+ undefined,
29
+ true
30
+ ),
23
31
  new Literal("single-quote", "'"),
24
32
  ]);
25
33
 
@@ -77,7 +77,7 @@ describe("And", () => {
77
77
  const sequence = new And("sequence", [
78
78
  new Literal("a", "A"),
79
79
  new Literal("b", "B", true)
80
- ], true);
80
+ ]);
81
81
  const cursor = new Cursor("AD");
82
82
  const result = sequence.parse(cursor);
83
83
  const expected = new Node("and", "sequence", 0, 0, [
@@ -93,7 +93,7 @@ describe("And", () => {
93
93
  const sequence = new And("sequence", [
94
94
  new Literal("a", "A"),
95
95
  new Literal("b", "B", true)
96
- ], true);
96
+ ]);
97
97
  const cursor = new Cursor("A");
98
98
  const result = sequence.parse(cursor);
99
99
  const expected = new Node("and", "sequence", 0, 0, [
@@ -105,7 +105,7 @@ describe("And", () => {
105
105
  expect(cursor.index).toBe(0);
106
106
  });
107
107
 
108
- test("Incomplete Parse", () => {
108
+ test("Incomplete Parse (Optional)", () => {
109
109
  const sequence = new And("sequence", [
110
110
  new Literal("a", "A"),
111
111
  new Literal("b", "B")
@@ -175,6 +175,32 @@ describe("And", () => {
175
175
  expect(sequence.children[0].name).toBe("a");
176
176
  });
177
177
 
178
+ test("Exec", () => {
179
+ const sequence = new And("sequence", [new Literal("a", "A")]);
180
+
181
+ const { ast: result, cursor } = sequence.exec("A");
182
+ const expected = new Node("and", "sequence", 0, 0, [
183
+ new Node("literal", "a", 0, 0, undefined, "A")
184
+ ]);
185
+
186
+ expect(result).toEqual(expected)
187
+ expect(cursor).not.toBeNull();
188
+ });
189
+
190
+ test("Test With Match", () => {
191
+ const sequence = new And("sequence", [new Literal("a", "A")]);
192
+ const hasMatch = sequence.test("A");
193
+
194
+ expect(hasMatch).toBeTruthy();
195
+ });
196
+
197
+ test("Test With No Match", () => {
198
+ const sequence = new And("sequence", [new Literal("a", "A")]);
199
+ const hasMatch = sequence.test("B");
200
+
201
+ expect(hasMatch).toBeFalsy();
202
+ });
203
+
178
204
  test("Set Parent", () => {
179
205
  const a = new Literal("a", "A", true)
180
206
  const sequence = new And("sequence", [
@@ -186,33 +212,6 @@ describe("And", () => {
186
212
  expect(parent.children[0].type).toBe("and");
187
213
  });
188
214
 
189
- test("Reduce Ast", () => {
190
- const sequence = new And("sequence", [
191
- new Literal("a", "A"),
192
- ], true);
193
- sequence.enableAstReduction();
194
-
195
- const cursor = new Cursor("A");
196
- let result = sequence.parse(cursor);
197
- let expected = new Node("and", "sequence", 0, 0, [], "A");
198
-
199
- expect(result).toEqual(expected);
200
- expect(cursor.error).toBe(null)
201
- expect(cursor.index).toBe(0);
202
-
203
- sequence.disableAstReduction()
204
-
205
- cursor.moveTo(0)
206
- result = sequence.parse(cursor);
207
- expected = new Node("and", "sequence", 0, 0, [
208
- new Node("literal", "a", 0, 0, [], "A"),
209
- ]);
210
-
211
- expect(result).toEqual(expected);
212
- expect(cursor.error).toBe(null)
213
- expect(cursor.index).toBe(0);
214
- });
215
-
216
215
  test("Get Tokens", () => {
217
216
  const sequence = new And("sequence", [
218
217
  new Literal("a", "A", true),
@@ -224,76 +223,101 @@ describe("And", () => {
224
223
  expect(tokens).toEqual(expected);
225
224
  });
226
225
 
227
- test("Get Next Tokens", () => {
226
+ test("Get Tokens After", () => {
228
227
  const sequence = new And("sequence", [
229
228
  new Literal("a", "A"),
230
229
  new Literal("b", "B", true),
231
230
  new Literal("c", "C"),
232
231
  ], true);
233
232
 
234
- const tokens = sequence.getNextTokens(sequence.children[0])
233
+ const tokens = sequence.getTokensAfter(sequence.children[0])
235
234
  const expected = ["B", "C"];
236
235
 
237
236
  expect(tokens).toEqual(expected);
238
237
  });
239
238
 
240
- test("Get Next Tokens With Invalid Pattern", () => {
239
+ test("Get Tokens After With Invalid Pattern", () => {
241
240
  const sequence = new And("sequence", [
242
241
  new Literal("a", "A"),
243
242
  new Literal("b", "B", true),
244
243
  new Literal("c", "C"),
245
244
  ], true);
246
245
 
247
- const tokens = sequence.getNextTokens(new Literal("not-child", "not-child"))
246
+ const tokens = sequence.getTokensAfter(new Literal("not-child", "not-child"))
248
247
 
249
248
  expect(tokens).toEqual([]);
250
249
  });
251
250
 
252
- test("Get Next Tokens With Last Child", () => {
251
+ test("Get Tokens After With Last Child", () => {
253
252
  const sequence = new And("sequence", [
254
253
  new Literal("a", "A"),
255
254
  ], true);
256
255
  const parent = new And("parent", [sequence, new Literal("b", "B")]);
257
256
 
258
257
 
259
- const tokens = parent.children[0].getNextTokens(parent.children[0].children[0])
258
+ const tokens = parent.children[0].getTokensAfter(parent.children[0].children[0])
260
259
 
261
260
  expect(tokens).toEqual(["B"]);
262
261
  });
263
262
 
264
- test("Get Next Tokens With Last Optional Child", () => {
263
+ test("Get Tokens After With Last Optional Child", () => {
265
264
  const sequence = new And("sequence", [
266
265
  new Literal("a", "A"),
267
266
  new Literal("b", "B", true),
268
267
  ], true);
269
268
  const parent = new And("parent", [sequence, new Literal("c", "C")]);
270
269
 
271
-
272
- const tokens = parent.children[0].getNextTokens(parent.children[0].children[0])
270
+ const tokens = parent.children[0].getTokensAfter(parent.children[0].children[0])
273
271
 
274
272
  expect(tokens).toEqual(["B", "C"]);
275
273
  });
276
274
 
277
- test("Parse Text", () => {
275
+ test("Get Next Tokens", () => {
278
276
  const sequence = new And("sequence", [new Literal("a", "A")]);
279
- sequence.enableAstReduction();
277
+ const parent = new And("parent", [sequence, new Literal("b", "B")]);
280
278
 
281
- const { ast: result } = sequence.parseText("A");
282
- const expected = new Node("and", "sequence", 0, 0, [], "A");
279
+ const sequenceClone = parent.findPattern(p => p.name === "sequence");
280
+ const tokens = sequenceClone?.getNextTokens() || [];
283
281
 
284
- expect(result).toEqual(expected)
282
+ expect(tokens[0]).toBe("B");
283
+ });
284
+
285
+ test("Get Next Tokens With Null Parent", () => {
286
+ const sequence = new And("sequence", [new Literal("a", "A")]);
287
+ const tokens = sequence.getNextTokens();
288
+
289
+ expect(tokens.length).toBe(0);
285
290
  });
286
291
 
287
- test("Get Next Pattern", () => {
292
+ test("Get Patterns", () => {
288
293
  const sequence = new And("sequence", [
289
- new Literal("a", "A"),
290
- new Literal("b", "B", true),
294
+ new Literal("a", "A", true),
295
+ new Literal("b", "B"),
291
296
  ], true);
292
- const parent = new And("parent", [sequence, new Literal("c", "C")]);
297
+ const tokens = sequence.getPatterns();
298
+ const a = sequence.findPattern(p=>p.name === "a");
299
+ const b = sequence.findPattern(p=>p.name === "b");
300
+ const expected = [a, b]
293
301
 
302
+ expect(tokens).toEqual(expected);
303
+ });
294
304
 
295
- const nextPattern = parent.children[0].getNextPattern()
305
+ test("Get Next Patterns", () => {
306
+ const sequence = new And("sequence", [new Literal("a", "A")]);
307
+ const parent = new And("parent", [sequence, new Literal("b", "B")]);
308
+
309
+ const sequenceClone = parent.findPattern(p => p.name === "sequence");
310
+ const nextPatterns = sequenceClone?.getNextPatterns() || [];
311
+ const b = parent.findPattern(p => p.name === "b")
296
312
 
297
- expect(nextPattern?.name).toBe("c");
313
+ expect(nextPatterns[0]).toBe(b);
298
314
  });
315
+
316
+ test("Get Next Patterns With Null Parent", () => {
317
+ const sequence = new And("sequence", [new Literal("a", "A")]);
318
+ const nextPatterns = sequence.getNextPatterns()
319
+
320
+ expect(nextPatterns.length).toBe(0);
321
+ });
322
+
299
323
  });
@@ -3,7 +3,6 @@ import { Pattern } from "./Pattern";
3
3
  import { Node } from "../ast/Node";
4
4
  import { clonePatterns } from "./clonePatterns";
5
5
  import { filterOutNull } from "./filterOutNull";
6
- import { getNextPattern } from "./getNextPattern";
7
6
  import { findPattern } from "./findPattern";
8
7
 
9
8
  export class And implements Pattern {
@@ -14,7 +13,6 @@ export class And implements Pattern {
14
13
  private _isOptional: boolean;
15
14
  private _nodes: (Node | null)[];
16
15
  private _firstIndex: number;
17
- private _shouldReduceAst: boolean;
18
16
 
19
17
  get type(): string {
20
18
  return this._type;
@@ -54,7 +52,6 @@ export class And implements Pattern {
54
52
  this._parent = null;
55
53
  this._children = children;
56
54
  this._firstIndex = -1
57
- this._shouldReduceAst = false;
58
55
  this._nodes = [];
59
56
  }
60
57
 
@@ -64,12 +61,19 @@ export class And implements Pattern {
64
61
  }
65
62
  }
66
63
 
67
- parseText(text: string) {
64
+ test(text: string) {
68
65
  const cursor = new Cursor(text);
69
- const ast = this.parse(cursor)
66
+ const ast = this.parse(cursor);
67
+
68
+ return ast?.value === text;
69
+ }
70
+
71
+ exec(text: string) {
72
+ const cursor = new Cursor(text);
73
+ const ast = this.parse(cursor);
70
74
 
71
75
  return {
72
- ast,
76
+ ast: ast?.value === text ? ast : null,
73
77
  cursor
74
78
  };
75
79
  }
@@ -115,32 +119,41 @@ export class And implements Pattern {
115
119
  if (hasMorePatterns) {
116
120
  if (hadMatch) {
117
121
  if (cursor.hasNext()) {
122
+ // We had a match. Increment the cursor and use the next pattern.
118
123
  cursor.next();
119
124
  continue;
120
125
  } else {
126
+ // We are at the end of the text, it may still be valid, if all the
127
+ // following patterns are optional.
121
128
  if (this.areRemainingPatternsOptional(i)) {
122
129
  passed = true;
123
130
  break;
124
131
  }
125
132
 
133
+ // We didn't finish the parsing sequence.
126
134
  cursor.recordErrorAt(cursor.index + 1, this);
127
135
  break;
128
136
  }
129
137
  } else {
138
+ // An optional pattern did not matched, try from the same spot on the next
139
+ // pattern.
130
140
  cursor.moveTo(runningCursorIndex);
131
141
  continue;
132
142
  }
133
143
  } else {
144
+ // If we don't have any results from what we parsed then record error.
134
145
  const lastNode = this.getLastValidNode();
135
146
  if (lastNode === null) {
136
147
  cursor.recordErrorAt(cursor.index, this);
137
148
  break;
138
149
  }
139
150
 
151
+ // The sequence was parsed fully.
140
152
  passed = true;
141
153
  break;
142
154
  }
143
155
  } else {
156
+ // The pattern failed.
144
157
  cursor.moveTo(this._firstIndex);
145
158
  break;
146
159
  }
@@ -181,28 +194,15 @@ export class And implements Pattern {
181
194
 
182
195
  cursor.moveTo(lastIndex)
183
196
 
184
- if (this._shouldReduceAst) {
185
- children.length = 0;
186
- }
187
-
188
197
  return new Node(
189
198
  "and",
190
199
  this._name,
191
200
  this._firstIndex,
192
201
  lastIndex,
193
- children,
194
- this._shouldReduceAst ? value : undefined
202
+ children
195
203
  );
196
204
  }
197
205
 
198
- enableAstReduction(): void {
199
- this._shouldReduceAst = true;
200
- }
201
-
202
- disableAstReduction(): void {
203
- this._shouldReduceAst = false;
204
- }
205
-
206
206
  getTokens(): string[] {
207
207
  const tokens: string[] = [];
208
208
 
@@ -217,14 +217,45 @@ export class And implements Pattern {
217
217
  return tokens;
218
218
  }
219
219
 
220
- getNextTokens(lastMatched: Pattern): string[] {
220
+ getTokensAfter(childReference: Pattern): string[] {
221
+ const patterns = this.getPatternsAfter(childReference);
222
+ const tokens: string[] = [];
223
+
224
+ patterns.forEach(p => tokens.push(...p.getTokens()));
225
+
226
+ return tokens;
227
+ }
228
+
229
+ getNextTokens(): string[] {
230
+ if (this.parent == null) {
231
+ return []
232
+ }
233
+
234
+ return this.parent.getTokensAfter(this);
235
+ }
236
+
237
+ getPatterns(): Pattern[] {
238
+ const patterns: Pattern[] = [];
239
+
240
+ for (const pattern of this._children) {
241
+ patterns.push(...pattern.getPatterns());
242
+
243
+ if (!pattern.isOptional) {
244
+ break;
245
+ }
246
+ }
247
+
248
+ return patterns;
249
+ }
250
+
251
+ getPatternsAfter(childReference: Pattern): Pattern[] {
221
252
  let nextSibling: Pattern | null = null;
222
253
  let nextSiblingIndex = -1;
223
254
  let index = -1;
224
- const tokens: string[] = [];
255
+ const patterns: Pattern[] = [];
225
256
 
226
257
  for (let i = 0; i < this._children.length; i++) {
227
- if (this._children[i] === lastMatched) {
258
+ if (this._children[i] === childReference) {
228
259
  if (i + 1 < this._children.length) {
229
260
  nextSibling = this._children[i + 1];
230
261
  }
@@ -234,48 +265,53 @@ export class And implements Pattern {
234
265
  }
235
266
  }
236
267
 
268
+ // The child reference isn't one of the child patterns.
237
269
  if (index === -1) {
238
270
  return [];
239
271
  }
240
272
 
273
+ // The reference pattern is the last child. So ask the parent for the next pattern.
241
274
  if (nextSiblingIndex === this._children.length && this._parent !== null) {
242
- return this._parent.getNextTokens(this);
275
+ return this._parent.getPatternsAfter(this);
243
276
  }
244
277
 
278
+ // Next pattern isn't optional so send it back as the next patterns.
245
279
  if (nextSibling !== null && !nextSibling.isOptional) {
246
- return nextSibling.getTokens();
280
+ return [nextSibling];
247
281
  }
248
282
 
283
+ // Send back as many optional patterns as possible.
249
284
  if (nextSibling !== null && nextSibling.isOptional) {
250
285
  for (let i = nextSiblingIndex; i < this._children.length; i++) {
251
286
  const child = this._children[i];
252
- tokens.push(...child.getTokens());
287
+ patterns.push(child);
253
288
 
254
289
  if (!child.isOptional) {
255
290
  break;
256
291
  }
257
292
 
258
293
  if (i === this._children.length - 1 && this._parent !== null) {
259
- tokens.push(...this._parent.getNextTokens(this));
294
+ patterns.push(...this._parent.getPatternsAfter(this));
260
295
  }
261
296
  }
262
297
  }
263
298
 
264
- return tokens;
299
+ return patterns;
265
300
  }
266
301
 
267
- getNextPattern(): Pattern | null {
268
- return getNextPattern(this)
302
+ getNextPatterns(): Pattern[] {
303
+ if (this.parent == null) {
304
+ return [];
305
+ }
306
+
307
+ return this.parent.getPatternsAfter(this)
269
308
  }
270
309
 
271
- findPattern(isMatch: (p: Pattern)=>boolean): Pattern | null{
272
- return findPattern(this, isMatch);
310
+ findPattern(predicate: (p: Pattern) => boolean): Pattern | null {
311
+ return findPattern(this, predicate);
273
312
  }
274
313
 
275
314
  clone(name = this._name, isOptional = this._isOptional): Pattern {
276
- const and = new And(name, this._children, isOptional)
277
- and._shouldReduceAst = this._shouldReduceAst;
278
-
279
- return and
315
+ return new And(name, this._children, isOptional)
280
316
  }
281
317
  }
@@ -1,5 +1,7 @@
1
- import { Pattern, Node, ParseError } from "..";
1
+ import { Node } from "../ast/Node";
2
2
  import { CursorHistory, Match } from "./CursorHistory";
3
+ import { ParseError } from "./ParseError";
4
+ import { Pattern } from "./Pattern";
3
5
 
4
6
  export class Cursor {
5
7
  private _text: string;
@@ -16,21 +18,21 @@ export class Cursor {
16
18
  }
17
19
 
18
20
  get isOnLast(): boolean {
19
- return this._index === this._getLastIndex();
21
+ return this._index === this.getLastIndex();
20
22
  }
21
23
 
22
24
  get isRecording(): boolean {
23
25
  return this._history.isRecording;
24
26
  }
25
27
 
26
- get leafMatch(): Match {
27
- return this._history.leafMatch;
28
- }
29
-
30
28
  get rootMatch(): Match {
31
29
  return this._history.rootMatch;
32
30
  }
33
31
 
32
+ get leafMatch(): Match {
33
+ return this._history.leafMatch;
34
+ }
35
+
34
36
  get furthestError(): ParseError | null {
35
37
  return this._history.furthestError;
36
38
  }
@@ -70,16 +72,16 @@ export class Cursor {
70
72
  return this._index + 1 < this._length;
71
73
  }
72
74
 
73
- hasPrevious(): boolean {
74
- return this._index - 1 >= 0;
75
- }
76
-
77
75
  next(): void {
78
76
  if (this.hasNext()) {
79
77
  this._index++;
80
78
  }
81
79
  }
82
80
 
81
+ hasPrevious(): boolean {
82
+ return this._index - 1 >= 0;
83
+ }
84
+
83
85
  previous(): void {
84
86
  if (this.hasPrevious()) {
85
87
  this._index--;
@@ -97,7 +99,11 @@ export class Cursor {
97
99
  }
98
100
 
99
101
  moveToLastChar(): void {
100
- this._index = this._getLastIndex();
102
+ this._index = this.getLastIndex();
103
+ }
104
+
105
+ getLastIndex(): number {
106
+ return this._length - 1;
101
107
  }
102
108
 
103
109
  getChars(first: number, last: number): string {
@@ -124,7 +130,4 @@ export class Cursor {
124
130
  this._history.stopRecording();
125
131
  }
126
132
 
127
- private _getLastIndex(): number {
128
- return this._length - 1;
129
- }
130
133
  }
@@ -17,6 +17,14 @@ export class CursorHistory {
17
17
  private _nodes: Node[] = [];
18
18
  private _errors: ParseError[] = [];
19
19
 
20
+ get isRecording(): boolean {
21
+ return this._isRecording;
22
+ }
23
+
24
+ get rootMatch(): Match {
25
+ return this._rootMatch;
26
+ }
27
+
20
28
  get leafMatch(): Match {
21
29
  return this._leafMatch;
22
30
  }
@@ -25,10 +33,6 @@ export class CursorHistory {
25
33
  return this._furthestError;
26
34
  }
27
35
 
28
- get isRecording(): boolean {
29
- return this._isRecording;
30
- }
31
-
32
36
  get errors(): ParseError[] {
33
37
  return this._errors;
34
38
  }
@@ -45,10 +49,6 @@ export class CursorHistory {
45
49
  return this._patterns;
46
50
  }
47
51
 
48
- get rootMatch(): Match {
49
- return this._rootMatch;
50
- }
51
-
52
52
  recordMatch(pattern: Pattern, node: Node): void {
53
53
  if (this._isRecording) {
54
54
  this._patterns.push(pattern);