clarity-pattern-parser 10.3.0 → 10.3.2
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/dist/index.browser.js +89 -45
- package/dist/index.browser.js.map +1 -1
- package/dist/index.esm.js +89 -45
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +89 -45
- package/dist/index.js.map +1 -1
- package/dist/patterns/Context.d.ts +1 -0
- package/dist/patterns/ExpressionPattern.d.ts +2 -0
- package/dist/patterns/FiniteRepeat.d.ts +2 -0
- package/dist/patterns/InfiniteRepeat.d.ts +1 -0
- package/dist/patterns/Literal.d.ts +1 -0
- package/dist/patterns/Not.d.ts +1 -0
- package/dist/patterns/Optional.d.ts +1 -0
- package/dist/patterns/Options.d.ts +2 -0
- package/dist/patterns/Pattern.d.ts +1 -0
- package/dist/patterns/Reference.d.ts +2 -0
- package/dist/patterns/Regex.d.ts +1 -0
- package/dist/patterns/Repeat.d.ts +1 -0
- package/dist/patterns/Sequence.d.ts +2 -0
- package/package.json +1 -1
- package/src/patterns/Context.ts +4 -0
- package/src/patterns/ExpressionPattern.test.ts +38 -0
- package/src/patterns/ExpressionPattern.ts +26 -11
- package/src/patterns/FiniteRepeat.ts +8 -0
- package/src/patterns/InfiniteRepeat.ts +4 -0
- package/src/patterns/Literal.ts +4 -0
- package/src/patterns/Not.ts +4 -0
- package/src/patterns/Optional.ts +4 -0
- package/src/patterns/Options.ts +23 -13
- package/src/patterns/Pattern.ts +1 -0
- package/src/patterns/Reference.ts +7 -0
- package/src/patterns/Regex.ts +6 -2
- package/src/patterns/Repeat.ts +4 -0
- package/src/patterns/RightAssociatedPattern.ts +4 -0
- package/src/patterns/Sequence.ts +23 -8
- package/src/patterns/DepthCache.ts +0 -26
|
@@ -17,6 +17,7 @@ export declare class Context implements Pattern {
|
|
|
17
17
|
get parent(): Pattern | null;
|
|
18
18
|
set parent(pattern: Pattern | null);
|
|
19
19
|
get children(): Pattern[];
|
|
20
|
+
get startedOnIndex(): number;
|
|
20
21
|
getPatternWithinContext(name: string): Pattern | null;
|
|
21
22
|
getPatternsWithinContext(): {
|
|
22
23
|
[x: string]: Pattern;
|
|
@@ -29,6 +29,7 @@ export declare class ExpressionPattern implements Pattern {
|
|
|
29
29
|
get unaryPatterns(): readonly Pattern[];
|
|
30
30
|
get binaryPatterns(): readonly Pattern[];
|
|
31
31
|
get recursivePatterns(): readonly Pattern[];
|
|
32
|
+
get startedOnIndex(): number;
|
|
32
33
|
constructor(name: string, patterns: Pattern[]);
|
|
33
34
|
private _organizePatterns;
|
|
34
35
|
private _isBinary;
|
|
@@ -42,6 +43,7 @@ export declare class ExpressionPattern implements Pattern {
|
|
|
42
43
|
parse(cursor: Cursor): Node | null;
|
|
43
44
|
private _compactResult;
|
|
44
45
|
private _tryToParse;
|
|
46
|
+
private _isBeyondRecursiveAllowance;
|
|
45
47
|
test(text: string): boolean;
|
|
46
48
|
exec(text: string, record?: boolean): ParseResult;
|
|
47
49
|
getTokens(): string[];
|
|
@@ -18,6 +18,7 @@ export declare class FiniteRepeat implements Pattern {
|
|
|
18
18
|
private _min;
|
|
19
19
|
private _max;
|
|
20
20
|
private _trimDivider;
|
|
21
|
+
private _firstIndex;
|
|
21
22
|
shouldCompactAst: boolean;
|
|
22
23
|
get id(): string;
|
|
23
24
|
get type(): string;
|
|
@@ -27,6 +28,7 @@ export declare class FiniteRepeat implements Pattern {
|
|
|
27
28
|
get children(): Pattern[];
|
|
28
29
|
get min(): number;
|
|
29
30
|
get max(): number;
|
|
31
|
+
get startedOnIndex(): number;
|
|
30
32
|
constructor(name: string, pattern: Pattern, options?: FiniteRepeatOptions);
|
|
31
33
|
parse(cursor: Cursor): Node | null;
|
|
32
34
|
test(text: string): boolean;
|
|
@@ -27,6 +27,7 @@ export declare class InfiniteRepeat implements Pattern {
|
|
|
27
27
|
set parent(pattern: Pattern | null);
|
|
28
28
|
get children(): Pattern[];
|
|
29
29
|
get min(): number;
|
|
30
|
+
get startedOnIndex(): number;
|
|
30
31
|
constructor(name: string, pattern: Pattern, options?: InfiniteRepeatOptions);
|
|
31
32
|
private _assignChildrenToParent;
|
|
32
33
|
test(text: string): boolean;
|
|
@@ -20,6 +20,7 @@ export declare class Literal implements Pattern {
|
|
|
20
20
|
get parent(): Pattern | null;
|
|
21
21
|
set parent(pattern: Pattern | null);
|
|
22
22
|
get children(): Pattern[];
|
|
23
|
+
get startedOnIndex(): number;
|
|
23
24
|
constructor(name: string, value: string);
|
|
24
25
|
test(text: string, record?: boolean): boolean;
|
|
25
26
|
exec(text: string, record?: boolean): ParseResult;
|
package/dist/patterns/Not.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export declare class Not implements Pattern {
|
|
|
15
15
|
get parent(): Pattern | null;
|
|
16
16
|
set parent(pattern: Pattern | null);
|
|
17
17
|
get children(): Pattern[];
|
|
18
|
+
get startedOnIndex(): number;
|
|
18
19
|
constructor(name: string, pattern: Pattern);
|
|
19
20
|
test(text: string): boolean;
|
|
20
21
|
exec(text: string, record?: boolean): ParseResult;
|
|
@@ -15,6 +15,7 @@ export declare class Optional implements Pattern {
|
|
|
15
15
|
get parent(): Pattern | null;
|
|
16
16
|
set parent(pattern: Pattern | null);
|
|
17
17
|
get children(): Pattern[];
|
|
18
|
+
get startedOnIndex(): number;
|
|
18
19
|
constructor(name: string, pattern: Pattern);
|
|
19
20
|
test(text: string): boolean;
|
|
20
21
|
exec(text: string, record?: boolean): ParseResult;
|
|
@@ -17,12 +17,14 @@ export declare class Options implements Pattern {
|
|
|
17
17
|
get parent(): Pattern | null;
|
|
18
18
|
set parent(pattern: Pattern | null);
|
|
19
19
|
get children(): Pattern[];
|
|
20
|
+
get startedOnIndex(): number;
|
|
20
21
|
constructor(name: string, options: Pattern[], isGreedy?: boolean);
|
|
21
22
|
private _assignChildrenToParent;
|
|
22
23
|
test(text: string): boolean;
|
|
23
24
|
exec(text: string, record?: boolean): ParseResult;
|
|
24
25
|
parse(cursor: Cursor): Node | null;
|
|
25
26
|
private _tryToParse;
|
|
27
|
+
private _isBeyondRecursiveAllowance;
|
|
26
28
|
getTokens(): string[];
|
|
27
29
|
getTokensAfter(_childReference: Pattern): string[];
|
|
28
30
|
getNextTokens(): string[];
|
|
@@ -10,6 +10,7 @@ export declare class Reference implements Pattern {
|
|
|
10
10
|
private _cachedPattern;
|
|
11
11
|
private _pattern;
|
|
12
12
|
private _children;
|
|
13
|
+
private _firstIndex;
|
|
13
14
|
shouldCompactAst: boolean;
|
|
14
15
|
get id(): string;
|
|
15
16
|
get type(): string;
|
|
@@ -17,6 +18,7 @@ export declare class Reference implements Pattern {
|
|
|
17
18
|
get parent(): Pattern | null;
|
|
18
19
|
set parent(pattern: Pattern | null);
|
|
19
20
|
get children(): Pattern[];
|
|
21
|
+
get startedOnIndex(): number;
|
|
20
22
|
constructor(name: string);
|
|
21
23
|
test(text: string): boolean;
|
|
22
24
|
exec(text: string, record?: boolean): ParseResult;
|
package/dist/patterns/Regex.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export declare class Regex implements Pattern {
|
|
|
22
22
|
get parent(): Pattern | null;
|
|
23
23
|
set parent(pattern: Pattern | null);
|
|
24
24
|
get children(): Pattern[];
|
|
25
|
+
get startedOnIndex(): number;
|
|
25
26
|
constructor(name: string, regex: string);
|
|
26
27
|
private assertArguments;
|
|
27
28
|
test(text: string): boolean;
|
|
@@ -26,6 +26,7 @@ export declare class Repeat implements Pattern {
|
|
|
26
26
|
get children(): Pattern[];
|
|
27
27
|
get min(): number;
|
|
28
28
|
get max(): number;
|
|
29
|
+
get startedOnIndex(): number;
|
|
29
30
|
constructor(name: string, pattern: Pattern, options?: RepeatOptions);
|
|
30
31
|
parse(cursor: Cursor): Node | null;
|
|
31
32
|
exec(text: string): ParseResult;
|
|
@@ -16,6 +16,7 @@ export declare class Sequence implements Pattern {
|
|
|
16
16
|
get parent(): Pattern | null;
|
|
17
17
|
set parent(pattern: Pattern | null);
|
|
18
18
|
get children(): Pattern[];
|
|
19
|
+
get startedOnIndex(): number;
|
|
19
20
|
constructor(name: string, sequence: Pattern[]);
|
|
20
21
|
private _assignChildrenToParent;
|
|
21
22
|
test(text: string): boolean;
|
|
@@ -26,6 +27,7 @@ export declare class Sequence implements Pattern {
|
|
|
26
27
|
parse(cursor: Cursor): Node | null;
|
|
27
28
|
private tryToParse;
|
|
28
29
|
private getLastValidNode;
|
|
30
|
+
private _isBeyondRecursiveAllowance;
|
|
29
31
|
private areRemainingPatternsOptional;
|
|
30
32
|
private createNode;
|
|
31
33
|
getTokens(): string[];
|
package/package.json
CHANGED
package/src/patterns/Context.ts
CHANGED
|
@@ -40,6 +40,10 @@ export class Context implements Pattern {
|
|
|
40
40
|
return this._children;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
get startedOnIndex(){
|
|
44
|
+
return this.children[0].startedOnIndex;
|
|
45
|
+
}
|
|
46
|
+
|
|
43
47
|
getPatternWithinContext(name: string): Pattern | null {
|
|
44
48
|
return this._patterns[name] || null;
|
|
45
49
|
}
|
|
@@ -96,6 +96,34 @@ function createOptionsExpression() {
|
|
|
96
96
|
return expressionPattern;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
function createTailExpression() {
|
|
100
|
+
const a = new Literal("a", "a");
|
|
101
|
+
const b = new Literal("b", "b");
|
|
102
|
+
const c = new Literal("c", "c");
|
|
103
|
+
const variable = new Options("variable", [a, b, c]);
|
|
104
|
+
const period = new Literal(".", ".");
|
|
105
|
+
|
|
106
|
+
const refinement = new Sequence("refinement", [period, variable]);
|
|
107
|
+
const refinementExpression = new Sequence("refinement-expression", [
|
|
108
|
+
new Reference("expression"),
|
|
109
|
+
refinement
|
|
110
|
+
]);
|
|
111
|
+
|
|
112
|
+
const invocation = new Literal("invocation", "()");
|
|
113
|
+
const invocationExpression = new Sequence("invocation-expression", [
|
|
114
|
+
new Reference("expression"),
|
|
115
|
+
invocation
|
|
116
|
+
]);
|
|
117
|
+
|
|
118
|
+
const expression = new ExpressionPattern("expression", [
|
|
119
|
+
refinementExpression,
|
|
120
|
+
invocationExpression,
|
|
121
|
+
variable
|
|
122
|
+
]);
|
|
123
|
+
|
|
124
|
+
return expression;
|
|
125
|
+
}
|
|
126
|
+
|
|
99
127
|
describe("Expression Pattern", () => {
|
|
100
128
|
test("Single Expression", () => {
|
|
101
129
|
const expression = createExpressionPattern();
|
|
@@ -113,6 +141,16 @@ describe("Expression Pattern", () => {
|
|
|
113
141
|
expect(result).toBe(result);
|
|
114
142
|
});
|
|
115
143
|
|
|
144
|
+
test("Tail", () => {
|
|
145
|
+
const expression = createTailExpression();
|
|
146
|
+
let result = expression.exec("a");
|
|
147
|
+
result = expression.exec("a.b");
|
|
148
|
+
result = expression.exec("a.b.c");
|
|
149
|
+
result = expression.exec("a.b.c()()()");
|
|
150
|
+
|
|
151
|
+
expect(result).toBe(result);
|
|
152
|
+
});
|
|
153
|
+
|
|
116
154
|
test("Options like", () => {
|
|
117
155
|
const expression = createOptionsExpression();
|
|
118
156
|
const autoComplete = new AutoComplete(expression);
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { Node } from "../ast/Node";
|
|
2
2
|
import { Cursor } from "./Cursor";
|
|
3
|
-
import { DepthCache } from "./DepthCache";
|
|
4
3
|
import { ParseResult } from "./ParseResult";
|
|
5
4
|
import { Pattern } from "./Pattern";
|
|
6
5
|
import { findPattern } from "./findPattern";
|
|
7
6
|
import { Sequence } from "./Sequence";
|
|
8
7
|
|
|
9
8
|
let indexId = 0;
|
|
10
|
-
const depthCache = new DepthCache();
|
|
11
9
|
|
|
12
10
|
function createNode(name: string, children: Node[]) {
|
|
13
11
|
return new Node("expression", name, 0, 0, children, "");
|
|
@@ -74,6 +72,10 @@ export class ExpressionPattern implements Pattern {
|
|
|
74
72
|
return this._recursivePatterns;
|
|
75
73
|
}
|
|
76
74
|
|
|
75
|
+
get startedOnIndex() {
|
|
76
|
+
return this._firstIndex;
|
|
77
|
+
}
|
|
78
|
+
|
|
77
79
|
constructor(name: string, patterns: Pattern[]) {
|
|
78
80
|
if (patterns.length === 0) {
|
|
79
81
|
throw new Error("Need at least one pattern with an 'expression' pattern.");
|
|
@@ -211,15 +213,9 @@ export class ExpressionPattern implements Pattern {
|
|
|
211
213
|
}
|
|
212
214
|
|
|
213
215
|
parse(cursor: Cursor): Node | null {
|
|
214
|
-
// This is a cache to help with speed
|
|
215
|
-
this._firstIndex = cursor.index;
|
|
216
|
-
depthCache.incrementDepth(this._id, this._firstIndex);
|
|
217
|
-
|
|
218
216
|
this._firstIndex = cursor.index;
|
|
219
217
|
const node = this._tryToParse(cursor);
|
|
220
218
|
|
|
221
|
-
depthCache.decrementDepth(this._id, this._firstIndex);
|
|
222
|
-
|
|
223
219
|
if (node != null) {
|
|
224
220
|
cursor.moveTo(node.lastIndex);
|
|
225
221
|
cursor.resolveError();
|
|
@@ -254,12 +250,11 @@ export class ExpressionPattern implements Pattern {
|
|
|
254
250
|
}
|
|
255
251
|
|
|
256
252
|
private _tryToParse(cursor: Cursor): Node | null {
|
|
257
|
-
if (
|
|
253
|
+
if (this._isBeyondRecursiveAllowance()) {
|
|
258
254
|
cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
|
|
259
255
|
return null;
|
|
260
256
|
}
|
|
261
257
|
|
|
262
|
-
|
|
263
258
|
let lastUnaryNode: Node | null = null;
|
|
264
259
|
let lastBinaryNode: Node | null = null;
|
|
265
260
|
let onIndex = cursor.index;
|
|
@@ -330,7 +325,9 @@ export class ExpressionPattern implements Pattern {
|
|
|
330
325
|
}
|
|
331
326
|
break outer;
|
|
332
327
|
}
|
|
333
|
-
|
|
328
|
+
onIndex = cursor.index;
|
|
329
|
+
i = -1;
|
|
330
|
+
continue;
|
|
334
331
|
}
|
|
335
332
|
}
|
|
336
333
|
|
|
@@ -446,6 +443,24 @@ export class ExpressionPattern implements Pattern {
|
|
|
446
443
|
}
|
|
447
444
|
}
|
|
448
445
|
|
|
446
|
+
private _isBeyondRecursiveAllowance() {
|
|
447
|
+
let depth = 0;
|
|
448
|
+
let pattern: Pattern | null = this;
|
|
449
|
+
|
|
450
|
+
while (pattern != null) {
|
|
451
|
+
if (pattern.id === this.id && pattern.startedOnIndex === this.startedOnIndex) {
|
|
452
|
+
depth++;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (depth > 2) {
|
|
456
|
+
return true;
|
|
457
|
+
}
|
|
458
|
+
pattern = pattern.parent;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
|
|
449
464
|
test(text: string) {
|
|
450
465
|
const cursor = new Cursor(text);
|
|
451
466
|
const ast = this.parse(cursor);
|
|
@@ -23,6 +23,7 @@ export class FiniteRepeat implements Pattern {
|
|
|
23
23
|
private _min: number;
|
|
24
24
|
private _max: number;
|
|
25
25
|
private _trimDivider: boolean;
|
|
26
|
+
private _firstIndex: number;
|
|
26
27
|
|
|
27
28
|
shouldCompactAst = false;
|
|
28
29
|
|
|
@@ -58,6 +59,10 @@ export class FiniteRepeat implements Pattern {
|
|
|
58
59
|
return this._max;
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
get startedOnIndex() {
|
|
63
|
+
return this._firstIndex;
|
|
64
|
+
}
|
|
65
|
+
|
|
61
66
|
constructor(name: string, pattern: Pattern, options: FiniteRepeatOptions = {}) {
|
|
62
67
|
this._id = `finite-repeat-${idIndex++}`;
|
|
63
68
|
this._type = "finite-repeat";
|
|
@@ -68,6 +73,7 @@ export class FiniteRepeat implements Pattern {
|
|
|
68
73
|
this._min = options.min != null ? Math.max(options.min, 1) : 1;
|
|
69
74
|
this._max = Math.max(this.min, options.max || this.min);
|
|
70
75
|
this._trimDivider = options.trimDivider == null ? false : options.trimDivider;
|
|
76
|
+
this._firstIndex = 0;
|
|
71
77
|
|
|
72
78
|
for (let i = 0; i < this._max; i++) {
|
|
73
79
|
const child = pattern.clone();
|
|
@@ -85,6 +91,8 @@ export class FiniteRepeat implements Pattern {
|
|
|
85
91
|
}
|
|
86
92
|
|
|
87
93
|
parse(cursor: Cursor): Node | null {
|
|
94
|
+
this._firstIndex = cursor.index;
|
|
95
|
+
|
|
88
96
|
const startIndex = cursor.index;
|
|
89
97
|
const nodes: Node[] = [];
|
|
90
98
|
const modulo = this._hasDivider ? 2 : 1;
|
|
@@ -56,6 +56,10 @@ export class InfiniteRepeat implements Pattern {
|
|
|
56
56
|
return this._min;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
get startedOnIndex(){
|
|
60
|
+
return this._firstIndex;
|
|
61
|
+
}
|
|
62
|
+
|
|
59
63
|
constructor(name: string, pattern: Pattern, options: InfiniteRepeatOptions = {}) {
|
|
60
64
|
const min = options.min != null ? Math.max(options.min, 1) : 1;
|
|
61
65
|
const divider = options.divider;
|
package/src/patterns/Literal.ts
CHANGED
package/src/patterns/Not.ts
CHANGED
package/src/patterns/Optional.ts
CHANGED
|
@@ -38,6 +38,10 @@ export class Optional 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(name: string, pattern: Pattern) {
|
|
42
46
|
this._id = `optional-${idIndex++}`;
|
|
43
47
|
this._type = "optional";
|
package/src/patterns/Options.ts
CHANGED
|
@@ -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 (
|
|
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
|
|
package/src/patterns/Pattern.ts
CHANGED
|
@@ -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
|
|
package/src/patterns/Regex.ts
CHANGED
|
@@ -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 =
|
|
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
|
|
package/src/patterns/Repeat.ts
CHANGED
|
@@ -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";
|
package/src/patterns/Sequence.ts
CHANGED
|
@@ -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 (
|
|
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
|
-
}
|