clarity-pattern-parser 10.3.6 → 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 +418 -490
  5. package/dist/index.browser.js.map +1 -1
  6. package/dist/index.d.ts +3 -1
  7. package/dist/index.esm.js +417 -491
  8. package/dist/index.esm.js.map +1 -1
  9. package/dist/index.js +418 -490
  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 +237 -387
  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 {
@@ -257,9 +249,10 @@ export class ExpressionPattern implements Pattern {
257
249
  const node = this._tryToParse(cursor);
258
250
 
259
251
  if (node != null) {
252
+ node.normalize(this._firstIndex);
253
+
260
254
  cursor.moveTo(node.lastIndex);
261
255
  cursor.resolveError();
262
- this._compactResult(node);
263
256
  return node;
264
257
  }
265
258
 
@@ -267,27 +260,6 @@ export class ExpressionPattern implements Pattern {
267
260
  return null;
268
261
  }
269
262
 
270
- private _compactResult(node: Node | null) {
271
- if (node == null) {
272
- return;
273
- }
274
-
275
- if (this.shouldCompactAst) {
276
- node.compact();
277
- return;
278
- }
279
-
280
- // This could be really expensive with large trees. So we optimize with these checks,
281
- // as well as use breadth first as to not recompact nodes over and over again.
282
- const isCompactingNeeded = Object.values(this._shouldCompactPatternsMap).some(p => p);
283
- if (isCompactingNeeded) {
284
- node.walkBreadthFirst(n => {
285
- if (this._shouldCompactPatternsMap[n.name]) {
286
- n.compact();
287
- }
288
- });
289
- }
290
- }
291
263
 
292
264
  private _tryToParse(cursor: Cursor): Node | null {
293
265
  if (this._isBeyondRecursiveAllowance()) {
@@ -295,231 +267,165 @@ export class ExpressionPattern implements Pattern {
295
267
  return null;
296
268
  }
297
269
 
298
- let lastAtomNode: Node | null = null;
299
- let lastBinaryNode: Node | null = null;
300
- let onIndex = cursor.index;
270
+ this._shouldStopParsing = false;
301
271
 
302
- outer: while (true) {
272
+ while (true) {
303
273
  cursor.resolveError();
304
- onIndex = cursor.index;
305
-
306
- let prefix: Node | null = null;
307
- let prefixName = "";
308
- for (let i = 0; i < this._unaryPrefixPatterns.length; i++) {
309
- cursor.moveTo(onIndex);
310
- const pattern = this._unaryPrefixPatterns[i];
311
- const node = pattern.parse(cursor);
312
274
 
313
- if (node != null) {
314
- prefix = node;
315
- prefixName = this._unaryPrefixNames[i];
275
+ this._tryToMatchPrefix(cursor);
316
276
 
317
- if (cursor.hasNext()) {
318
- cursor.next();
319
- } else {
320
- break outer;
321
- }
322
-
323
- break;
324
- } else {
325
- cursor.resolveError();
326
- }
277
+ if (this._shouldStopParsing) {
278
+ break;
327
279
  }
328
280
 
329
- onIndex = cursor.index;
330
- for (let i = 0; i < this._atomPatterns.length; i++) {
331
- cursor.moveTo(onIndex);
332
- const pattern = this._atomPatterns[i];
333
- const node = pattern.parse(cursor);
334
-
335
- if (node != null) {
336
- lastAtomNode = node;
281
+ this._tryToMatchAtom(cursor);
337
282
 
338
- break;
339
- } else {
340
- lastAtomNode = null;
341
- cursor.resolveError();
342
- }
283
+ if (this._shouldStopParsing) {
284
+ break;
343
285
  }
344
286
 
345
- if (lastAtomNode == null) {
287
+ this._tryToMatchPostfix(cursor);
288
+
289
+ if (this._shouldStopParsing) {
346
290
  break;
347
291
  }
348
292
 
349
- if (cursor.hasNext()) {
350
- cursor.next();
351
- } else {
352
- if (lastBinaryNode != null && lastAtomNode != null) {
353
- if (prefix != null) {
354
- lastAtomNode = createNode(prefixName, [prefix, lastAtomNode]);
355
- }
356
- lastBinaryNode.appendChild(lastAtomNode);
293
+ if (this._precedenceTree.hasAtom()) {
294
+ this._tryToMatchBinary(cursor);
295
+
296
+ if (this._shouldStopParsing) {
297
+ break;
357
298
  }
299
+ } else {
358
300
  break;
359
301
  }
302
+ }
303
+
304
+ return this._precedenceTree.commit();
305
+ }
360
306
 
361
- onIndex = cursor.index;
307
+ private _tryToMatchPrefix(cursor: Cursor) {
308
+ let onIndex = cursor.index;
362
309
 
363
- if (prefix != null && this._recursivePatterns.length === 0) {
364
- lastAtomNode = createNode(prefixName, [prefix, lastAtomNode]);
365
- }
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);
366
314
 
367
- for (let i = 0; i < this._recursivePatterns.length; i++) {
368
- const pattern = this._recursivePatterns[i];
369
- const node = pattern.parse(cursor);
370
-
371
- if (node != null) {
372
- const name = this._recursiveNames[i];
373
-
374
- if (this._endsInRecursion[i]) {
375
- if (lastBinaryNode != null && lastAtomNode != null) {
376
- if (prefix != null) {
377
- lastAtomNode = createNode(prefixName, [prefix, lastAtomNode]);
378
- }
379
- lastBinaryNode.appendChild(lastAtomNode);
380
- }
381
-
382
- const frontExpression = lastBinaryNode == null ? lastAtomNode as Node : lastBinaryNode.findRoot();
383
- const recursiveNode = createNode(name, [frontExpression, ...node.children]);
384
-
385
- recursiveNode.normalize(this._firstIndex);
386
-
387
- return recursiveNode;
388
- } else {
389
- if (prefix != null) {
390
- lastAtomNode = createNode(prefixName, [prefix, lastAtomNode]);
391
- }
392
-
393
- const recursiveNode = createNode(name, [lastAtomNode, ...node.children]);
394
- recursiveNode.normalize(lastAtomNode.startIndex);
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
- }
315
+ if (node != null) {
316
+ this._precedenceTree.addPrefix(name, ...node.children);
317
+
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
- root.normalize(this._firstIndex);
519
- return root;
423
+ if (!foundMatch) {
424
+ this._shouldStopParsing = true;
520
425
  }
521
426
  }
522
427
 
428
+
523
429
  private _isBeyondRecursiveAllowance() {
524
430
  let depth = 0;
525
431
  let pattern: Pattern | null = this;
@@ -538,52 +444,19 @@ export class ExpressionPattern implements Pattern {
538
444
  return false;
539
445
  }
540
446
 
541
- test(text: string) {
542
- const cursor = new Cursor(text);
543
- const ast = this.parse(cursor);
544
-
545
- return ast?.value === text;
447
+ test(text: string, record = false): boolean {
448
+ return testPattern(this, text, record);
546
449
  }
547
450
 
548
451
  exec(text: string, record = false): ParseResult {
549
- const cursor = new Cursor(text);
550
- record && cursor.startRecording();
551
-
552
- const ast = this.parse(cursor);
553
-
554
- return {
555
- ast: ast?.value === text ? ast : null,
556
- cursor
557
- };
452
+ return execPattern(this, text, record);
558
453
  }
559
454
 
560
455
  getTokens(): string[] {
561
456
  return this.atomPatterns.map(p => p.getTokens()).flat();
562
457
  }
563
458
 
564
- getTokensAfter(childReference: Pattern): string[] {
565
- if (this.atomPatterns.indexOf(childReference)) {
566
- const recursiveTokens = this._recursivePatterns.map(p => p.getTokens()).flat();
567
- const binaryTokens = this._binaryPatterns.map(p => p.getTokens()).flat();
568
-
569
- return [...recursiveTokens, ...binaryTokens];
570
- }
571
-
572
- if (this.recursivePatterns.indexOf(childReference)) {
573
- return this._binaryPatterns.map(p => p.getTokens()).flat();
574
- }
575
-
576
- if (this.binaryPatterns.indexOf(childReference)) {
577
- const unaryTokens = this._atomPatterns.map(p => p.getTokens()).flat();
578
-
579
- if (this._parent != null) {
580
- const nextTokens = this._parent.getTokensAfter(this);
581
- return [...unaryTokens, ...nextTokens];
582
- }
583
-
584
- return unaryTokens;
585
- }
586
-
459
+ getTokensAfter(_childReference: Pattern): string[] {
587
460
  return [];
588
461
  }
589
462
 
@@ -599,29 +472,7 @@ export class ExpressionPattern implements Pattern {
599
472
  return this.atomPatterns.map(p => p.getPatterns()).flat();
600
473
  }
601
474
 
602
- getPatternsAfter(childReference: Pattern): Pattern[] {
603
- if (this.atomPatterns.indexOf(childReference)) {
604
- const recursivePatterns = this._recursivePatterns.map(p => p.getPatterns()).flat();
605
- const binaryPatterns = this._binaryPatterns.map(p => p.getPatterns()).flat();
606
-
607
- return [...recursivePatterns, ...binaryPatterns];
608
- }
609
-
610
- if (this.recursivePatterns.indexOf(childReference)) {
611
- return this._binaryPatterns.map(p => p.getPatterns()).flat();
612
- }
613
-
614
- if (this.binaryPatterns.indexOf(childReference)) {
615
- const unaryPatterns = this._atomPatterns.map(p => p.getPatterns()).flat();
616
-
617
- if (this._parent != null) {
618
- const nextPatterns = this._parent.getPatternsAfter(this);
619
- return [...unaryPatterns, ...nextPatterns];
620
- }
621
-
622
- return unaryPatterns;
623
- }
624
-
475
+ getPatternsAfter(_childReference: Pattern): Pattern[] {
625
476
  return [];
626
477
  }
627
478
 
@@ -640,7 +491,6 @@ export class ExpressionPattern implements Pattern {
640
491
  clone(name = this._name): Pattern {
641
492
  const clone = new ExpressionPattern(name, this._originalPatterns);
642
493
  clone._id = this._id;
643
- clone.shouldCompactAst = this.shouldCompactAst;
644
494
  return clone;
645
495
  }
646
496