clarity-pattern-parser 10.3.1 → 10.3.3

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.
@@ -4,14 +4,8 @@ import { Pattern } from "./Pattern";
4
4
  import { clonePatterns } from "./clonePatterns";
5
5
  import { findPattern } from "./findPattern";
6
6
  import { ParseResult } from "./ParseResult";
7
- import { DepthCache } from './DepthCache';
8
7
  import { isRecursivePattern } from "./isRecursivePattern";
9
8
 
10
- /*
11
- The following is created to reduce the overhead of recursion check.
12
- */
13
-
14
- const depthCache = new DepthCache();
15
9
  let idIndex = 0;
16
10
 
17
11
  export class Options implements Pattern {
@@ -49,6 +43,10 @@ export class Options implements Pattern {
49
43
  return this._children;
50
44
  }
51
45
 
46
+ get startedOnIndex() {
47
+ return this._firstIndex;
48
+ }
49
+
52
50
  constructor(name: string, options: Pattern[], isGreedy = false) {
53
51
  if (options.length === 0) {
54
52
  throw new Error("Need at least one pattern with an 'options' pattern.");
@@ -92,15 +90,9 @@ export class Options implements Pattern {
92
90
  }
93
91
 
94
92
  parse(cursor: Cursor): Node | null {
95
- // This is a cache to help with speed
96
- this._firstIndex = cursor.index;
97
- depthCache.incrementDepth(this._id, this._firstIndex);
98
-
99
93
  this._firstIndex = cursor.index;
100
94
  const node = this._tryToParse(cursor);
101
95
 
102
- depthCache.decrementDepth(this._id, this._firstIndex);
103
-
104
96
  if (node != null) {
105
97
  cursor.moveTo(node.lastIndex);
106
98
  cursor.resolveError();
@@ -117,7 +109,7 @@ export class Options implements Pattern {
117
109
  }
118
110
 
119
111
  private _tryToParse(cursor: Cursor): Node | null {
120
- if (depthCache.getDepth(this._id, this._firstIndex) > 2) {
112
+ if (this._isBeyondRecursiveAllowance()) {
121
113
  return null;
122
114
  }
123
115
 
@@ -146,6 +138,24 @@ export class Options implements Pattern {
146
138
  return nonNullResults[0] || null;
147
139
  }
148
140
 
141
+ private _isBeyondRecursiveAllowance() {
142
+ let depth = 0;
143
+ let pattern: Pattern | null = this;
144
+
145
+ while (pattern != null) {
146
+ if (pattern.id === this.id && pattern.startedOnIndex === this.startedOnIndex) {
147
+ depth++;
148
+ }
149
+
150
+ if (depth > 2) {
151
+ return true;
152
+ }
153
+ pattern = pattern.parent;
154
+ }
155
+
156
+ return false;
157
+ }
158
+
149
159
  getTokens(): string[] {
150
160
  const tokens: string[] = [];
151
161
 
@@ -7,6 +7,7 @@ export interface Pattern {
7
7
  type: string;
8
8
  name: string;
9
9
  shouldCompactAst: boolean;
10
+ startedOnIndex: number;
10
11
  parent: Pattern | null;
11
12
  children: Pattern[];
12
13
 
@@ -15,6 +15,7 @@ export class Reference implements Pattern {
15
15
  private _cachedPattern: Pattern | null;
16
16
  private _pattern: Pattern | null;
17
17
  private _children: Pattern[];
18
+ private _firstIndex: number;
18
19
 
19
20
  shouldCompactAst = false;
20
21
 
@@ -42,6 +43,10 @@ export class Reference implements Pattern {
42
43
  return this._children;
43
44
  }
44
45
 
46
+ get startedOnIndex() {
47
+ return this._firstIndex;
48
+ }
49
+
45
50
  constructor(name: string) {
46
51
  this._id = `reference-${idIndex++}`;
47
52
  this._type = "reference";
@@ -50,6 +55,7 @@ export class Reference implements Pattern {
50
55
  this._pattern = null;
51
56
  this._cachedPattern = null;
52
57
  this._children = [];
58
+ this._firstIndex = 0;
53
59
  }
54
60
 
55
61
  test(text: string) {
@@ -72,6 +78,7 @@ export class Reference implements Pattern {
72
78
  }
73
79
 
74
80
  parse(cursor: Cursor): Node | null {
81
+ this._firstIndex = cursor.index;
75
82
  return this.getReferencePatternSafely().parse(cursor);
76
83
  }
77
84
 
@@ -14,7 +14,7 @@ export class Regex implements Pattern {
14
14
  private _regex: RegExp;
15
15
  private _node: Node | null = null;
16
16
  private _cursor: Cursor | null = null;
17
- private _firstIndex = -1;
17
+ private _firstIndex = 0;
18
18
  private _substring = "";
19
19
  private _tokens: string[] = [];
20
20
 
@@ -48,6 +48,10 @@ export class Regex implements Pattern {
48
48
  return [];
49
49
  }
50
50
 
51
+ get startedOnIndex() {
52
+ return this._firstIndex;
53
+ }
54
+
51
55
  constructor(name: string, regex: string) {
52
56
  this._id = `regex-${idIndex++}`;
53
57
  this._type = "regex";
@@ -149,7 +153,7 @@ export class Regex implements Pattern {
149
153
  clone._tokens = this._tokens.slice();
150
154
  clone._id = this._id;
151
155
  clone.shouldCompactAst = this.shouldCompactAst;
152
-
156
+
153
157
  return clone;
154
158
  }
155
159
 
@@ -70,6 +70,10 @@ export class Repeat implements Pattern {
70
70
  return this._options.max;
71
71
  }
72
72
 
73
+ get startedOnIndex(){
74
+ return this._repeatPattern.startedOnIndex;
75
+ }
76
+
73
77
  constructor(name: string, pattern: Pattern, options: RepeatOptions = {}) {
74
78
  this._id = `repeat-${idIndex++}`;
75
79
  this._pattern = pattern;
@@ -38,6 +38,10 @@ export class RightAssociatedPattern implements Pattern {
38
38
  return this._children;
39
39
  }
40
40
 
41
+ get startedOnIndex() {
42
+ return this._children[0].startedOnIndex;
43
+ }
44
+
41
45
  constructor(pattern: Pattern) {
42
46
  this._id = `right-associated-${indexId++}`;
43
47
  this._type = "right-associated";
@@ -4,10 +4,8 @@ import { Node } from "../ast/Node";
4
4
  import { clonePatterns } from "./clonePatterns";
5
5
  import { filterOutNull } from "./filterOutNull";
6
6
  import { findPattern } from "./findPattern";
7
- import { DepthCache } from "./DepthCache";
8
7
  import { isRecursivePattern } from "./isRecursivePattern";
9
8
 
10
- const depthCache = new DepthCache();
11
9
  let idIndex = 0;
12
10
 
13
11
  export class Sequence implements Pattern {
@@ -45,6 +43,10 @@ export class Sequence implements Pattern {
45
43
  return this._children;
46
44
  }
47
45
 
46
+ get startedOnIndex() {
47
+ return this._firstIndex;
48
+ }
49
+
48
50
  constructor(name: string, sequence: Pattern[]) {
49
51
  if (sequence.length === 0) {
50
52
  throw new Error("Need at least one pattern with a 'sequence' pattern.");
@@ -88,14 +90,9 @@ export class Sequence implements Pattern {
88
90
  }
89
91
 
90
92
  parse(cursor: Cursor): Node | null {
91
- // This is a cache to help with speed
92
93
  this._firstIndex = cursor.index;
93
- depthCache.incrementDepth(this._id, this._firstIndex);
94
-
95
94
  this._nodes = [];
96
-
97
95
  const passed = this.tryToParse(cursor);
98
- depthCache.decrementDepth(this._id, this._firstIndex);
99
96
 
100
97
  if (passed) {
101
98
  const node = this.createNode(cursor);
@@ -115,7 +112,7 @@ export class Sequence implements Pattern {
115
112
  }
116
113
 
117
114
  private tryToParse(cursor: Cursor): boolean {
118
- if (depthCache.getDepth(this._id, this._firstIndex) > 1) {
115
+ if (this._isBeyondRecursiveAllowance()) {
119
116
  cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
120
117
  return false;
121
118
  }
@@ -190,6 +187,24 @@ export class Sequence implements Pattern {
190
187
  return nodes[nodes.length - 1];
191
188
  }
192
189
 
190
+ private _isBeyondRecursiveAllowance() {
191
+ let depth = 0;
192
+ let pattern: Pattern | null = this;
193
+
194
+ while (pattern != null) {
195
+ if (pattern.id === this.id && pattern.startedOnIndex === this.startedOnIndex) {
196
+ depth++;
197
+ }
198
+
199
+ if (depth > 1) {
200
+ return true;
201
+ }
202
+ pattern = pattern.parent;
203
+ }
204
+
205
+ return false;
206
+ }
207
+
193
208
  private areRemainingPatternsOptional(fromIndex: number): boolean {
194
209
  const startOnIndex = fromIndex + 1;
195
210
  const length = this._children.length;
@@ -1,26 +0,0 @@
1
- export class DepthCache {
2
- private _depthMap: Record<string, Record<number, number>> = {};
3
-
4
- getDepth(name: string, cursorIndex: number) {
5
- if (this._depthMap[name] == null) {
6
- this._depthMap[name] = {};
7
- }
8
-
9
- if (this._depthMap[name][cursorIndex] == null) {
10
- this._depthMap[name][cursorIndex] = 0;
11
- }
12
-
13
-
14
- return this._depthMap[name][cursorIndex];
15
- }
16
-
17
- incrementDepth(name: string, cursorIndex: number) {
18
- const depth = this.getDepth(name, cursorIndex);
19
- this._depthMap[name][cursorIndex] = depth + 1;
20
- }
21
-
22
- decrementDepth(name: string, cursorIndex: number) {
23
- const depth = this.getDepth(name, cursorIndex);
24
- this._depthMap[name][cursorIndex] = depth - 1;
25
- }
26
- }