clarity-pattern-parser 10.3.7 → 11.0.1

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 (51) hide show
  1. package/dist/ast/Node.d.ts +2 -2
  2. package/dist/ast/compact.d.ts +2 -0
  3. package/dist/ast/remove.d.ts +2 -0
  4. package/dist/index.browser.js +418 -487
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.d.ts +3 -1
  7. package/dist/index.esm.js +417 -488
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.js +418 -487
  10. package/dist/index.js.map +1 -1
  11. package/dist/patterns/ExpressionPattern.d.ts +27 -25
  12. package/dist/patterns/FiniteRepeat.d.ts +1 -2
  13. package/dist/patterns/InfiniteRepeat.d.ts +1 -2
  14. package/dist/patterns/Literal.d.ts +0 -1
  15. package/dist/patterns/Not.d.ts +1 -2
  16. package/dist/patterns/Optional.d.ts +0 -1
  17. package/dist/patterns/Options.d.ts +1 -2
  18. package/dist/patterns/Pattern.d.ts +0 -1
  19. package/dist/patterns/PrecedenceTree.d.ts +28 -0
  20. package/dist/patterns/Reference.d.ts +1 -2
  21. package/dist/patterns/Regex.d.ts +1 -2
  22. package/dist/patterns/Repeat.d.ts +0 -3
  23. package/dist/patterns/Sequence.d.ts +3 -6
  24. package/dist/patterns/execPattern.d.ts +3 -0
  25. package/dist/patterns/testPattern.d.ts +2 -0
  26. package/package.json +1 -1
  27. package/src/ast/Node.test.ts +17 -17
  28. package/src/ast/Node.ts +7 -5
  29. package/src/ast/compact.ts +11 -0
  30. package/src/ast/remove.ts +11 -0
  31. package/src/grammar/Grammar.test.ts +0 -50
  32. package/src/grammar/Grammar.ts +0 -20
  33. package/src/grammar/patterns/statement.ts +1 -6
  34. package/src/index.ts +4 -0
  35. package/src/patterns/ExpressionPattern.test.ts +1 -1
  36. package/src/patterns/ExpressionPattern.ts +236 -384
  37. package/src/patterns/FiniteRepeat.ts +5 -22
  38. package/src/patterns/InfiniteRepeat.ts +6 -21
  39. package/src/patterns/Literal.ts +5 -19
  40. package/src/patterns/Not.ts +5 -16
  41. package/src/patterns/Optional.ts +0 -7
  42. package/src/patterns/Options.ts +5 -21
  43. package/src/patterns/Pattern.ts +0 -1
  44. package/src/patterns/PrecedenceTree.test.ts +162 -0
  45. package/src/patterns/PrecedenceTree.ts +207 -0
  46. package/src/patterns/Reference.ts +5 -17
  47. package/src/patterns/Regex.ts +5 -17
  48. package/src/patterns/Repeat.ts +1 -13
  49. package/src/patterns/Sequence.ts +7 -22
  50. package/src/patterns/execPattern.ts +16 -0
  51. package/src/patterns/testPattern.ts +11 -0
@@ -4,18 +4,12 @@ import { ParseResult } from "./ParseResult";
4
4
  import { Pattern } from "./Pattern";
5
5
  import { findPattern } from "./findPattern";
6
6
  import { Sequence } from "./Sequence";
7
+ import { Association, PrecedenceTree } from './PrecedenceTree';
8
+ import { testPattern } from "./testPattern";
9
+ import { execPattern } from "./execPattern";
7
10
 
8
11
  let indexId = 0;
9
12
 
10
- function createNode(name: string, children: Node[]) {
11
- return new Node("expression", name, 0, 0, children, "");
12
- }
13
-
14
- enum Association {
15
- left = 0,
16
- right = 1,
17
- }
18
-
19
13
  export class ExpressionPattern implements Pattern {
20
14
  private _id: string;
21
15
  private _type: string;
@@ -25,18 +19,16 @@ export class ExpressionPattern implements Pattern {
25
19
  private _originalPatterns: Pattern[];
26
20
  private _patterns: Pattern[];
27
21
  private _atomPatterns: Pattern[];
28
- private _unaryPrefixPatterns: Pattern[];
29
- private _unaryPrefixNames: string[];
22
+ private _prefixPatterns: Pattern[];
23
+ private _prefixNames: string[];
24
+ private _postfixPatterns: Pattern[];
25
+ private _postfixNames: string[];
30
26
  private _binaryPatterns: Pattern[];
31
- private _recursivePatterns: Pattern[];
32
- private _recursiveNames: string[];
33
- private _endsInRecursion: boolean[];
34
- private _binaryAssociation: Association[];
35
- private _precedenceMap: Record<string, number>;
36
27
  private _binaryNames: string[];
37
- private _shouldCompactPatternsMap: Record<string, boolean>;
38
-
39
- shouldCompactAst = false;
28
+ private associationMap: Record<string, Association>;
29
+ private _precedenceMap: Record<string, number>;
30
+ private _shouldStopParsing: boolean;
31
+ private _precedenceTree: PrecedenceTree;
40
32
 
41
33
  get id(): string {
42
34
  return this._id;
@@ -62,20 +54,20 @@ export class ExpressionPattern implements Pattern {
62
54
  return this._patterns;
63
55
  }
64
56
 
65
- get unaryPrefixPatterns(): readonly Pattern[] {
66
- return this._unaryPrefixPatterns;
57
+ get prefixPatterns(): readonly Pattern[] {
58
+ return this._prefixPatterns;
67
59
  }
68
60
 
69
61
  get atomPatterns(): readonly Pattern[] {
70
62
  return this._atomPatterns;
71
63
  }
72
64
 
73
- get binaryPatterns(): readonly Pattern[] {
74
- return this._binaryPatterns;
65
+ get postfixPatterns(): readonly Pattern[] {
66
+ return this._postfixPatterns;
75
67
  }
76
68
 
77
- get recursivePatterns(): readonly Pattern[] {
78
- return this._recursivePatterns;
69
+ get binaryPatterns(): readonly Pattern[] {
70
+ return this._binaryPatterns;
79
71
  }
80
72
 
81
73
  get startedOnIndex() {
@@ -93,67 +85,69 @@ export class ExpressionPattern implements Pattern {
93
85
  this._parent = null;
94
86
  this._firstIndex = -1;
95
87
  this._atomPatterns = [];
96
- this._unaryPrefixPatterns = [];
97
- this._unaryPrefixNames = [];
88
+ this._prefixPatterns = [];
89
+ this._prefixNames = [];
90
+ this._postfixPatterns = [];
91
+ this._postfixNames = [];
98
92
  this._binaryPatterns = [];
99
- this._recursivePatterns = [];
100
- this._recursiveNames = [];
101
- this._endsInRecursion = [];
102
93
  this._binaryNames = [];
103
- this._binaryAssociation = [];
94
+ this.associationMap = {};
104
95
  this._precedenceMap = {};
105
96
  this._originalPatterns = patterns;
106
- this._shouldCompactPatternsMap = {};
107
97
  this._patterns = this._organizePatterns(patterns);
98
+ this._shouldStopParsing = false;
99
+ this._precedenceTree = new PrecedenceTree(this._precedenceMap, this.associationMap);
108
100
 
109
101
  if (this._atomPatterns.length === 0) {
110
- throw new Error("Need at least one operand pattern with an 'expression' pattern.");
102
+ throw new Error("Need at least one terminating pattern with an 'expression' pattern.");
111
103
  }
112
104
  }
113
105
 
114
106
  private _organizePatterns(patterns: Pattern[]) {
115
107
  const finalPatterns: Pattern[] = [];
116
108
  patterns.forEach((pattern) => {
117
- this._shouldCompactPatternsMap[pattern.name] = pattern.shouldCompactAst;
118
109
 
119
- if (this._isUnary(pattern)) {
120
- const unaryPrefix = this._extractUnaryPrefixPattern(pattern).clone();
121
- this._unaryPrefixPatterns.push(unaryPrefix);
122
- this._unaryPrefixNames.push(pattern.name);
123
- unaryPrefix.parent = this;
110
+ if (this._isAtom(pattern)) {
111
+ const atom = pattern.clone();
112
+ atom.parent = this;
124
113
 
125
- finalPatterns.push(unaryPrefix);
114
+ this._atomPatterns.push(atom);
115
+
116
+ finalPatterns.push(atom);
117
+ } else if (this._isPrefix(pattern)) {
118
+ const name = this._extractName(pattern);
119
+ const prefix = this._extractPrefix(pattern);
120
+
121
+ prefix.parent = this;
122
+
123
+ this._prefixPatterns.push(prefix);
124
+ this._prefixNames.push(name);
125
+
126
+ finalPatterns.push(prefix);
127
+ } else if (this._isPostfix(pattern)) {
128
+ const name = this._extractName(pattern);
129
+ const postfix = this._extractPostfix(pattern);
130
+ postfix.parent = this;
131
+
132
+ this._postfixPatterns.push(postfix);
133
+ this._postfixNames.push(name);
134
+
135
+ finalPatterns.push(postfix);
126
136
  } else if (this._isBinary(pattern)) {
127
- const binaryName = this._extractName(pattern);
128
- const clone = this._extractDelimiter(pattern).clone();
137
+ const name = this._extractName(pattern);
138
+ const clone = this._extractBinary(pattern);
129
139
  clone.parent = this;
130
140
 
131
- this._precedenceMap[binaryName] = this._binaryPatterns.length;
141
+ this._precedenceMap[name] = this._binaryPatterns.length;
132
142
  this._binaryPatterns.push(clone);
133
- this._binaryNames.push(binaryName);
143
+ this._binaryNames.push(name);
134
144
 
135
145
  if (pattern.type === "right-associated") {
136
- this._binaryAssociation.push(Association.right);
146
+ this.associationMap[name] = Association.right;
137
147
  } else {
138
- this._binaryAssociation.push(Association.left);
148
+ this.associationMap[name] = Association.left;
139
149
  }
140
150
 
141
- finalPatterns.push(clone);
142
- } else if (this._isRecursive(pattern)) {
143
- const name = this._extractName(pattern);
144
- const tail = this._extractRecursiveTail(pattern);
145
-
146
- tail.parent = this;
147
-
148
- this._recursivePatterns.push(tail);
149
- this._recursiveNames.push(name);
150
- this._endsInRecursion.push(this._endsWithRecursion(pattern));
151
- finalPatterns.push(tail);
152
- } else {
153
- const clone = pattern.clone();
154
- clone.parent = this;
155
-
156
- this._atomPatterns.push(clone);
157
151
  finalPatterns.push(clone);
158
152
  }
159
153
  });
@@ -161,95 +155,93 @@ export class ExpressionPattern implements Pattern {
161
155
  return finalPatterns;
162
156
  }
163
157
 
164
- private _isBinary(pattern: Pattern) {
165
- if (pattern.type === "right-associated" && this._isBinaryPattern(pattern.children[0])) {
166
- return true;
158
+ private _extractName(pattern: Pattern) {
159
+ if (pattern.type === "right-associated") {
160
+ return pattern.children[0].name;
167
161
  }
168
162
 
169
- return this._isBinaryPattern(pattern);
163
+ return pattern.name;
170
164
  }
171
165
 
172
- private _isBinaryPattern(pattern: Pattern) {
173
- return pattern.type === "sequence" &&
174
- pattern.children.length === 3 &&
175
- pattern.children[0].type === "reference" &&
176
- pattern.children[0].name === this.name &&
177
- pattern.children[2].type === "reference" &&
178
- pattern.children[2].name === this.name;
166
+ private _isPrefix(pattern: Pattern) {
167
+ pattern = this._unwrapAssociationIfNecessary(pattern);
168
+
169
+ const lastChild = pattern.children[pattern.children.length - 1];
170
+ const referenceCount = this._referenceCount(pattern);
171
+ const lastChildIsReference = this._isRecursiveReference(lastChild);
172
+
173
+ return lastChildIsReference &&
174
+ referenceCount === 1;
179
175
  }
180
176
 
181
- private _extractDelimiter(pattern: Pattern) {
182
- if (pattern.type === "right-associated") {
183
- return pattern.children[0].children[1];
184
- }
185
- return pattern.children[1];
177
+ private _extractPrefix(pattern: Pattern) {
178
+ pattern = this._unwrapAssociationIfNecessary(pattern);
179
+ return new Sequence(`${pattern.name}-prefix`, pattern.children.slice(0, -1));
186
180
  }
187
181
 
188
- private _extractName(pattern: Pattern) {
189
- if (pattern.type === "right-associated") {
190
- return pattern.children[0].name;
191
- }
182
+ private _isAtom(pattern: Pattern) {
183
+ pattern = this._unwrapAssociationIfNecessary(pattern);
192
184
 
193
- return pattern.name;
185
+ const firstChild = pattern.children[0];
186
+ const lastChild = pattern.children[1];
187
+ const firstChildIsReference = this._isRecursiveReference(firstChild);
188
+ const lastChildIsReference = this._isRecursiveReference(lastChild);
189
+
190
+ return !firstChildIsReference && !lastChildIsReference;
194
191
  }
195
192
 
196
- private _isUnary(pattern: Pattern) {
197
- if (pattern.type === "right-associated" && this._isUnaryPattern(pattern.children[0])) {
198
- return true;
199
- }
193
+ private _isPostfix(pattern: Pattern) {
194
+ pattern = this._unwrapAssociationIfNecessary(pattern);
200
195
 
201
- return this._isUnaryPattern(pattern);
202
- }
196
+ const firstChild = pattern.children[0];
197
+ const referenceCount = this._referenceCount(pattern);
198
+ const firstChildIsReference = this._isRecursiveReference(firstChild);
203
199
 
204
- private _isUnaryPattern(pattern: Pattern) {
205
- return pattern.type === "sequence" &&
206
- pattern.children[0].type !== "reference" &&
207
- pattern.children[0].name !== this.name &&
208
- pattern.children[1].type === "reference" &&
209
- pattern.children[1].name === this.name &&
210
- pattern.children.length === 2;
200
+ return firstChildIsReference &&
201
+ referenceCount === 1;
211
202
  }
212
203
 
213
- private _extractUnaryPrefixPattern(pattern: Pattern) {
214
- if (pattern.type === "right-associated") {
215
- return pattern.children[0].children[0];
216
- }
217
-
218
- return pattern.children[0];
204
+ private _extractPostfix(pattern: Pattern) {
205
+ pattern = this._unwrapAssociationIfNecessary(pattern);
206
+ return new Sequence(`${pattern.name}-postfix`, pattern.children.slice(1));
219
207
  }
220
208
 
221
- private _isRecursive(pattern: Pattern) {
222
- if (pattern.type === "right-associated" && this._isRecursivePattern(pattern.children[0])) {
223
- return true;
224
- }
209
+ private _isBinary(pattern: Pattern) {
210
+ pattern = this._unwrapAssociationIfNecessary(pattern);
211
+
212
+ const firstChild = pattern.children[0];
213
+ const lastChild = pattern.children[pattern.children.length - 1];
214
+ const firstChildIsReference = this._isRecursiveReference(firstChild);
215
+ const lastChildIsReference = this._isRecursiveReference(lastChild);
225
216
 
226
- return this._isRecursivePattern(pattern);
217
+ return firstChildIsReference && lastChildIsReference && pattern.children.length > 2;
227
218
  }
228
219
 
229
- private _isRecursivePattern(pattern: Pattern) {
230
- return pattern.type === "sequence" &&
231
- pattern.children[0].type === "reference" &&
232
- pattern.children[0].name === this.name &&
233
- pattern.children.length > 2;
220
+ private _extractBinary(pattern: Pattern) {
221
+ pattern = this._unwrapAssociationIfNecessary(pattern);
222
+ const children = pattern.children.slice(1, -1);
223
+ const binarySequence = new Sequence(`${pattern.name}-delimiter`, children);
224
+
225
+ return binarySequence;
234
226
  }
235
227
 
236
- private _extractRecursiveTail(pattern: Pattern) {
228
+ private _unwrapAssociationIfNecessary(pattern: Pattern) {
237
229
  if (pattern.type === "right-associated") {
238
- return new Sequence(`${pattern.children[0].name}-tail`, pattern.children[0].children.slice(1));
230
+ return pattern.children[0];
239
231
  }
240
- return new Sequence(`${pattern.name}-tail`, pattern.children.slice(1));
232
+
233
+ return pattern;
241
234
  }
242
235
 
243
- private _endsWithRecursion(pattern: Pattern) {
244
- if (pattern.type === "right-associated") {
245
- pattern = pattern.children[0];
246
- }
236
+ private _referenceCount(pattern: Pattern) {
237
+ return pattern.children.filter(p => this._isRecursiveReference(p)).length;
238
+ }
247
239
 
248
- const lastChild = pattern.children[pattern.children.length - 1];
249
- return pattern.type === "sequence" &&
250
- pattern.children.length > 1 &&
251
- lastChild.type === "reference" &&
252
- lastChild.name === this.name;
240
+ private _isRecursiveReference(pattern: Pattern) {
241
+ if (pattern == null){
242
+ return false;
243
+ }
244
+ return pattern.type === "reference" && pattern.name === this.name;
253
245
  }
254
246
 
255
247
  parse(cursor: Cursor): Node | null {
@@ -261,35 +253,14 @@ export class ExpressionPattern implements Pattern {
261
253
 
262
254
  cursor.moveTo(node.lastIndex);
263
255
  cursor.resolveError();
264
- this._compactResult(node);
265
256
  return node;
266
257
  }
267
258
 
259
+ cursor.moveTo(this._firstIndex);
268
260
  cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
269
261
  return null;
270
262
  }
271
263
 
272
- private _compactResult(node: Node | null) {
273
- if (node == null) {
274
- return;
275
- }
276
-
277
- if (this.shouldCompactAst) {
278
- node.compact();
279
- return;
280
- }
281
-
282
- // This could be really expensive with large trees. So we optimize with these checks,
283
- // as well as use breadth first as to not recompact nodes over and over again.
284
- const isCompactingNeeded = Object.values(this._shouldCompactPatternsMap).some(p => p);
285
- if (isCompactingNeeded) {
286
- node.walkBreadthFirst(n => {
287
- if (this._shouldCompactPatternsMap[n.name]) {
288
- n.compact();
289
- }
290
- });
291
- }
292
- }
293
264
 
294
265
  private _tryToParse(cursor: Cursor): Node | null {
295
266
  if (this._isBeyondRecursiveAllowance()) {
@@ -297,228 +268,165 @@ export class ExpressionPattern implements Pattern {
297
268
  return null;
298
269
  }
299
270
 
300
- let lastAtomNode: Node | null = null;
301
- let lastBinaryNode: Node | null = null;
302
- let onIndex = cursor.index;
271
+ this._shouldStopParsing = false;
303
272
 
304
- outer: while (true) {
273
+ while (true) {
305
274
  cursor.resolveError();
306
- onIndex = cursor.index;
307
-
308
- let prefix: Node | null = null;
309
- let prefixName = "";
310
- for (let i = 0; i < this._unaryPrefixPatterns.length; i++) {
311
- cursor.moveTo(onIndex);
312
- const pattern = this._unaryPrefixPatterns[i];
313
- const node = pattern.parse(cursor);
314
-
315
- if (node != null) {
316
- prefix = node;
317
- prefixName = this._unaryPrefixNames[i];
318
275
 
319
- if (cursor.hasNext()) {
320
- cursor.next();
321
- } else {
322
- break outer;
323
- }
276
+ this._tryToMatchPrefix(cursor);
324
277
 
325
- break;
326
- } else {
327
- cursor.resolveError();
328
- }
278
+ if (this._shouldStopParsing) {
279
+ break;
329
280
  }
330
281
 
331
- onIndex = cursor.index;
332
- for (let i = 0; i < this._atomPatterns.length; i++) {
333
- cursor.moveTo(onIndex);
334
- const pattern = this._atomPatterns[i];
335
- const node = pattern.parse(cursor);
282
+ this._tryToMatchAtom(cursor);
336
283
 
337
- if (node != null) {
338
- lastAtomNode = node;
339
-
340
- break;
341
- } else {
342
- lastAtomNode = null;
343
- cursor.resolveError();
344
- }
284
+ if (this._shouldStopParsing) {
285
+ break;
345
286
  }
346
287
 
347
- if (lastAtomNode == null) {
288
+ this._tryToMatchPostfix(cursor);
289
+
290
+ if (this._shouldStopParsing) {
348
291
  break;
349
292
  }
350
293
 
351
- if (cursor.hasNext()) {
352
- cursor.next();
353
- } else {
354
- if (lastBinaryNode != null && lastAtomNode != null) {
355
- if (prefix != null) {
356
- lastAtomNode = createNode(prefixName, [prefix, lastAtomNode]);
357
- }
358
- lastBinaryNode.appendChild(lastAtomNode);
294
+ if (this._precedenceTree.hasAtom()) {
295
+ this._tryToMatchBinary(cursor);
296
+
297
+ if (this._shouldStopParsing) {
298
+ break;
359
299
  }
300
+ } else {
360
301
  break;
361
302
  }
303
+ }
362
304
 
363
- onIndex = cursor.index;
305
+ return this._precedenceTree.commit();
306
+ }
364
307
 
365
- if (prefix != null && this._recursivePatterns.length === 0) {
366
- lastAtomNode = createNode(prefixName, [prefix, lastAtomNode]);
367
- }
308
+ private _tryToMatchPrefix(cursor: Cursor) {
309
+ let onIndex = cursor.index;
310
+
311
+ for (let i = 0; i < this._prefixPatterns.length; i++) {
312
+ const pattern = this._prefixPatterns[i];
313
+ const name = this._prefixNames[i];
314
+ const node = pattern.parse(cursor);
315
+
316
+ if (node != null) {
317
+ this._precedenceTree.addPrefix(name, ...node.children);
368
318
 
369
- for (let i = 0; i < this._recursivePatterns.length; i++) {
370
- const pattern = this._recursivePatterns[i];
371
- const node = pattern.parse(cursor);
372
-
373
- if (node != null) {
374
- const name = this._recursiveNames[i];
375
-
376
- if (this._endsInRecursion[i]) {
377
- if (lastBinaryNode != null && lastAtomNode != null) {
378
- if (prefix != null) {
379
- lastAtomNode = createNode(prefixName, [prefix, lastAtomNode]);
380
- }
381
- lastBinaryNode.appendChild(lastAtomNode);
382
- }
383
-
384
- const frontExpression = lastBinaryNode == null ? lastAtomNode as Node : lastBinaryNode.findRoot();
385
- const recursiveNode = createNode(name, [frontExpression, ...node.children]);
386
-
387
-
388
- return recursiveNode;
389
- } else {
390
- if (prefix != null) {
391
- lastAtomNode = createNode(prefixName, [prefix, lastAtomNode]);
392
- }
393
-
394
- const recursiveNode = createNode(name, [lastAtomNode, ...node.children]);
395
- lastAtomNode = recursiveNode;
396
-
397
- if (cursor.hasNext()) {
398
- cursor.next();
399
- } else {
400
- if (lastBinaryNode != null && lastAtomNode != null) {
401
- lastBinaryNode.appendChild(lastAtomNode);
402
- }
403
- break outer;
404
- }
405
- onIndex = cursor.index;
406
- i = -1;
407
- continue;
408
- }
319
+ if (cursor.hasNext()) {
320
+ cursor.next();
321
+ onIndex = cursor.index;
322
+ i = -1;
323
+
324
+ continue;
325
+ } else {
326
+ this._shouldStopParsing = true;
327
+ break;
409
328
  }
410
329
 
411
- cursor.resolveError();
330
+ } else {
412
331
  cursor.moveTo(onIndex);
332
+ cursor.resolveError();
413
333
  }
334
+ }
335
+ }
414
336
 
415
- onIndex = cursor.index;
416
- for (let i = 0; i < this._binaryPatterns.length; i++) {
417
- cursor.resolveError();
418
- cursor.moveTo(onIndex);
337
+ private _tryToMatchAtom(cursor: Cursor) {
338
+ let onIndex = cursor.index;
419
339
 
420
- const pattern = this._binaryPatterns[i];
421
- const name = this._binaryNames[i];
422
- const delimiterNode = pattern.parse(cursor);
423
-
424
- if (delimiterNode == null) {
425
- if (i === this._binaryPatterns.length - 1) {
426
- if (lastBinaryNode == null) {
427
- return lastAtomNode;
428
- } else if (lastAtomNode != null) {
429
- lastBinaryNode.appendChild(lastAtomNode);
430
- }
431
- }
432
- continue;
433
- }
340
+ for (let i = 0; i < this._atomPatterns.length; i++) {
341
+ cursor.moveTo(onIndex);
434
342
 
435
- if (lastBinaryNode == null && lastAtomNode != null && delimiterNode != null) {
436
- const node = createNode(name, [lastAtomNode, delimiterNode]);
437
- lastBinaryNode = node;
438
- } else if (lastBinaryNode != null && lastAtomNode != null && delimiterNode != null) {
439
- const precedence = this._precedenceMap[name];
440
- const lastPrecendece = lastBinaryNode == null ? 0 : this._precedenceMap[lastBinaryNode.name] == null ? -1 : this._precedenceMap[lastBinaryNode.name];
441
- const association = this._binaryAssociation[i];
442
-
443
- if (precedence === lastPrecendece && association === Association.right) {
444
- const node = createNode(name, [lastAtomNode, delimiterNode]);
445
- lastBinaryNode.appendChild(node);
446
-
447
- lastBinaryNode = node;
448
- } else if (precedence === lastPrecendece) {
449
- const node = createNode(name, []);
450
-
451
- lastBinaryNode.replaceWith(node);
452
- lastBinaryNode.appendChild(lastAtomNode);
453
-
454
- node.append(lastBinaryNode, delimiterNode);
455
- lastBinaryNode = node;
456
- } else if (precedence > lastPrecendece) {
457
- let ancestor = lastBinaryNode.parent;
458
- let root: Node | null = lastBinaryNode;
459
-
460
- while (ancestor != null) {
461
- const nodePrecedence = this._precedenceMap[ancestor.name];
462
-
463
- if (nodePrecedence > precedence) {
464
- break;
465
- }
466
- root = ancestor;
467
- ancestor = ancestor.parent;
468
- }
469
-
470
- lastBinaryNode.appendChild(lastAtomNode);
471
-
472
- if (root != null) {
473
- const node = createNode(name, []);
474
- root.replaceWith(node);
475
- node.append(root, delimiterNode);
476
-
477
- lastBinaryNode = node;
478
- } else {
479
- const node = createNode(name, [lastAtomNode, delimiterNode]);
480
- lastBinaryNode = node;
481
- }
482
-
483
- } else {
484
- const node = createNode(name, [lastAtomNode, delimiterNode]);
485
- lastBinaryNode.appendChild(node);
486
-
487
- lastBinaryNode = node;
488
- }
343
+ const pattern = this._atomPatterns[i];
344
+ const node = pattern.parse(cursor);
489
345
 
490
- }
346
+ if (node != null) {
347
+ this._precedenceTree.addAtom(node);
491
348
 
492
349
  if (cursor.hasNext()) {
493
350
  cursor.next();
494
351
  } else {
495
- break outer;
352
+ this._shouldStopParsing = true;
496
353
  }
497
354
 
498
355
  break;
356
+ } else {
357
+ cursor.resolveError();
358
+ cursor.moveTo(onIndex);
499
359
  }
360
+ }
361
+ }
500
362
 
501
- if (lastBinaryNode == null) {
502
- break;
363
+ private _tryToMatchPostfix(cursor: Cursor) {
364
+ let onIndex = cursor.index;
365
+
366
+ for (let i = 0; i < this._postfixPatterns.length; i++) {
367
+ const pattern = this._postfixPatterns[i];
368
+ const name = this._postfixNames[i];
369
+ const node = pattern.parse(cursor);
370
+
371
+ if (node != null) {
372
+ this._precedenceTree.addPostfix(name, ...node.children);
373
+
374
+ if (cursor.hasNext()) {
375
+ cursor.next();
376
+ onIndex = cursor.index;
377
+ i = -1;
378
+
379
+ continue;
380
+ } else {
381
+ this._shouldStopParsing = true;
382
+ break;
383
+ }
384
+
385
+ } else {
386
+ cursor.moveTo(onIndex);
387
+ cursor.resolveError();
503
388
  }
504
389
  }
390
+ }
505
391
 
506
- if (lastBinaryNode == null) {
507
- return lastAtomNode;
508
- } else {
509
- const root = lastBinaryNode.findAncestor(n => n.parent == null) as Node || lastBinaryNode;
510
- if (lastBinaryNode.children.length < 3) {
511
- lastBinaryNode.remove();
392
+ private _tryToMatchBinary(cursor: Cursor) {
393
+ let onIndex = cursor.index;
394
+ let foundMatch = false;
395
+
396
+ if (this.binaryPatterns.length === 0) {
397
+ this._shouldStopParsing = true;
398
+ }
512
399
 
513
- if (lastBinaryNode === root) {
514
- return lastAtomNode;
400
+ for (let i = 0; i < this._binaryPatterns.length; i++) {
401
+ cursor.moveTo(onIndex);
402
+
403
+ const pattern = this._binaryPatterns[i];
404
+ const name = this._binaryNames[i];
405
+ const node = pattern.parse(cursor);
406
+
407
+ if (node != null) {
408
+ foundMatch = true;
409
+ this._precedenceTree.addBinary(name, ...node.children);
410
+
411
+ if (cursor.hasNext()) {
412
+ cursor.next();
413
+ } else {
414
+ this._shouldStopParsing = true;
515
415
  }
416
+
417
+ break;
418
+ } else {
419
+ cursor.resolveError();
420
+ cursor.moveTo(onIndex);
516
421
  }
422
+ }
517
423
 
518
- return root;
424
+ if (!foundMatch) {
425
+ this._shouldStopParsing = true;
519
426
  }
520
427
  }
521
428
 
429
+
522
430
  private _isBeyondRecursiveAllowance() {
523
431
  let depth = 0;
524
432
  let pattern: Pattern | null = this;
@@ -537,52 +445,19 @@ export class ExpressionPattern implements Pattern {
537
445
  return false;
538
446
  }
539
447
 
540
- test(text: string) {
541
- const cursor = new Cursor(text);
542
- const ast = this.parse(cursor);
543
-
544
- return ast?.value === text;
448
+ test(text: string, record = false): boolean {
449
+ return testPattern(this, text, record);
545
450
  }
546
451
 
547
452
  exec(text: string, record = false): ParseResult {
548
- const cursor = new Cursor(text);
549
- record && cursor.startRecording();
550
-
551
- const ast = this.parse(cursor);
552
-
553
- return {
554
- ast: ast?.value === text ? ast : null,
555
- cursor
556
- };
453
+ return execPattern(this, text, record);
557
454
  }
558
455
 
559
456
  getTokens(): string[] {
560
457
  return this.atomPatterns.map(p => p.getTokens()).flat();
561
458
  }
562
459
 
563
- getTokensAfter(childReference: Pattern): string[] {
564
- if (this.atomPatterns.indexOf(childReference)) {
565
- const recursiveTokens = this._recursivePatterns.map(p => p.getTokens()).flat();
566
- const binaryTokens = this._binaryPatterns.map(p => p.getTokens()).flat();
567
-
568
- return [...recursiveTokens, ...binaryTokens];
569
- }
570
-
571
- if (this.recursivePatterns.indexOf(childReference)) {
572
- return this._binaryPatterns.map(p => p.getTokens()).flat();
573
- }
574
-
575
- if (this.binaryPatterns.indexOf(childReference)) {
576
- const unaryTokens = this._atomPatterns.map(p => p.getTokens()).flat();
577
-
578
- if (this._parent != null) {
579
- const nextTokens = this._parent.getTokensAfter(this);
580
- return [...unaryTokens, ...nextTokens];
581
- }
582
-
583
- return unaryTokens;
584
- }
585
-
460
+ getTokensAfter(_childReference: Pattern): string[] {
586
461
  return [];
587
462
  }
588
463
 
@@ -598,29 +473,7 @@ export class ExpressionPattern implements Pattern {
598
473
  return this.atomPatterns.map(p => p.getPatterns()).flat();
599
474
  }
600
475
 
601
- getPatternsAfter(childReference: Pattern): Pattern[] {
602
- if (this.atomPatterns.indexOf(childReference)) {
603
- const recursivePatterns = this._recursivePatterns.map(p => p.getPatterns()).flat();
604
- const binaryPatterns = this._binaryPatterns.map(p => p.getPatterns()).flat();
605
-
606
- return [...recursivePatterns, ...binaryPatterns];
607
- }
608
-
609
- if (this.recursivePatterns.indexOf(childReference)) {
610
- return this._binaryPatterns.map(p => p.getPatterns()).flat();
611
- }
612
-
613
- if (this.binaryPatterns.indexOf(childReference)) {
614
- const unaryPatterns = this._atomPatterns.map(p => p.getPatterns()).flat();
615
-
616
- if (this._parent != null) {
617
- const nextPatterns = this._parent.getPatternsAfter(this);
618
- return [...unaryPatterns, ...nextPatterns];
619
- }
620
-
621
- return unaryPatterns;
622
- }
623
-
476
+ getPatternsAfter(_childReference: Pattern): Pattern[] {
624
477
  return [];
625
478
  }
626
479
 
@@ -639,7 +492,6 @@ export class ExpressionPattern implements Pattern {
639
492
  clone(name = this._name): Pattern {
640
493
  const clone = new ExpressionPattern(name, this._originalPatterns);
641
494
  clone._id = this._id;
642
- clone.shouldCompactAst = this.shouldCompactAst;
643
495
  return clone;
644
496
  }
645
497