clarity-pattern-parser 10.1.26 → 10.2.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.
@@ -3,10 +3,16 @@ import { Cursor } from "./Cursor";
3
3
  import { DepthCache } from "./DepthCache";
4
4
  import { ParseResult } from "./ParseResult";
5
5
  import { Pattern } from "./Pattern";
6
+ import { findPattern } from "./findPattern";
7
+ import { Sequence } from "./Sequence";
6
8
 
7
9
  let indexId = 0;
8
10
  const depthCache = new DepthCache();
9
11
 
12
+ function createNode(name: string, children: Node[]) {
13
+ return new Node("expression", name, 0, 0, children, "");
14
+ }
15
+
10
16
  enum Association {
11
17
  left = 0,
12
18
  right = 1,
@@ -17,13 +23,15 @@ export class ExpressionPattern implements Pattern {
17
23
  private _type: string;
18
24
  private _name: string;
19
25
  private _parent: Pattern | null;
20
- private _token: string;
21
26
  private _firstIndex: number;
27
+ private _originalPatterns: Pattern[];
22
28
  private _patterns: Pattern[];
23
29
  private _unaryPatterns: Pattern[];
24
30
  private _binaryPatterns: Pattern[];
31
+ private _recursivePatterns: Pattern[];
32
+ private _recursiveNames: string[];
25
33
  private _binaryAssociation: Association[];
26
- private _precedenceMap: Record<string, number>;
34
+ private _precedenceMap: Record<string, number>;
27
35
  private _binaryNames: string[];
28
36
 
29
37
  get id(): string {
@@ -38,10 +46,6 @@ export class ExpressionPattern implements Pattern {
38
46
  return this._name;
39
47
  }
40
48
 
41
- get token(): string {
42
- return this._token;
43
- }
44
-
45
49
  get parent(): Pattern | null {
46
50
  return this._parent;
47
51
  }
@@ -54,6 +58,18 @@ export class ExpressionPattern implements Pattern {
54
58
  return this._patterns;
55
59
  }
56
60
 
61
+ get unaryPatterns(): readonly Pattern[] {
62
+ return this._unaryPatterns;
63
+ }
64
+
65
+ get binaryPatterns(): readonly Pattern[] {
66
+ return this._binaryPatterns;
67
+ }
68
+
69
+ get recursivePatterns(): readonly Pattern[] {
70
+ return this._recursivePatterns;
71
+ }
72
+
57
73
  constructor(name: string, patterns: Pattern[]) {
58
74
  if (patterns.length === 0) {
59
75
  throw new Error("Need at least one pattern with an 'expression' pattern.");
@@ -62,19 +78,28 @@ export class ExpressionPattern implements Pattern {
62
78
  this._id = `expression-${indexId++}`;
63
79
  this._type = "expression";
64
80
  this._name = name;
81
+ this._parent = null;
82
+ this._firstIndex = -1;
65
83
  this._unaryPatterns = [];
66
84
  this._binaryPatterns = [];
85
+ this._recursivePatterns = [];
86
+ this._recursiveNames = [];
87
+ this._binaryNames = [];
88
+ this._binaryAssociation = [];
67
89
  this._precedenceMap = {};
68
-
69
- this._patterns.forEach(p => p.parent = this);
90
+ this._originalPatterns = patterns;
70
91
  this._patterns = this._organizePatterns(patterns);
92
+
93
+ if (this._unaryPatterns.length === 0) {
94
+ throw new Error("Need at least one operand pattern with an 'expression' pattern.");
95
+ }
71
96
  }
72
97
 
73
98
  private _organizePatterns(patterns: Pattern[]) {
74
99
  const finalPatterns: Pattern[] = [];
75
100
  patterns.forEach((pattern) => {
76
101
  if (this._isBinary(pattern)) {
77
- const binaryName = pattern.name;
102
+ const binaryName = this._extractName(pattern);
78
103
  const clone = this._extractDelimiter(pattern).clone();
79
104
  clone.parent = this;
80
105
 
@@ -89,6 +114,14 @@ export class ExpressionPattern implements Pattern {
89
114
  }
90
115
 
91
116
  finalPatterns.push(clone);
117
+ } else if (this._isRecursive(pattern)) {
118
+ const name = this._extractName(pattern);
119
+ const tail = this._extractRecursiveTail(pattern);
120
+ tail.parent = this;
121
+
122
+ this._recursivePatterns.push(tail);
123
+ this._recursiveNames.push(name);
124
+ finalPatterns.push(tail);
92
125
  } else {
93
126
  const clone = pattern.clone();
94
127
  clone.parent = this;
@@ -118,10 +151,43 @@ export class ExpressionPattern implements Pattern {
118
151
  pattern.children.length === 3;
119
152
  }
120
153
 
121
- private _extractDelimiter(pattern) {
154
+ private _extractDelimiter(pattern: Pattern) {
155
+ if (pattern.type === "right-associated") {
156
+ return pattern.children[0].children[1];
157
+ }
122
158
  return pattern.children[1];
123
159
  }
124
160
 
161
+ private _extractName(pattern: Pattern) {
162
+ if (pattern.type === "right-associated") {
163
+ return pattern.children[0].name;
164
+ }
165
+
166
+ return pattern.name;
167
+ }
168
+
169
+ private _isRecursive(pattern: Pattern) {
170
+ if (pattern.type === "right-associated" && this._isRecursivePattern(pattern.children[0])) {
171
+ return true;
172
+ }
173
+
174
+ return this._isRecursivePattern(pattern);
175
+ }
176
+
177
+ private _isRecursivePattern(pattern: Pattern) {
178
+ return pattern.type === "sequence" &&
179
+ pattern.children[0].type === "reference" &&
180
+ pattern.children[0].name === this.name &&
181
+ pattern.children.length > 2;
182
+ }
183
+
184
+ private _extractRecursiveTail(pattern: Pattern) {
185
+ if (pattern.type === "right-associated") {
186
+ return new Sequence(`${pattern.children[0].name}-tail`, pattern.children[0].children.slice(1));
187
+ }
188
+ return new Sequence(`${pattern.name}-tail`, pattern.children.slice(1));
189
+ }
190
+
125
191
  parse(cursor: Cursor): Node | null {
126
192
  // This is a cache to help with speed
127
193
  this._firstIndex = cursor.index;
@@ -143,103 +209,263 @@ export class ExpressionPattern implements Pattern {
143
209
  }
144
210
 
145
211
  private _tryToParse(cursor: Cursor): Node | null {
212
+ if (depthCache.getDepth(this._id, this._firstIndex) > 2) {
213
+ cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
214
+ return null;
215
+ }
216
+
146
217
  let lastUnaryNode: Node | null = null;
147
218
  let lastBinaryNode: Node | null = null;
148
219
  let onIndex = cursor.index;
149
-
150
- while (true) {
220
+
221
+ outer: while (true) {
151
222
  onIndex = cursor.index;
152
223
 
153
224
  for (let i = 0; i < this._unaryPatterns.length; i++) {
154
225
  cursor.moveTo(onIndex);
155
226
 
156
227
  const pattern = this._unaryPatterns[i];
157
- lastUnaryNode = pattern.parse(cursor);
228
+ const node = pattern.parse(cursor);
229
+
230
+ if (node != null) {
231
+ lastUnaryNode = node;
232
+ break;
233
+ } else {
234
+ lastUnaryNode = null;
235
+ cursor.resolveError();
236
+ }
158
237
  }
159
-
160
- const canContinue = cursor.hasNext();
161
238
 
162
- // if (canContinue) {
163
- // cursor.next();
164
- // } else if (!canContinue && astStack.length > 1) {
165
-
166
- // } else if (!canContinue && astStack.length === 1){
167
- // return astStack[0];
168
- // }
239
+ if (lastUnaryNode == null) {
240
+ break;
241
+ }
242
+
243
+ if (cursor.hasNext()) {
244
+ cursor.next();
245
+ } else {
246
+ if (lastBinaryNode != null && lastUnaryNode != null) {
247
+ lastBinaryNode.appendChild(lastUnaryNode);
248
+ }
249
+ break;
250
+ }
169
251
 
170
252
  onIndex = cursor.index;
171
253
 
254
+ for (let i = 0; i < this._recursivePatterns.length; i++) {
255
+ const pattern = this._recursivePatterns[i];
256
+ const node = pattern.parse(cursor);
257
+
258
+ if (node != null) {
259
+ if (lastBinaryNode != null && lastUnaryNode != null) {
260
+ lastBinaryNode.appendChild(lastUnaryNode);
261
+ }
262
+
263
+ const frontExpression = lastBinaryNode == null ? lastUnaryNode as Node : lastBinaryNode.findRoot();
264
+ const name = this._recursiveNames[i];
265
+ const recursiveNode = createNode(name, [frontExpression, ...node.children]);
266
+
267
+ recursiveNode.normalize(this._firstIndex);
268
+ return recursiveNode;
269
+ }
270
+
271
+ cursor.moveTo(onIndex);
272
+ }
273
+
274
+ onIndex = cursor.index;
172
275
  for (let i = 0; i < this._binaryPatterns.length; i++) {
173
276
  cursor.moveTo(onIndex);
174
- const name = this._binaryNames[i];
175
- const pattern = this._binaryPatterns[i];
176
277
 
177
- const node = pattern.parse(cursor);
278
+ const pattern = this._binaryPatterns[i];
279
+ const name = this._binaryNames[i];
280
+ const delimiterNode = pattern.parse(cursor);
281
+
282
+ if (delimiterNode == null) {
283
+ if (i === this._binaryPatterns.length - 1) {
284
+ if (lastBinaryNode == null) {
285
+ return lastUnaryNode;
286
+ } else if (lastUnaryNode != null) {
287
+ lastBinaryNode.appendChild(lastUnaryNode);
288
+ }
289
+ }
290
+ continue;
291
+ }
178
292
 
179
- // if (node != null) {
180
- // binaryIndex = i;
293
+ if (lastBinaryNode == null && lastUnaryNode != null && delimiterNode != null) {
294
+ const node = createNode(name, [lastUnaryNode, delimiterNode]);
295
+ lastBinaryNode = node;
296
+ } else if (lastBinaryNode != null && lastUnaryNode != null && delimiterNode != null) {
297
+ const precedence = this._precedenceMap[name];
298
+ const lastPrecendece = lastBinaryNode == null ? 0 : this._precedenceMap[lastBinaryNode.name];
299
+ const association = this._binaryAssociation[i];
300
+
301
+ if (precedence === lastPrecendece && association === Association.right) {
302
+ const node = createNode(name, [lastUnaryNode, delimiterNode]);
303
+ lastBinaryNode.appendChild(node);
304
+ lastBinaryNode = node;
305
+ } else if (precedence === lastPrecendece) {
306
+ const node = createNode(name, []);
307
+
308
+ lastBinaryNode.replaceWith(node);
309
+ lastBinaryNode.appendChild(lastUnaryNode);
310
+ node.append(lastBinaryNode, delimiterNode);
311
+ lastBinaryNode = node;
312
+ } else if (precedence > lastPrecendece) {
313
+ const root = lastBinaryNode.findRoot();
314
+ lastBinaryNode.appendChild(lastUnaryNode);
315
+
316
+ if (root != null) {
317
+ const node = createNode(name, [root, delimiterNode]);
318
+ lastBinaryNode = node;
319
+ } else {
320
+ const node = createNode(name, [lastUnaryNode, delimiterNode]);
321
+ lastBinaryNode = node;
322
+ }
323
+
324
+ } else {
325
+ const node = createNode(name, [lastUnaryNode, delimiterNode]);
326
+ lastBinaryNode.appendChild(node);
327
+ lastBinaryNode = node;
328
+ }
181
329
 
182
- // const binaryNode = Node.createNode(name, []);
183
- // association = this._binaryAssociation[i];
330
+ }
184
331
 
185
- // if (association === Association.left) {
186
- // if (nodeToAppendTo != null){
187
- // nodeToAppendTo = binaryNode;
188
- // } else {
189
- // nodeToAppendTo.
190
- // }
191
- // } else {
332
+ if (cursor.hasNext()) {
333
+ cursor.next();
334
+ } else {
335
+ break outer;
336
+ }
192
337
 
193
- // }
194
- // }
338
+ break;
339
+ }
195
340
 
341
+ if (lastBinaryNode == null){
342
+ break;
196
343
  }
197
344
  }
198
345
 
199
- return null;
200
- }
346
+ if (lastBinaryNode == null) {
347
+ return lastUnaryNode;
348
+ } else {
349
+ const root = lastBinaryNode.findAncestor(n => n.parent == null) as Node || lastBinaryNode;
350
+ if (lastBinaryNode.children.length < 3) {
351
+ lastBinaryNode.remove();
352
+
353
+ if (lastBinaryNode === root) {
354
+ return lastUnaryNode;
355
+ }
356
+ }
201
357
 
202
- exec(text: string, record?: boolean | undefined): ParseResult {
203
- throw new Error("Method not implemented.");
358
+ root.normalize(this._firstIndex);
359
+ return root;
360
+ }
204
361
  }
205
362
 
206
- test(text: string, record?: boolean | undefined): boolean {
207
- throw new Error("Method not implemented.");
363
+ test(text: string) {
364
+ const cursor = new Cursor(text);
365
+ const ast = this.parse(cursor);
366
+
367
+ return ast?.value === text;
208
368
  }
209
369
 
210
- clone(name?: string | undefined): Pattern {
211
- throw new Error("Method not implemented.");
370
+ exec(text: string, record = false): ParseResult {
371
+ const cursor = new Cursor(text);
372
+ record && cursor.startRecording();
373
+
374
+ const ast = this.parse(cursor);
375
+
376
+ return {
377
+ ast: ast?.value === text ? ast : null,
378
+ cursor
379
+ };
212
380
  }
213
381
 
214
382
  getTokens(): string[] {
215
- throw new Error("Method not implemented.");
383
+ return this.unaryPatterns.map(p => p.getTokens()).flat();
216
384
  }
217
385
 
218
386
  getTokensAfter(childReference: Pattern): string[] {
219
- throw new Error("Method not implemented.");
387
+ if (this.unaryPatterns.indexOf(childReference)) {
388
+ const recursiveTokens = this._recursivePatterns.map(p => p.getTokens()).flat();
389
+ const binaryTokens = this._binaryPatterns.map(p => p.getTokens()).flat();
390
+
391
+ return [...recursiveTokens, ...binaryTokens];
392
+ }
393
+
394
+ if (this.recursivePatterns.indexOf(childReference)) {
395
+ return this._binaryPatterns.map(p => p.getTokens()).flat();
396
+ }
397
+
398
+ if (this.binaryPatterns.indexOf(childReference)) {
399
+ const unaryTokens = this._unaryPatterns.map(p => p.getTokens()).flat();
400
+
401
+ if (this._parent != null) {
402
+ const nextTokens = this._parent.getTokensAfter(this);
403
+ return [...unaryTokens, ...nextTokens];
404
+ }
405
+
406
+ return unaryTokens;
407
+ }
408
+
409
+ return [];
220
410
  }
221
411
 
222
412
  getNextTokens(): string[] {
223
- throw new Error("Method not implemented.");
413
+ if (this._parent == null) {
414
+ return [];
415
+ }
416
+
417
+ return this._parent.getTokensAfter(this);
224
418
  }
225
419
 
226
420
  getPatterns(): Pattern[] {
227
- throw new Error("Method not implemented.");
421
+ return this.unaryPatterns.map(p => p.getPatterns()).flat();
228
422
  }
229
423
 
230
424
  getPatternsAfter(childReference: Pattern): Pattern[] {
231
- throw new Error("Method not implemented.");
425
+ if (this.unaryPatterns.indexOf(childReference)) {
426
+ const recursivePatterns = this._recursivePatterns.map(p => p.getPatterns()).flat();
427
+ const binaryPatterns = this._binaryPatterns.map(p => p.getPatterns()).flat();
428
+
429
+ return [...recursivePatterns, ...binaryPatterns];
430
+ }
431
+
432
+ if (this.recursivePatterns.indexOf(childReference)) {
433
+ return this._binaryPatterns.map(p => p.getPatterns()).flat();
434
+ }
435
+
436
+ if (this.binaryPatterns.indexOf(childReference)) {
437
+ const unaryPatterns = this._unaryPatterns.map(p => p.getPatterns()).flat();
438
+
439
+ if (this._parent != null) {
440
+ const nextPatterns = this._parent.getPatternsAfter(this);
441
+ return [...unaryPatterns, ...nextPatterns];
442
+ }
443
+
444
+ return unaryPatterns;
445
+ }
446
+
447
+ return [];
232
448
  }
233
449
 
234
450
  getNextPatterns(): Pattern[] {
235
- throw new Error("Method not implemented.");
451
+ if (this._parent == null) {
452
+ return [];
453
+ }
454
+
455
+ return this._parent.getPatternsAfter(this);
236
456
  }
237
457
 
238
- find(predicate: (pattern: Pattern) => boolean): Pattern | null {
239
- throw new Error("Method not implemented.");
458
+ find(predicate: (p: Pattern) => boolean): Pattern | null {
459
+ return findPattern(this, predicate);
240
460
  }
241
461
 
242
- isEqual(pattern: Pattern): boolean {
243
- throw new Error("Method not implemented.");
462
+ clone(name = this._name): Pattern {
463
+ const clone = new ExpressionPattern(name, this._originalPatterns);
464
+ clone._id = this._id;
465
+ return clone;
244
466
  }
245
- }
467
+
468
+ isEqual(pattern: ExpressionPattern): boolean {
469
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
470
+ }
471
+ }
@@ -111,7 +111,6 @@ export class Options implements Pattern {
111
111
 
112
112
  private _tryToParse(cursor: Cursor): Node | null {
113
113
  if (depthCache.getDepth(this._id, this._firstIndex) > 2) {
114
- cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
115
114
  return null;
116
115
  }
117
116
 
@@ -6,13 +6,25 @@ import { Pattern } from "./Pattern";
6
6
  let indexId = 0;
7
7
 
8
8
  export class RightAssociatedPattern implements Pattern {
9
- readonly id: string;
10
- readonly type: string;
11
- readonly name: string;
9
+ private _id: string;
10
+ private _type: string;
11
+ private _name: string;
12
12
  private _parent: Pattern | null;
13
- readonly children: Pattern[];
13
+ private _children: Pattern[];
14
14
 
15
- get parent() {
15
+ get id(): string {
16
+ return this._id;
17
+ }
18
+
19
+ get type(): string {
20
+ return this._type;
21
+ }
22
+
23
+ get name(): string {
24
+ return this._name;
25
+ }
26
+
27
+ get parent(): Pattern | null {
16
28
  return this._parent;
17
29
  }
18
30
 
@@ -20,12 +32,16 @@ export class RightAssociatedPattern implements Pattern {
20
32
  this._parent = pattern;
21
33
  }
22
34
 
35
+ get children(): Pattern[] {
36
+ return this._children;
37
+ }
38
+
23
39
  constructor(pattern: Pattern) {
24
- this.id = `right-associated-${indexId++}`;
25
- this.type = "right-associated";
26
- this.name = "";
27
- this.parent = null;
28
- this.children = [pattern];
40
+ this._id = `right-associated-${indexId++}`;
41
+ this._type = "right-associated";
42
+ this._name = "";
43
+ this._parent = null;
44
+ this._children = [pattern.clone()];
29
45
  }
30
46
 
31
47
  parse(cursor: Cursor): Node | null {
@@ -41,7 +57,9 @@ export class RightAssociatedPattern implements Pattern {
41
57
  }
42
58
 
43
59
  clone(_name?: string | undefined): Pattern {
44
- return new RightAssociatedPattern(this.children[0]);
60
+ const clone = new RightAssociatedPattern(this.children[0]);
61
+ clone._id = this._id;
62
+ return clone;
45
63
  }
46
64
 
47
65
  getTokens(): string[] {