clarity-pattern-parser 10.3.7 → 11.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 (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 +417 -487
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.d.ts +3 -1
  7. package/dist/index.esm.js +416 -488
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.js +417 -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 +235 -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,7 +253,6 @@ 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
 
@@ -269,27 +260,6 @@ export class ExpressionPattern implements Pattern {
269
260
  return null;
270
261
  }
271
262
 
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
263
 
294
264
  private _tryToParse(cursor: Cursor): Node | null {
295
265
  if (this._isBeyondRecursiveAllowance()) {
@@ -297,228 +267,165 @@ export class ExpressionPattern implements Pattern {
297
267
  return null;
298
268
  }
299
269
 
300
- let lastAtomNode: Node | null = null;
301
- let lastBinaryNode: Node | null = null;
302
- let onIndex = cursor.index;
270
+ this._shouldStopParsing = false;
303
271
 
304
- outer: while (true) {
272
+ while (true) {
305
273
  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
274
 
319
- if (cursor.hasNext()) {
320
- cursor.next();
321
- } else {
322
- break outer;
323
- }
275
+ this._tryToMatchPrefix(cursor);
324
276
 
325
- break;
326
- } else {
327
- cursor.resolveError();
328
- }
277
+ if (this._shouldStopParsing) {
278
+ break;
329
279
  }
330
280
 
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);
281
+ this._tryToMatchAtom(cursor);
336
282
 
337
- if (node != null) {
338
- lastAtomNode = node;
339
-
340
- break;
341
- } else {
342
- lastAtomNode = null;
343
- cursor.resolveError();
344
- }
283
+ if (this._shouldStopParsing) {
284
+ break;
345
285
  }
346
286
 
347
- if (lastAtomNode == null) {
287
+ this._tryToMatchPostfix(cursor);
288
+
289
+ if (this._shouldStopParsing) {
348
290
  break;
349
291
  }
350
292
 
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);
293
+ if (this._precedenceTree.hasAtom()) {
294
+ this._tryToMatchBinary(cursor);
295
+
296
+ if (this._shouldStopParsing) {
297
+ break;
359
298
  }
299
+ } else {
360
300
  break;
361
301
  }
302
+ }
362
303
 
363
- onIndex = cursor.index;
304
+ return this._precedenceTree.commit();
305
+ }
364
306
 
365
- if (prefix != null && this._recursivePatterns.length === 0) {
366
- lastAtomNode = createNode(prefixName, [prefix, lastAtomNode]);
367
- }
307
+ private _tryToMatchPrefix(cursor: Cursor) {
308
+ let onIndex = cursor.index;
309
+
310
+ for (let i = 0; i < this._prefixPatterns.length; i++) {
311
+ const pattern = this._prefixPatterns[i];
312
+ const name = this._prefixNames[i];
313
+ const node = pattern.parse(cursor);
314
+
315
+ if (node != null) {
316
+ this._precedenceTree.addPrefix(name, ...node.children);
368
317
 
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
- }
318
+ if (cursor.hasNext()) {
319
+ cursor.next();
320
+ onIndex = cursor.index;
321
+ i = -1;
322
+
323
+ continue;
324
+ } else {
325
+ this._shouldStopParsing = true;
326
+ break;
409
327
  }
410
328
 
411
- cursor.resolveError();
329
+ } else {
412
330
  cursor.moveTo(onIndex);
331
+ cursor.resolveError();
413
332
  }
333
+ }
334
+ }
414
335
 
415
- onIndex = cursor.index;
416
- for (let i = 0; i < this._binaryPatterns.length; i++) {
417
- cursor.resolveError();
418
- cursor.moveTo(onIndex);
336
+ private _tryToMatchAtom(cursor: Cursor) {
337
+ let onIndex = cursor.index;
419
338
 
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
- }
339
+ for (let i = 0; i < this._atomPatterns.length; i++) {
340
+ cursor.moveTo(onIndex);
434
341
 
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
- }
342
+ const pattern = this._atomPatterns[i];
343
+ const node = pattern.parse(cursor);
489
344
 
490
- }
345
+ if (node != null) {
346
+ this._precedenceTree.addAtom(node);
491
347
 
492
348
  if (cursor.hasNext()) {
493
349
  cursor.next();
494
350
  } else {
495
- break outer;
351
+ this._shouldStopParsing = true;
496
352
  }
497
353
 
498
354
  break;
355
+ } else {
356
+ cursor.resolveError();
357
+ cursor.moveTo(onIndex);
499
358
  }
359
+ }
360
+ }
500
361
 
501
- if (lastBinaryNode == null) {
502
- break;
362
+ private _tryToMatchPostfix(cursor: Cursor) {
363
+ let onIndex = cursor.index;
364
+
365
+ for (let i = 0; i < this._postfixPatterns.length; i++) {
366
+ const pattern = this._postfixPatterns[i];
367
+ const name = this._postfixNames[i];
368
+ const node = pattern.parse(cursor);
369
+
370
+ if (node != null) {
371
+ this._precedenceTree.addPostfix(name, ...node.children);
372
+
373
+ if (cursor.hasNext()) {
374
+ cursor.next();
375
+ onIndex = cursor.index;
376
+ i = -1;
377
+
378
+ continue;
379
+ } else {
380
+ this._shouldStopParsing = true;
381
+ break;
382
+ }
383
+
384
+ } else {
385
+ cursor.moveTo(onIndex);
386
+ cursor.resolveError();
503
387
  }
504
388
  }
389
+ }
505
390
 
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();
391
+ private _tryToMatchBinary(cursor: Cursor) {
392
+ let onIndex = cursor.index;
393
+ let foundMatch = false;
394
+
395
+ if (this.binaryPatterns.length === 0) {
396
+ this._shouldStopParsing = true;
397
+ }
512
398
 
513
- if (lastBinaryNode === root) {
514
- return lastAtomNode;
399
+ for (let i = 0; i < this._binaryPatterns.length; i++) {
400
+ cursor.moveTo(onIndex);
401
+
402
+ const pattern = this._binaryPatterns[i];
403
+ const name = this._binaryNames[i];
404
+ const node = pattern.parse(cursor);
405
+
406
+ if (node != null) {
407
+ foundMatch = true;
408
+ this._precedenceTree.addBinary(name, ...node.children);
409
+
410
+ if (cursor.hasNext()) {
411
+ cursor.next();
412
+ } else {
413
+ this._shouldStopParsing = true;
515
414
  }
415
+
416
+ break;
417
+ } else {
418
+ cursor.resolveError();
419
+ cursor.moveTo(onIndex);
516
420
  }
421
+ }
517
422
 
518
- return root;
423
+ if (!foundMatch) {
424
+ this._shouldStopParsing = true;
519
425
  }
520
426
  }
521
427
 
428
+
522
429
  private _isBeyondRecursiveAllowance() {
523
430
  let depth = 0;
524
431
  let pattern: Pattern | null = this;
@@ -537,52 +444,19 @@ export class ExpressionPattern implements Pattern {
537
444
  return false;
538
445
  }
539
446
 
540
- test(text: string) {
541
- const cursor = new Cursor(text);
542
- const ast = this.parse(cursor);
543
-
544
- return ast?.value === text;
447
+ test(text: string, record = false): boolean {
448
+ return testPattern(this, text, record);
545
449
  }
546
450
 
547
451
  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
- };
452
+ return execPattern(this, text, record);
557
453
  }
558
454
 
559
455
  getTokens(): string[] {
560
456
  return this.atomPatterns.map(p => p.getTokens()).flat();
561
457
  }
562
458
 
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
-
459
+ getTokensAfter(_childReference: Pattern): string[] {
586
460
  return [];
587
461
  }
588
462
 
@@ -598,29 +472,7 @@ export class ExpressionPattern implements Pattern {
598
472
  return this.atomPatterns.map(p => p.getPatterns()).flat();
599
473
  }
600
474
 
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
-
475
+ getPatternsAfter(_childReference: Pattern): Pattern[] {
624
476
  return [];
625
477
  }
626
478
 
@@ -639,7 +491,6 @@ export class ExpressionPattern implements Pattern {
639
491
  clone(name = this._name): Pattern {
640
492
  const clone = new ExpressionPattern(name, this._originalPatterns);
641
493
  clone._id = this._id;
642
- clone.shouldCompactAst = this.shouldCompactAst;
643
494
  return clone;
644
495
  }
645
496