clarity-pattern-parser 10.1.20 → 10.1.21

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clarity-pattern-parser",
3
- "version": "10.1.20",
3
+ "version": "10.1.21",
4
4
  "description": "Parsing Library for Typescript and Javascript.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.esm.js",
@@ -490,4 +490,89 @@ describe("AutoComplete", () => {
490
490
  expect(results.options).toEqual(expected);
491
491
  });
492
492
 
493
+ test("Multiple Complex Branches", () => {
494
+ const branchOne = new Sequence("branch-1", [
495
+ new Literal("space-1-1", " "),
496
+ new Literal("space-1-2", " "),
497
+ new Options('branch-1-options', [
498
+ new Literal("AA", "AA"),
499
+ new Literal("AB", "AB"),
500
+ new Literal("BC", "BC"),
501
+ ])
502
+ ]);
503
+ const branchTwo = new Sequence("branch-2", [
504
+ new Literal("space-2-1", " "),
505
+ new Literal("space-2-2", " "),
506
+ new Options('branch-2-options', [
507
+ new Literal("BA", "BA"),
508
+ new Literal("BB", "BB")
509
+ ])
510
+ ]);
511
+ const eitherBranch = new Options("either-branch", [branchOne, branchTwo]);
512
+
513
+ const autoComplete = new AutoComplete(eitherBranch);
514
+ const results = autoComplete.suggestFor(" B");
515
+ const expected = [
516
+ { startIndex: 3, text: "A" },
517
+ { startIndex: 3, text: "B" },
518
+ { startIndex: 3, text: "C" },
519
+ ];
520
+ expect(results.options).toEqual(expected);
521
+ });
522
+
523
+
524
+ test("Recursion With Or", () => {
525
+ const ref = new Reference("names");
526
+ const names = new Options("names", [
527
+ ref,
528
+ new Literal("john", "John"),
529
+ new Literal("jane", "Jane")
530
+ ]);
531
+
532
+ const autoComplete = new AutoComplete(names);
533
+ const suggestion = autoComplete.suggestFor("Jo");
534
+
535
+ expect(suggestion.options).toEqual([
536
+ { text: 'hn', startIndex: 2 }
537
+ ]);
538
+ expect(suggestion.error?.endIndex).toBe(2);
539
+ });
540
+
541
+ test("Recursion With And", () => {
542
+ const firstNames = new Options("first-names", [
543
+ new Literal("john", "John"),
544
+ new Literal("jane", "Jane"),
545
+ ]);
546
+
547
+ const lastNames = new Options("last-names", [
548
+ new Literal("doe", "Doe"),
549
+ new Literal("smith", "Smith"),
550
+ ]);
551
+
552
+ const fullName = new Sequence("full-name", [
553
+ firstNames,
554
+ new Literal("space", " "),
555
+ lastNames
556
+ ]);
557
+
558
+ const ref = new Reference("names");
559
+ const names = new Sequence("names", [
560
+ fullName,
561
+ ref,
562
+ lastNames,
563
+ ]);
564
+
565
+ const autoComplete = new AutoComplete(names, {
566
+ greedyPatternNames: ["space"]
567
+ });
568
+ const suggestion = autoComplete.suggestFor("John");
569
+
570
+ expect(suggestion.options).toEqual([{
571
+ "text": " Doe",
572
+ "startIndex": 4
573
+ }, {
574
+ "text": " Smith",
575
+ "startIndex": 4
576
+ }]);
577
+ });
493
578
  });
@@ -12,6 +12,9 @@ export class ExpressionPattern implements Pattern {
12
12
  private _parent: Pattern | null;
13
13
  private _token: string;
14
14
  private _firstIndex: number;
15
+ private _patterns: Pattern[];
16
+ private _unaryPatterns: Pattern[];
17
+ private _binaryPatterns: Pattern[];
15
18
 
16
19
  get id(): string {
17
20
  return this._id;
@@ -41,10 +44,42 @@ export class ExpressionPattern implements Pattern {
41
44
  return [];
42
45
  }
43
46
 
44
- constructor(){
47
+ constructor(name: string, patterns: []) {
45
48
  this._id = `expression-${indexId++}`;
46
49
  this._type = "expression";
50
+ this._unaryPatterns = [];
51
+ this._binaryPatterns = [];
52
+ }
53
+
54
+ private _organizePatterns() {
55
+ this._patterns.forEach((pattern) => {
56
+ if (this._isBinary(pattern)) {
57
+ this._binaryPatterns.push(pattern);
58
+ } else {
59
+ this._unaryPatterns.push();
60
+ }
61
+ });
62
+ }
63
+
64
+ private _isBinary(pattern: Pattern) {
65
+ if (pattern.type === "right-associated" && this._isBinaryPattern(pattern.children[0])) {
66
+ return true;
67
+ }
68
+
69
+ return this._isBinaryPattern(pattern);
70
+ }
71
+
72
+ private _isBinaryPattern(pattern: Pattern) {
73
+ return pattern.type === "sequence" &&
74
+ pattern.children[0].type === "reference" &&
75
+ pattern.children[0].name === this.name &&
76
+ pattern.children[2].type === "reference" &&
77
+ pattern.children[2].name === this.name &&
78
+ pattern.children.length === 3;
79
+ }
47
80
 
81
+ private extractDelimiter(pattern) {
82
+ return pattern.children[1];
48
83
  }
49
84
 
50
85
  parse(cursor: Cursor): Node | null {
@@ -142,8 +142,11 @@ export class Options implements Pattern {
142
142
  getTokens(): string[] {
143
143
  const tokens: string[] = [];
144
144
 
145
- for (const child of this._children) {
146
- tokens.push(...child.getTokens());
145
+ for (const pattern of this._children) {
146
+ if (pattern.type === "reference" && pattern.name === this.name) {
147
+ continue;
148
+ }
149
+ tokens.push(...pattern.getTokens());
147
150
  }
148
151
 
149
152
  return tokens;
@@ -169,6 +172,9 @@ export class Options implements Pattern {
169
172
  const patterns: Pattern[] = [];
170
173
 
171
174
  for (const pattern of this._children) {
175
+ if (pattern.type === "reference" && pattern.name === this.name) {
176
+ continue;
177
+ }
172
178
  patterns.push(...pattern.getPatterns());
173
179
  }
174
180
 
@@ -0,0 +1,71 @@
1
+ import { Node } from "../ast/Node";
2
+ import { Cursor } from "./Cursor";
3
+ import { ParseResult } from "./ParseResult";
4
+ import { Pattern } from "./Pattern";
5
+
6
+ let indexId = 0;
7
+
8
+ export class RightAssociatedPattern implements Pattern {
9
+ readonly id: string;
10
+ readonly type: string;
11
+ readonly name: string;
12
+ private _parent: Pattern | null;
13
+ readonly children: Pattern[];
14
+
15
+ get parent() {
16
+ return this._parent;
17
+ }
18
+
19
+ set parent(pattern: Pattern | null) {
20
+ this._parent = pattern;
21
+ }
22
+
23
+ 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];
29
+ }
30
+
31
+ parse(cursor: Cursor): Node | null {
32
+ return this.children[0].parse(cursor);
33
+ }
34
+
35
+ exec(text: string, record?: boolean | undefined): ParseResult {
36
+ return this.children[0].exec(text, record);
37
+ }
38
+
39
+ test(text: string, record?: boolean | undefined): boolean {
40
+ return this.children[0].test(text, record);
41
+ }
42
+
43
+ clone(name?: string | undefined): Pattern {
44
+ return new RightAssociatedPattern(this.children[0]);
45
+ }
46
+
47
+ getTokens(): string[] {
48
+ return this.children[0].getTokens();
49
+ }
50
+ getTokensAfter(childReference: Pattern): string[] {
51
+ return this.children[0].getTokensAfter(childReference);
52
+ }
53
+ getNextTokens(): string[] {
54
+ return this.children[0].getNextTokens();
55
+ }
56
+ getPatterns(): Pattern[] {
57
+ return this.children[0].getPatterns();
58
+ }
59
+ getPatternsAfter(childReference: Pattern): Pattern[] {
60
+ return this.children[0].getPatternsAfter(childReference);
61
+ }
62
+ getNextPatterns(): Pattern[] {
63
+ return this.children[0].getNextPatterns();
64
+ }
65
+ find(predicate: (pattern: Pattern) => boolean): Pattern | null {
66
+ return this.children[0].find(predicate);
67
+ }
68
+ isEqual(pattern: Pattern): boolean {
69
+ return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
70
+ }
71
+ }
@@ -216,10 +216,13 @@ export class Sequence implements Pattern {
216
216
  getTokens(): string[] {
217
217
  const tokens: string[] = [];
218
218
 
219
- for (const child of this._children) {
220
- tokens.push(...child.getTokens());
219
+ for (const pattern of this._children) {
220
+ if (pattern.type === "reference" && pattern.name === this.name && pattern === this.children[0]) {
221
+ return tokens;
222
+ }
221
223
 
222
- if (child.type !== "optional" && child.type !== "not") {
224
+ tokens.push(...pattern.getTokens());
225
+ if (pattern.type !== "optional" && pattern.type !== "not") {
223
226
  break;
224
227
  }
225
228
  }
@@ -247,10 +250,15 @@ export class Sequence implements Pattern {
247
250
  getPatterns(): Pattern[] {
248
251
  const patterns: Pattern[] = [];
249
252
 
250
- for (const child of this._children) {
251
- patterns.push(...child.getPatterns());
253
+ for (const pattern of this._children) {
254
+
255
+ if (pattern.type === "reference" && pattern.name === this.name && pattern === this.children[0]) {
256
+ return patterns;
257
+ }
258
+
259
+ patterns.push(...pattern.getPatterns());
252
260
 
253
- if (child.type !== "optional" && child.type !== "not") {
261
+ if (pattern.type !== "optional" && pattern.type !== "not") {
254
262
  break;
255
263
  }
256
264
  }