clarity-pattern-parser 5.0.0 → 6.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.
- package/README.md +328 -38
- package/TODO.md +55 -1
- package/dist/ast/Node.d.ts +8 -2
- package/dist/index.browser.js +470 -205
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.esm.js +469 -206
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +470 -205
- package/dist/index.js.map +1 -1
- package/dist/intellisense/AutoComplete.d.ts +28 -0
- package/dist/intellisense/Suggestion.d.ts +11 -0
- package/dist/intellisense/SuggestionOption.d.ts +4 -0
- package/dist/patterns/And.d.ts +7 -7
- package/dist/patterns/Cursor.d.ts +6 -4
- package/dist/patterns/CursorHistory.d.ts +2 -2
- package/dist/patterns/Literal.d.ts +7 -8
- package/dist/patterns/Not.d.ts +8 -5
- package/dist/patterns/Or.d.ts +7 -5
- package/dist/patterns/Pattern.d.ts +7 -4
- package/dist/patterns/Reference.d.ts +10 -7
- package/dist/patterns/Regex.d.ts +7 -8
- package/dist/patterns/Repeat.d.ts +7 -7
- package/package.json +1 -1
- package/src/ast/Node.test.ts +110 -0
- package/src/ast/Node.ts +71 -5
- package/src/index.ts +14 -3
- package/src/intellisense/AutoComplete.test.ts +90 -12
- package/src/intellisense/AutoComplete.ts +66 -12
- package/src/intellisense/Suggestion.ts +3 -4
- package/src/intellisense/javascript/Javascript.test.ts +56 -56
- package/src/intellisense/javascript/escapedCharacter.ts +0 -1
- package/src/intellisense/javascript/exponent.ts +0 -2
- package/src/intellisense/javascript/fraction.ts +0 -2
- package/src/patterns/And.test.ts +63 -52
- package/src/patterns/And.ts +58 -36
- package/src/patterns/Cursor.ts +17 -14
- package/src/patterns/CursorHistory.ts +8 -8
- package/src/patterns/Literal.test.ts +70 -38
- package/src/patterns/Literal.ts +31 -42
- package/src/patterns/Not.test.ts +88 -8
- package/src/patterns/Not.ts +54 -14
- package/src/patterns/Or.test.ts +117 -13
- package/src/patterns/Or.ts +36 -13
- package/src/patterns/Pattern.ts +7 -4
- package/src/patterns/Reference.test.ts +117 -28
- package/src/patterns/Reference.ts +58 -32
- package/src/patterns/Regex.test.ts +67 -35
- package/src/patterns/Regex.ts +31 -43
- package/src/patterns/Repeat.test.ts +63 -41
- package/src/patterns/Repeat.ts +51 -38
- package/src/patterns/getNextPattern.test.ts +0 -39
- package/src/patterns/getNextPattern.ts +0 -18
package/src/patterns/And.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { Pattern } from "./Pattern";
|
|
|
3
3
|
import { Node } from "../ast/Node";
|
|
4
4
|
import { clonePatterns } from "./clonePatterns";
|
|
5
5
|
import { filterOutNull } from "./filterOutNull";
|
|
6
|
-
import { getNextPattern } from "./getNextPattern";
|
|
7
6
|
import { findPattern } from "./findPattern";
|
|
8
7
|
|
|
9
8
|
export class And implements Pattern {
|
|
@@ -14,7 +13,6 @@ export class And implements Pattern {
|
|
|
14
13
|
private _isOptional: boolean;
|
|
15
14
|
private _nodes: (Node | null)[];
|
|
16
15
|
private _firstIndex: number;
|
|
17
|
-
private _shouldReduceAst: boolean;
|
|
18
16
|
|
|
19
17
|
get type(): string {
|
|
20
18
|
return this._type;
|
|
@@ -54,7 +52,6 @@ export class And implements Pattern {
|
|
|
54
52
|
this._parent = null;
|
|
55
53
|
this._children = children;
|
|
56
54
|
this._firstIndex = -1
|
|
57
|
-
this._shouldReduceAst = false;
|
|
58
55
|
this._nodes = [];
|
|
59
56
|
}
|
|
60
57
|
|
|
@@ -64,12 +61,19 @@ export class And implements Pattern {
|
|
|
64
61
|
}
|
|
65
62
|
}
|
|
66
63
|
|
|
67
|
-
|
|
64
|
+
test(text: string) {
|
|
68
65
|
const cursor = new Cursor(text);
|
|
69
|
-
const ast = this.parse(cursor)
|
|
66
|
+
const ast = this.parse(cursor);
|
|
67
|
+
|
|
68
|
+
return ast?.value === text;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
exec(text: string) {
|
|
72
|
+
const cursor = new Cursor(text);
|
|
73
|
+
const ast = this.parse(cursor);
|
|
70
74
|
|
|
71
75
|
return {
|
|
72
|
-
ast,
|
|
76
|
+
ast: ast?.value === text ? ast : null,
|
|
73
77
|
cursor
|
|
74
78
|
};
|
|
75
79
|
}
|
|
@@ -115,32 +119,41 @@ export class And implements Pattern {
|
|
|
115
119
|
if (hasMorePatterns) {
|
|
116
120
|
if (hadMatch) {
|
|
117
121
|
if (cursor.hasNext()) {
|
|
122
|
+
// We had a match. Increment the cursor and use the next pattern.
|
|
118
123
|
cursor.next();
|
|
119
124
|
continue;
|
|
120
125
|
} else {
|
|
126
|
+
// We are at the end of the text, it may still be valid, if all the
|
|
127
|
+
// following patterns are optional.
|
|
121
128
|
if (this.areRemainingPatternsOptional(i)) {
|
|
122
129
|
passed = true;
|
|
123
130
|
break;
|
|
124
131
|
}
|
|
125
132
|
|
|
133
|
+
// We didn't finish the parsing sequence.
|
|
126
134
|
cursor.recordErrorAt(cursor.index + 1, this);
|
|
127
135
|
break;
|
|
128
136
|
}
|
|
129
137
|
} else {
|
|
138
|
+
// An optional pattern did not matched, try from the same spot on the next
|
|
139
|
+
// pattern.
|
|
130
140
|
cursor.moveTo(runningCursorIndex);
|
|
131
141
|
continue;
|
|
132
142
|
}
|
|
133
143
|
} else {
|
|
144
|
+
// If we don't have any results from what we parsed then record error.
|
|
134
145
|
const lastNode = this.getLastValidNode();
|
|
135
146
|
if (lastNode === null) {
|
|
136
147
|
cursor.recordErrorAt(cursor.index, this);
|
|
137
148
|
break;
|
|
138
149
|
}
|
|
139
150
|
|
|
151
|
+
// The sequence was parsed fully.
|
|
140
152
|
passed = true;
|
|
141
153
|
break;
|
|
142
154
|
}
|
|
143
155
|
} else {
|
|
156
|
+
// The pattern failed.
|
|
144
157
|
cursor.moveTo(this._firstIndex);
|
|
145
158
|
break;
|
|
146
159
|
}
|
|
@@ -181,28 +194,15 @@ export class And implements Pattern {
|
|
|
181
194
|
|
|
182
195
|
cursor.moveTo(lastIndex)
|
|
183
196
|
|
|
184
|
-
if (this._shouldReduceAst) {
|
|
185
|
-
children.length = 0;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
197
|
return new Node(
|
|
189
198
|
"and",
|
|
190
199
|
this._name,
|
|
191
200
|
this._firstIndex,
|
|
192
201
|
lastIndex,
|
|
193
|
-
children
|
|
194
|
-
this._shouldReduceAst ? value : undefined
|
|
202
|
+
children
|
|
195
203
|
);
|
|
196
204
|
}
|
|
197
205
|
|
|
198
|
-
enableAstReduction(): void {
|
|
199
|
-
this._shouldReduceAst = true;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
disableAstReduction(): void {
|
|
203
|
-
this._shouldReduceAst = false;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
206
|
getTokens(): string[] {
|
|
207
207
|
const tokens: string[] = [];
|
|
208
208
|
|
|
@@ -217,14 +217,31 @@ export class And implements Pattern {
|
|
|
217
217
|
return tokens;
|
|
218
218
|
}
|
|
219
219
|
|
|
220
|
-
|
|
220
|
+
getTokensAfter(childReference: Pattern): string[] {
|
|
221
|
+
const patterns = this.getPatternsAfter(childReference);
|
|
222
|
+
const tokens: string[] = [];
|
|
223
|
+
|
|
224
|
+
patterns.forEach(p => tokens.push(...p.getTokens()));
|
|
225
|
+
|
|
226
|
+
return tokens;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
getNextTokens(): string[] {
|
|
230
|
+
if (this.parent == null) {
|
|
231
|
+
return []
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return this.parent.getTokensAfter(this);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
getPatternsAfter(childReference: Pattern): Pattern[] {
|
|
221
238
|
let nextSibling: Pattern | null = null;
|
|
222
239
|
let nextSiblingIndex = -1;
|
|
223
240
|
let index = -1;
|
|
224
|
-
const
|
|
241
|
+
const patterns: Pattern[] = [];
|
|
225
242
|
|
|
226
243
|
for (let i = 0; i < this._children.length; i++) {
|
|
227
|
-
if (this._children[i] ===
|
|
244
|
+
if (this._children[i] === childReference) {
|
|
228
245
|
if (i + 1 < this._children.length) {
|
|
229
246
|
nextSibling = this._children[i + 1];
|
|
230
247
|
}
|
|
@@ -234,48 +251,53 @@ export class And implements Pattern {
|
|
|
234
251
|
}
|
|
235
252
|
}
|
|
236
253
|
|
|
254
|
+
// The child reference isn't one of the child patterns.
|
|
237
255
|
if (index === -1) {
|
|
238
256
|
return [];
|
|
239
257
|
}
|
|
240
258
|
|
|
259
|
+
// The reference pattern is the last child. So ask the parent for the next pattern.
|
|
241
260
|
if (nextSiblingIndex === this._children.length && this._parent !== null) {
|
|
242
|
-
return this._parent.
|
|
261
|
+
return this._parent.getPatternsAfter(this);
|
|
243
262
|
}
|
|
244
263
|
|
|
264
|
+
// Next pattern isn't optional so send it back as the next patterns.
|
|
245
265
|
if (nextSibling !== null && !nextSibling.isOptional) {
|
|
246
|
-
return nextSibling
|
|
266
|
+
return [nextSibling];
|
|
247
267
|
}
|
|
248
268
|
|
|
269
|
+
// Send back as many optional patterns as possible.
|
|
249
270
|
if (nextSibling !== null && nextSibling.isOptional) {
|
|
250
271
|
for (let i = nextSiblingIndex; i < this._children.length; i++) {
|
|
251
272
|
const child = this._children[i];
|
|
252
|
-
|
|
273
|
+
patterns.push(child);
|
|
253
274
|
|
|
254
275
|
if (!child.isOptional) {
|
|
255
276
|
break;
|
|
256
277
|
}
|
|
257
278
|
|
|
258
279
|
if (i === this._children.length - 1 && this._parent !== null) {
|
|
259
|
-
|
|
280
|
+
patterns.push(...this._parent.getPatternsAfter(this));
|
|
260
281
|
}
|
|
261
282
|
}
|
|
262
283
|
}
|
|
263
284
|
|
|
264
|
-
return
|
|
285
|
+
return patterns;
|
|
265
286
|
}
|
|
266
287
|
|
|
267
|
-
|
|
268
|
-
|
|
288
|
+
getNextPatterns(): Pattern[] {
|
|
289
|
+
if (this.parent == null) {
|
|
290
|
+
return [];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return this.parent.getPatternsAfter(this)
|
|
269
294
|
}
|
|
270
295
|
|
|
271
|
-
findPattern(
|
|
272
|
-
return findPattern(this,
|
|
296
|
+
findPattern(predicate: (p: Pattern) => boolean): Pattern | null {
|
|
297
|
+
return findPattern(this, predicate);
|
|
273
298
|
}
|
|
274
299
|
|
|
275
300
|
clone(name = this._name, isOptional = this._isOptional): Pattern {
|
|
276
|
-
|
|
277
|
-
and._shouldReduceAst = this._shouldReduceAst;
|
|
278
|
-
|
|
279
|
-
return and
|
|
301
|
+
return new And(name, this._children, isOptional)
|
|
280
302
|
}
|
|
281
303
|
}
|
package/src/patterns/Cursor.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Node } from "../ast/Node";
|
|
2
2
|
import { CursorHistory, Match } from "./CursorHistory";
|
|
3
|
+
import { ParseError } from "./ParseError";
|
|
4
|
+
import { Pattern } from "./Pattern";
|
|
3
5
|
|
|
4
6
|
export class Cursor {
|
|
5
7
|
private _text: string;
|
|
@@ -16,21 +18,21 @@ export class Cursor {
|
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
get isOnLast(): boolean {
|
|
19
|
-
return this._index === this.
|
|
21
|
+
return this._index === this.getLastIndex();
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
get isRecording(): boolean {
|
|
23
25
|
return this._history.isRecording;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
get leafMatch(): Match {
|
|
27
|
-
return this._history.leafMatch;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
28
|
get rootMatch(): Match {
|
|
31
29
|
return this._history.rootMatch;
|
|
32
30
|
}
|
|
33
31
|
|
|
32
|
+
get leafMatch(): Match {
|
|
33
|
+
return this._history.leafMatch;
|
|
34
|
+
}
|
|
35
|
+
|
|
34
36
|
get furthestError(): ParseError | null {
|
|
35
37
|
return this._history.furthestError;
|
|
36
38
|
}
|
|
@@ -70,16 +72,16 @@ export class Cursor {
|
|
|
70
72
|
return this._index + 1 < this._length;
|
|
71
73
|
}
|
|
72
74
|
|
|
73
|
-
hasPrevious(): boolean {
|
|
74
|
-
return this._index - 1 >= 0;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
75
|
next(): void {
|
|
78
76
|
if (this.hasNext()) {
|
|
79
77
|
this._index++;
|
|
80
78
|
}
|
|
81
79
|
}
|
|
82
80
|
|
|
81
|
+
hasPrevious(): boolean {
|
|
82
|
+
return this._index - 1 >= 0;
|
|
83
|
+
}
|
|
84
|
+
|
|
83
85
|
previous(): void {
|
|
84
86
|
if (this.hasPrevious()) {
|
|
85
87
|
this._index--;
|
|
@@ -97,7 +99,11 @@ export class Cursor {
|
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
moveToLastChar(): void {
|
|
100
|
-
this._index = this.
|
|
102
|
+
this._index = this.getLastIndex();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
getLastIndex(): number {
|
|
106
|
+
return this._length - 1;
|
|
101
107
|
}
|
|
102
108
|
|
|
103
109
|
getChars(first: number, last: number): string {
|
|
@@ -124,7 +130,4 @@ export class Cursor {
|
|
|
124
130
|
this._history.stopRecording();
|
|
125
131
|
}
|
|
126
132
|
|
|
127
|
-
private _getLastIndex(): number {
|
|
128
|
-
return this._length - 1;
|
|
129
|
-
}
|
|
130
133
|
}
|
|
@@ -17,6 +17,14 @@ export class CursorHistory {
|
|
|
17
17
|
private _nodes: Node[] = [];
|
|
18
18
|
private _errors: ParseError[] = [];
|
|
19
19
|
|
|
20
|
+
get isRecording(): boolean {
|
|
21
|
+
return this._isRecording;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get rootMatch(): Match {
|
|
25
|
+
return this._rootMatch;
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
get leafMatch(): Match {
|
|
21
29
|
return this._leafMatch;
|
|
22
30
|
}
|
|
@@ -25,10 +33,6 @@ export class CursorHistory {
|
|
|
25
33
|
return this._furthestError;
|
|
26
34
|
}
|
|
27
35
|
|
|
28
|
-
get isRecording(): boolean {
|
|
29
|
-
return this._isRecording;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
36
|
get errors(): ParseError[] {
|
|
33
37
|
return this._errors;
|
|
34
38
|
}
|
|
@@ -45,10 +49,6 @@ export class CursorHistory {
|
|
|
45
49
|
return this._patterns;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
get rootMatch(): Match {
|
|
49
|
-
return this._rootMatch;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
52
|
recordMatch(pattern: Pattern, node: Node): void {
|
|
53
53
|
if (this._isRecording) {
|
|
54
54
|
this._patterns.push(pattern);
|
|
@@ -70,53 +70,22 @@ describe("Literal", () => {
|
|
|
70
70
|
});
|
|
71
71
|
|
|
72
72
|
test("Get Tokens", () => {
|
|
73
|
-
const
|
|
74
|
-
new Literal("a", "A"),
|
|
75
|
-
new Literal("b", "B")
|
|
76
|
-
]);
|
|
73
|
+
const a = new Literal("a", "A");
|
|
77
74
|
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
let tokens = a.getTokens();
|
|
82
|
-
let expectedTokens = ["A"];
|
|
83
|
-
|
|
84
|
-
expect(tokens).toEqual(expectedTokens);
|
|
85
|
-
|
|
86
|
-
a.enableContextualTokenAggregation();
|
|
87
|
-
|
|
88
|
-
tokens = a.getTokens();
|
|
89
|
-
expectedTokens = ["AB"];
|
|
90
|
-
|
|
91
|
-
expect(tokens).toEqual(expectedTokens);
|
|
92
|
-
|
|
93
|
-
a.disableContextualTokenAggregation();
|
|
94
|
-
|
|
95
|
-
tokens = a.getTokens();
|
|
96
|
-
expectedTokens = ["A"];
|
|
75
|
+
const tokens = a.getTokens();
|
|
76
|
+
const expectedTokens = ["A"];
|
|
97
77
|
|
|
98
78
|
expect(tokens).toEqual(expectedTokens);
|
|
99
79
|
});
|
|
100
80
|
|
|
101
|
-
test("Get
|
|
81
|
+
test("Get Tokens After", () => {
|
|
102
82
|
const literal = new Literal("a", "A");
|
|
103
|
-
const tokens = literal.
|
|
83
|
+
const tokens = literal.getTokensAfter(new Literal("bogus", "bogus"));
|
|
104
84
|
const expected: string[] = [];
|
|
105
85
|
|
|
106
86
|
expect(tokens).toEqual(expected)
|
|
107
87
|
});
|
|
108
88
|
|
|
109
|
-
test("Get Next Pattern", () => {
|
|
110
|
-
const parent = new And("parent", [
|
|
111
|
-
new Literal("a", "A"),
|
|
112
|
-
new Literal("b", "B")
|
|
113
|
-
]);
|
|
114
|
-
|
|
115
|
-
const nextPattern = parent.children[0].getNextPattern();
|
|
116
|
-
|
|
117
|
-
expect(nextPattern?.name).toBe("b")
|
|
118
|
-
});
|
|
119
|
-
|
|
120
89
|
test("Properties", () => {
|
|
121
90
|
const literal = new Literal("a", "A");
|
|
122
91
|
|
|
@@ -126,9 +95,72 @@ describe("Literal", () => {
|
|
|
126
95
|
expect(literal.children).toEqual([]);
|
|
127
96
|
});
|
|
128
97
|
|
|
129
|
-
test("
|
|
98
|
+
test("Exec", () => {
|
|
130
99
|
const literal = new Literal("a", "A");
|
|
131
|
-
const { ast: result } = literal.
|
|
100
|
+
const { ast: result } = literal.exec("B");
|
|
132
101
|
expect(result).toBeNull()
|
|
133
102
|
});
|
|
103
|
+
|
|
104
|
+
test("Test With No Match", () => {
|
|
105
|
+
const literal = new Literal("a", "A");
|
|
106
|
+
const isMatch = literal.test("B");
|
|
107
|
+
|
|
108
|
+
expect(isMatch).toBeFalsy();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test("Test With Match", () => {
|
|
112
|
+
const literal = new Literal("a", "A");
|
|
113
|
+
const isMatch = literal.test("A");
|
|
114
|
+
|
|
115
|
+
expect(isMatch).toBeTruthy();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("Get Next Tokens", () => {
|
|
119
|
+
const sequence = new And("sequence", [new Literal("a", "A")]);
|
|
120
|
+
const parent = new And("parent", [sequence, new Literal("b", "B")]);
|
|
121
|
+
|
|
122
|
+
const a = parent.findPattern(p => p.name === "a");
|
|
123
|
+
const tokens = a?.getNextTokens() || [];
|
|
124
|
+
|
|
125
|
+
expect(tokens[0]).toBe("B");
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
test("Get Next Tokens With Null Parent", () => {
|
|
129
|
+
const a = new Literal("a", "A");
|
|
130
|
+
const tokens = a.getNextTokens();
|
|
131
|
+
|
|
132
|
+
expect(tokens.length).toBe(0);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
test("Get Next Patterns", () => {
|
|
136
|
+
const sequence = new And("sequence", [new Literal("a", "A")]);
|
|
137
|
+
const parent = new And("parent", [sequence, new Literal("b", "B")]);
|
|
138
|
+
|
|
139
|
+
const a = parent.findPattern(p => p.name === "a");
|
|
140
|
+
const nextPatterns = a?.getNextPatterns() || [];
|
|
141
|
+
const b = parent.findPattern(p => p.name === "b")
|
|
142
|
+
|
|
143
|
+
expect(nextPatterns[0]).toBe(b);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("Get Next Patterns With Null Parent", () => {
|
|
147
|
+
const a = new Literal("a", "A");
|
|
148
|
+
const nextPatterns = a.getNextPatterns();
|
|
149
|
+
|
|
150
|
+
expect(nextPatterns.length).toBe(0);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
test("Get Patterns After", () => {
|
|
154
|
+
const a = new Literal("a", "A");
|
|
155
|
+
const patterns = a.getPatternsAfter();
|
|
156
|
+
|
|
157
|
+
expect(patterns.length).toBe(0);
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
test("Find Pattern", () => {
|
|
161
|
+
const a = new Literal("a", "A");
|
|
162
|
+
const pattern = a.findPattern(p => p.name === "nada");
|
|
163
|
+
|
|
164
|
+
expect(pattern).toBeNull();
|
|
165
|
+
});
|
|
134
166
|
});
|
package/src/patterns/Literal.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Node } from "../ast/Node";
|
|
2
2
|
import { Cursor } from "./Cursor";
|
|
3
|
-
import { getNextPattern } from "./getNextPattern";
|
|
4
3
|
import { Pattern } from "./Pattern";
|
|
5
4
|
|
|
6
5
|
export class Literal implements Pattern {
|
|
@@ -12,8 +11,6 @@ export class Literal implements Pattern {
|
|
|
12
11
|
private _runes: string[];
|
|
13
12
|
private _firstIndex: number;
|
|
14
13
|
private _lastIndex: number;
|
|
15
|
-
private _hasContextualTokenAggregation: boolean;
|
|
16
|
-
private _isRetrievingContextualTokens: boolean;
|
|
17
14
|
|
|
18
15
|
get type(): string {
|
|
19
16
|
return this._type;
|
|
@@ -40,10 +37,10 @@ export class Literal implements Pattern {
|
|
|
40
37
|
}
|
|
41
38
|
|
|
42
39
|
constructor(name: string, value: string, isOptional = false) {
|
|
43
|
-
if (value.length === 0){
|
|
40
|
+
if (value.length === 0) {
|
|
44
41
|
throw new Error("Value Cannot be empty.");
|
|
45
42
|
}
|
|
46
|
-
|
|
43
|
+
|
|
47
44
|
this._type = "literal";
|
|
48
45
|
this._name = name;
|
|
49
46
|
this._literal = value;
|
|
@@ -52,16 +49,21 @@ export class Literal implements Pattern {
|
|
|
52
49
|
this._parent = null;
|
|
53
50
|
this._firstIndex = 0;
|
|
54
51
|
this._lastIndex = 0;
|
|
55
|
-
this._hasContextualTokenAggregation = false;
|
|
56
|
-
this._isRetrievingContextualTokens = false;
|
|
57
52
|
}
|
|
58
53
|
|
|
59
|
-
|
|
54
|
+
test(text: string) {
|
|
55
|
+
const cursor = new Cursor(text);
|
|
56
|
+
const ast = this.parse(cursor);
|
|
57
|
+
|
|
58
|
+
return ast?.value === text;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
exec(text: string) {
|
|
60
62
|
const cursor = new Cursor(text);
|
|
61
|
-
const ast = this.parse(cursor)
|
|
63
|
+
const ast = this.parse(cursor);
|
|
62
64
|
|
|
63
65
|
return {
|
|
64
|
-
ast,
|
|
66
|
+
ast: ast?.value === text ? ast : null,
|
|
65
67
|
cursor
|
|
66
68
|
};
|
|
67
69
|
}
|
|
@@ -123,59 +125,46 @@ export class Literal implements Pattern {
|
|
|
123
125
|
this._name,
|
|
124
126
|
this._firstIndex,
|
|
125
127
|
this._lastIndex,
|
|
126
|
-
|
|
128
|
+
undefined,
|
|
127
129
|
this._literal
|
|
128
130
|
);
|
|
129
131
|
}
|
|
130
132
|
|
|
131
133
|
clone(name = this._name, isOptional = this._isOptional): Pattern {
|
|
132
134
|
const clone = new Literal(name, this._literal, isOptional);
|
|
133
|
-
clone._hasContextualTokenAggregation = this._hasContextualTokenAggregation;
|
|
134
135
|
return clone;
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
getTokens(): string[] {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
if (
|
|
141
|
-
this._hasContextualTokenAggregation &&
|
|
142
|
-
parent != null &&
|
|
143
|
-
!this._isRetrievingContextualTokens
|
|
144
|
-
) {
|
|
145
|
-
this._isRetrievingContextualTokens = true;
|
|
146
|
-
|
|
147
|
-
const aggregateTokens: string[] = [];
|
|
148
|
-
const nextTokens = parent.getNextTokens(this);
|
|
149
|
-
|
|
150
|
-
for (const nextToken of nextTokens) {
|
|
151
|
-
aggregateTokens.push(this._literal + nextToken);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
this._isRetrievingContextualTokens = false;
|
|
155
|
-
return aggregateTokens;
|
|
156
|
-
} else {
|
|
157
|
-
return [this._literal];
|
|
158
|
-
}
|
|
139
|
+
return [this._literal];
|
|
159
140
|
}
|
|
160
141
|
|
|
161
|
-
|
|
142
|
+
getTokensAfter(_lastMatched: Pattern): string[] {
|
|
162
143
|
return [];
|
|
163
144
|
}
|
|
164
145
|
|
|
165
|
-
|
|
166
|
-
|
|
146
|
+
getNextTokens(): string[] {
|
|
147
|
+
if (this.parent == null) {
|
|
148
|
+
return []
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return this.parent.getTokensAfter(this);
|
|
167
152
|
}
|
|
168
153
|
|
|
169
|
-
|
|
170
|
-
return
|
|
154
|
+
getPatternsAfter(): Pattern[] {
|
|
155
|
+
return []
|
|
171
156
|
}
|
|
172
157
|
|
|
173
|
-
|
|
174
|
-
this.
|
|
158
|
+
getNextPatterns(): Pattern[] {
|
|
159
|
+
if (this.parent == null) {
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return this.parent.getPatternsAfter(this)
|
|
175
164
|
}
|
|
176
165
|
|
|
177
|
-
|
|
178
|
-
|
|
166
|
+
findPattern(_predicate: (p: Pattern) => boolean): Pattern | null {
|
|
167
|
+
return null;
|
|
179
168
|
}
|
|
180
169
|
|
|
181
170
|
}
|