clarity-pattern-parser 8.4.14 → 9.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/TODO.md +4 -1
- package/dist/grammar/Grammar.d.ts +18 -10
- package/dist/grammar/patterns/andLiteral.d.ts +2 -0
- package/dist/grammar/patterns/anonymousPattern.d.ts +2 -0
- package/dist/grammar/patterns/inlinePattern.d.ts +1 -0
- package/dist/grammar/patterns/literals.d.ts +3 -0
- package/dist/grammar/patterns/pattern.d.ts +2 -2
- package/dist/grammar/patterns.d.ts +2 -0
- package/dist/index.browser.js +472 -185
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.esm.js +471 -186
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +472 -185
- package/dist/index.js.map +1 -1
- package/dist/patterns/And.d.ts +4 -1
- package/dist/patterns/Cursor.d.ts +5 -0
- package/dist/patterns/CursorHistory.d.ts +7 -0
- package/dist/patterns/FiniteRepeat.d.ts +4 -1
- package/dist/patterns/InfiniteRepeat.d.ts +5 -4
- package/dist/patterns/Literal.d.ts +6 -5
- package/dist/patterns/Not.d.ts +5 -4
- package/dist/patterns/Or.d.ts +5 -4
- package/dist/patterns/Pattern.d.ts +4 -2
- package/dist/patterns/Reference.d.ts +5 -4
- package/dist/patterns/Regex.d.ts +5 -4
- package/dist/patterns/Repeat.d.ts +3 -0
- package/dist/patterns/arePatternsEqual.d.ts +2 -0
- package/package.json +1 -1
- package/src/grammar/Grammar.test.ts +126 -72
- package/src/grammar/Grammar.ts +241 -158
- package/src/grammar/patterns/anonymousPattern.ts +23 -0
- package/src/grammar/patterns/body.ts +9 -6
- package/src/grammar/patterns/comment.ts +3 -2
- package/src/grammar/patterns/grammar.ts +15 -12
- package/src/grammar/patterns/import.ts +18 -12
- package/src/grammar/patterns/literal.ts +2 -3
- package/src/grammar/patterns/literals.ts +20 -0
- package/src/grammar/patterns/optionsLiteral.ts +19 -0
- package/src/grammar/patterns/pattern.ts +23 -9
- package/src/grammar/patterns/regexLiteral.ts +1 -0
- package/src/grammar/patterns/repeatLiteral.ts +30 -25
- package/src/grammar/patterns/sequenceLiteral.ts +24 -0
- package/src/grammar/patterns/spaces.ts +8 -6
- package/src/grammar/patterns/statement.ts +8 -20
- package/src/grammar/patterns.test.ts +38 -0
- package/src/grammar/patterns.ts +24 -0
- package/src/grammar/spec.md +4 -12
- package/src/index.ts +11 -5
- package/src/intellisense/AutoComplete.test.ts +41 -40
- package/src/intellisense/css/method.ts +2 -2
- package/src/intellisense/css/unit.ts +2 -2
- package/src/intellisense/css/value.ts +1 -1
- package/src/intellisense/javascript/Javascript.test.ts +31 -32
- package/src/intellisense/javascript/arrayLiteral.ts +7 -6
- package/src/intellisense/javascript/assignment.ts +6 -6
- package/src/intellisense/javascript/deleteStatement.ts +2 -2
- package/src/intellisense/javascript/escapedCharacter.ts +6 -6
- package/src/intellisense/javascript/exponent.ts +6 -6
- package/src/intellisense/javascript/expression.ts +18 -17
- package/src/intellisense/javascript/fraction.ts +3 -3
- package/src/intellisense/javascript/infixOperator.ts +10 -10
- package/src/intellisense/javascript/integer.ts +1 -1
- package/src/intellisense/javascript/invocation.ts +8 -7
- package/src/intellisense/javascript/literal.ts +3 -3
- package/src/intellisense/javascript/numberLiteral.ts +5 -4
- package/src/intellisense/javascript/objectAccess.ts +2 -3
- package/src/intellisense/javascript/objectLiteral.ts +8 -7
- package/src/intellisense/javascript/optionalSpaces.ts +2 -1
- package/src/intellisense/javascript/parameters.ts +5 -5
- package/src/intellisense/javascript/prefixOperator.ts +3 -4
- package/src/intellisense/javascript/propertyAccess.ts +9 -8
- package/src/intellisense/javascript/stringLiteral.ts +14 -15
- package/src/patterns/Cursor.ts +42 -4
- package/src/patterns/CursorHistory.ts +20 -4
- package/src/patterns/FiniteRepeat.test.ts +52 -51
- package/src/patterns/FiniteRepeat.ts +60 -38
- package/src/patterns/InfiniteRepeat.test.ts +36 -49
- package/src/patterns/InfiniteRepeat.ts +70 -37
- package/src/patterns/Literal.test.ts +16 -27
- package/src/patterns/Literal.ts +34 -27
- package/src/patterns/Not.test.ts +7 -7
- package/src/patterns/Not.ts +24 -6
- package/src/patterns/Optional.test.ts +164 -0
- package/src/patterns/Optional.ts +143 -0
- package/src/patterns/{Or.test.ts → Options.test.ts} +51 -49
- package/src/patterns/{Or.ts → Options.ts} +32 -23
- package/src/patterns/Pattern.ts +6 -5
- package/src/patterns/Reference.test.ts +21 -22
- package/src/patterns/Reference.ts +26 -15
- package/src/patterns/Regex.test.ts +15 -15
- package/src/patterns/Regex.ts +29 -19
- package/src/patterns/Repeat.test.ts +12 -22
- package/src/patterns/Repeat.ts +22 -21
- package/src/patterns/{And.test.ts → Sequence.test.ts} +78 -78
- package/src/patterns/{And.ts → Sequence.ts} +40 -29
- package/src/patterns/arePatternsEqual.ts +12 -0
- package/src/patterns/clonePatterns.ts +2 -2
- package/src/grammar/patterns/andLiteral.ts +0 -8
- package/src/grammar/patterns/orLiteral.ts +0 -8
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import { Cursor } from "./Cursor";
|
|
2
2
|
import { Node } from "../ast/Node";
|
|
3
3
|
import { Literal } from "./Literal";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { Options } from "./Options";
|
|
5
|
+
import { Sequence } from "./Sequence";
|
|
6
6
|
import { Pattern } from "./Pattern";
|
|
7
|
+
import { Optional } from "./Optional";
|
|
7
8
|
|
|
8
|
-
describe("
|
|
9
|
+
describe("Options", () => {
|
|
9
10
|
test("Empty Options", () => {
|
|
10
11
|
expect(() => {
|
|
11
|
-
new
|
|
12
|
+
new Options("bad", []);
|
|
12
13
|
}).toThrowError();
|
|
13
14
|
});
|
|
14
15
|
|
|
15
16
|
test("One Option Successful", () => {
|
|
16
|
-
const a = new
|
|
17
|
+
const a = new Options("a", [new Literal("a", "A")]);
|
|
17
18
|
const cursor = new Cursor("A");
|
|
18
19
|
const result = a.parse(cursor);
|
|
19
20
|
const expected = new Node("literal", "a", 0, 0, [], "A")
|
|
@@ -22,7 +23,7 @@ describe("Or", () => {
|
|
|
22
23
|
});
|
|
23
24
|
|
|
24
25
|
test("One Option Failed", () => {
|
|
25
|
-
const a = new
|
|
26
|
+
const a = new Options("a", [new Literal("a", "A")]);
|
|
26
27
|
const cursor = new Cursor("B");
|
|
27
28
|
const result = a.parse(cursor);
|
|
28
29
|
|
|
@@ -32,7 +33,7 @@ describe("Or", () => {
|
|
|
32
33
|
});
|
|
33
34
|
|
|
34
35
|
test("Two Option", () => {
|
|
35
|
-
const a = new
|
|
36
|
+
const a = new Options("a-b", [new Literal("a", "A"), new Literal("b", "B")]);
|
|
36
37
|
const cursor = new Cursor("AB");
|
|
37
38
|
let result = a.parse(cursor);
|
|
38
39
|
let expected = new Node("literal", "a", 0, 0, [], "A")
|
|
@@ -47,17 +48,8 @@ describe("Or", () => {
|
|
|
47
48
|
], "B");
|
|
48
49
|
});
|
|
49
50
|
|
|
50
|
-
test("Failed (Optional)", () => {
|
|
51
|
-
const a = new Or("a", [new Literal("a", "A")], true);
|
|
52
|
-
const cursor = new Cursor("B");
|
|
53
|
-
const result = a.parse(cursor);
|
|
54
|
-
|
|
55
|
-
expect(result).toBeNull();
|
|
56
|
-
expect(cursor.hasError).toBeFalsy();
|
|
57
|
-
});
|
|
58
|
-
|
|
59
51
|
test("Get Tokens", () => {
|
|
60
|
-
const aOrB = new
|
|
52
|
+
const aOrB = new Options("a-b", [new Literal("a", "A"), new Literal("b", "B")]);
|
|
61
53
|
const tokens = aOrB.getTokens();
|
|
62
54
|
const expected = ["A", "B"];
|
|
63
55
|
|
|
@@ -65,8 +57,8 @@ describe("Or", () => {
|
|
|
65
57
|
});
|
|
66
58
|
|
|
67
59
|
test("Get Tokens After", () => {
|
|
68
|
-
const a = new
|
|
69
|
-
const parent = new
|
|
60
|
+
const a = new Options("a", [new Literal("a", "A")]);
|
|
61
|
+
const parent = new Sequence("parent", [a, new Literal("b", "B")]);
|
|
70
62
|
const tokens = parent.children[0].getTokensAfter(parent.children[0].children[0]);
|
|
71
63
|
const expected = ["B"];
|
|
72
64
|
|
|
@@ -74,7 +66,7 @@ describe("Or", () => {
|
|
|
74
66
|
});
|
|
75
67
|
|
|
76
68
|
test("Get Tokens After Without A Parent", () => {
|
|
77
|
-
const a = new
|
|
69
|
+
const a = new Options("a", [new Literal("a", "A")]);
|
|
78
70
|
const tokens = a.getTokensAfter(a.children[0]);
|
|
79
71
|
const expected: string[] = [];
|
|
80
72
|
|
|
@@ -82,36 +74,35 @@ describe("Or", () => {
|
|
|
82
74
|
});
|
|
83
75
|
|
|
84
76
|
test("Properties", () => {
|
|
85
|
-
const a = new
|
|
77
|
+
const a = new Options("a", [new Literal("a", "A")]);
|
|
86
78
|
|
|
87
79
|
expect(a.type).toBe("or");
|
|
88
80
|
expect(a.name).toBe("a");
|
|
89
|
-
expect(a.isOptional).toBeFalsy();
|
|
90
81
|
expect(a.parent).toBeNull();
|
|
91
82
|
expect(a.children[0].name).toBe("a");
|
|
92
83
|
});
|
|
93
84
|
|
|
94
85
|
test("Exec", () => {
|
|
95
|
-
const a = new
|
|
86
|
+
const a = new Options("a", [new Literal("a", "A")]);
|
|
96
87
|
const { ast: result } = a.exec("B");
|
|
97
88
|
expect(result).toBeNull();
|
|
98
89
|
});
|
|
99
90
|
|
|
100
91
|
test("Test No Match", () => {
|
|
101
|
-
const a = new
|
|
92
|
+
const a = new Options("a", [new Literal("a", "A")]);
|
|
102
93
|
const result = a.test("B");
|
|
103
94
|
expect(result).toBeFalsy();
|
|
104
95
|
});
|
|
105
96
|
|
|
106
97
|
test("Test With Match", () => {
|
|
107
|
-
const a = new
|
|
98
|
+
const a = new Options("a", [new Literal("a", "A")]);
|
|
108
99
|
const result = a.test("A");
|
|
109
100
|
expect(result).toBeTruthy();
|
|
110
101
|
});
|
|
111
102
|
|
|
112
103
|
test("Get Next Tokens", () => {
|
|
113
|
-
const sequence = new
|
|
114
|
-
new
|
|
104
|
+
const sequence = new Sequence("sequence", [
|
|
105
|
+
new Options("a-or-b", [
|
|
115
106
|
new Literal("a", "A"),
|
|
116
107
|
new Literal("b", "B")
|
|
117
108
|
]),
|
|
@@ -126,7 +117,7 @@ describe("Or", () => {
|
|
|
126
117
|
});
|
|
127
118
|
|
|
128
119
|
test("Get Next Tokens With Null Parent", () => {
|
|
129
|
-
const or = new
|
|
120
|
+
const or = new Options("a-or-b", [
|
|
130
121
|
new Literal("a", "A"),
|
|
131
122
|
new Literal("b", "B")
|
|
132
123
|
])
|
|
@@ -137,8 +128,8 @@ describe("Or", () => {
|
|
|
137
128
|
|
|
138
129
|
|
|
139
130
|
test("Get Tokens After", () => {
|
|
140
|
-
const sequence = new
|
|
141
|
-
new
|
|
131
|
+
const sequence = new Sequence("sequence", [
|
|
132
|
+
new Options("a-or-b", [
|
|
142
133
|
new Literal("a", "A"),
|
|
143
134
|
new Literal("b", "B")
|
|
144
135
|
]),
|
|
@@ -154,7 +145,7 @@ describe("Or", () => {
|
|
|
154
145
|
});
|
|
155
146
|
|
|
156
147
|
test("Get Patterns", () => {
|
|
157
|
-
const aOrB = new
|
|
148
|
+
const aOrB = new Options("a-b", [new Literal("a", "A"), new Literal("b", "B")]);
|
|
158
149
|
const patterns = aOrB.getPatterns();
|
|
159
150
|
const expected = [
|
|
160
151
|
aOrB.find(p => p.name === "a"),
|
|
@@ -165,8 +156,8 @@ describe("Or", () => {
|
|
|
165
156
|
});
|
|
166
157
|
|
|
167
158
|
test("Get Patterns After", () => {
|
|
168
|
-
const sequence = new
|
|
169
|
-
new
|
|
159
|
+
const sequence = new Sequence("sequence", [
|
|
160
|
+
new Options("a-or-b", [
|
|
170
161
|
new Literal("a", "A"),
|
|
171
162
|
new Literal("b", "B")
|
|
172
163
|
]),
|
|
@@ -182,7 +173,7 @@ describe("Or", () => {
|
|
|
182
173
|
});
|
|
183
174
|
|
|
184
175
|
test("Get Patterns After With Null Parent", () => {
|
|
185
|
-
const or = new
|
|
176
|
+
const or = new Options("a-or-b", [
|
|
186
177
|
new Literal("a", "A"),
|
|
187
178
|
new Literal("b", "B")
|
|
188
179
|
])
|
|
@@ -193,8 +184,8 @@ describe("Or", () => {
|
|
|
193
184
|
});
|
|
194
185
|
|
|
195
186
|
test("Get Next Patterns", () => {
|
|
196
|
-
const sequence = new
|
|
197
|
-
new
|
|
187
|
+
const sequence = new Sequence("sequence", [
|
|
188
|
+
new Options("a-or-b", [
|
|
198
189
|
new Literal("a", "A"),
|
|
199
190
|
new Literal("b", "B")
|
|
200
191
|
]),
|
|
@@ -209,7 +200,7 @@ describe("Or", () => {
|
|
|
209
200
|
});
|
|
210
201
|
|
|
211
202
|
test("Get Next Patterns With Null Parent", () => {
|
|
212
|
-
const or = new
|
|
203
|
+
const or = new Options("a-or-b", [
|
|
213
204
|
new Literal("a", "A"),
|
|
214
205
|
new Literal("b", "B")
|
|
215
206
|
])
|
|
@@ -225,11 +216,11 @@ describe("Or", () => {
|
|
|
225
216
|
const smith = new Literal("smith", "Smith");
|
|
226
217
|
const space = new Literal("space", " ");
|
|
227
218
|
|
|
228
|
-
const firstName = new
|
|
229
|
-
const lastName = new
|
|
219
|
+
const firstName = new Options("first-name", [john, jane], true);
|
|
220
|
+
const lastName = new Options("last-name", [doe, smith], true);
|
|
230
221
|
const johnJohnson = new Literal("john-johnson", "John Johnson");
|
|
231
|
-
const fullName = new
|
|
232
|
-
const names = new
|
|
222
|
+
const fullName = new Sequence("full-name", [firstName, space, lastName]);
|
|
223
|
+
const names = new Options("names", [fullName, johnJohnson], true);
|
|
233
224
|
|
|
234
225
|
const result = names.exec("John Johnson");
|
|
235
226
|
expect(result.ast?.value).toBe("John Johnson");
|
|
@@ -242,11 +233,11 @@ describe("Or", () => {
|
|
|
242
233
|
const smith = new Literal("smith", "Smith");
|
|
243
234
|
const space = new Literal("space", " ");
|
|
244
235
|
|
|
245
|
-
const firstName = new
|
|
246
|
-
const lastName = new
|
|
236
|
+
const firstName = new Options("first-name", [john, jane], true);
|
|
237
|
+
const lastName = new Options("last-name", [doe, smith], true);
|
|
247
238
|
const johnJohnson = new Literal("john-johnson", "John Johnson");
|
|
248
|
-
const fullName = new
|
|
249
|
-
const names = new
|
|
239
|
+
const fullName = new Sequence("full-name", [firstName, space, lastName]);
|
|
240
|
+
const names = new Options("names", [johnJohnson, fullName], true);
|
|
250
241
|
|
|
251
242
|
const result = names.exec("John Johnson");
|
|
252
243
|
expect(result.ast?.value).toBe("John Johnson");
|
|
@@ -259,14 +250,25 @@ describe("Or", () => {
|
|
|
259
250
|
const smith = new Literal("smith", "Smith");
|
|
260
251
|
const space = new Literal("space", " ");
|
|
261
252
|
|
|
262
|
-
const firstName = new
|
|
263
|
-
const lastName = new
|
|
253
|
+
const firstName = new Options("first-name", [john, jane], true);
|
|
254
|
+
const lastName = new Options("last-name", [doe, smith], true);
|
|
264
255
|
const johnJohnson = new Literal("john-johnson", "John Johnson");
|
|
265
256
|
const johnStockton = new Literal("john-stockton", "John Stockton");
|
|
266
|
-
const fullName = new
|
|
267
|
-
const names = new
|
|
257
|
+
const fullName = new Sequence("full-name", [firstName, space, lastName]);
|
|
258
|
+
const names = new Options("names", [johnStockton, johnJohnson, fullName], true);
|
|
268
259
|
|
|
269
260
|
const result = names.exec("John Johnson");
|
|
270
261
|
expect(result.ast?.value).toBe("John Johnson");
|
|
271
262
|
});
|
|
263
|
+
|
|
264
|
+
// This doesn't make sense, but every pattern needs to handle a null result with no error.
|
|
265
|
+
test("Optional option", () => {
|
|
266
|
+
const john = new Optional("optional-john", new Literal("john", "John"));
|
|
267
|
+
const jane = new Literal("jane", "Jane");
|
|
268
|
+
|
|
269
|
+
const firstName = new Options("first-name", [john, jane], true);
|
|
270
|
+
|
|
271
|
+
const result = firstName.exec("Jane");
|
|
272
|
+
expect(result.ast?.value).toBe("Jane");
|
|
273
|
+
});
|
|
272
274
|
});
|
|
@@ -3,16 +3,23 @@ import { Cursor } from "./Cursor";
|
|
|
3
3
|
import { Pattern } from "./Pattern";
|
|
4
4
|
import { clonePatterns } from "./clonePatterns";
|
|
5
5
|
import { findPattern } from "./findPattern";
|
|
6
|
+
import { ParseResult } from "./ParseResult";
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
let idIndex = 0;
|
|
9
|
+
|
|
10
|
+
export class Options implements Pattern {
|
|
11
|
+
private _id: string;
|
|
8
12
|
private _type: string;
|
|
9
13
|
private _name: string;
|
|
10
14
|
private _parent: Pattern | null;
|
|
11
15
|
private _children: Pattern[];
|
|
12
|
-
private _isOptional: boolean;
|
|
13
16
|
private _isGreedy: boolean;
|
|
14
17
|
private _firstIndex: number;
|
|
15
18
|
|
|
19
|
+
get id(): string {
|
|
20
|
+
return this._id;
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
get type(): string {
|
|
17
24
|
return this._type;
|
|
18
25
|
}
|
|
@@ -33,23 +40,19 @@ export class Or implements Pattern {
|
|
|
33
40
|
return this._children;
|
|
34
41
|
}
|
|
35
42
|
|
|
36
|
-
|
|
37
|
-
return this._isOptional;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
constructor(name: string, options: Pattern[], isOptional = false, isGreedy = false) {
|
|
43
|
+
constructor(name: string, options: Pattern[], isGreedy = false) {
|
|
41
44
|
if (options.length === 0) {
|
|
42
45
|
throw new Error("Need at least one pattern with an 'or' pattern.");
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
const children = clonePatterns(options
|
|
48
|
+
const children = clonePatterns(options);
|
|
46
49
|
this._assignChildrenToParent(children);
|
|
47
50
|
|
|
51
|
+
this._id = `or-${idIndex++}`;
|
|
48
52
|
this._type = "or";
|
|
49
53
|
this._name = name;
|
|
50
54
|
this._parent = null;
|
|
51
55
|
this._children = children;
|
|
52
|
-
this._isOptional = isOptional;
|
|
53
56
|
this._firstIndex = 0;
|
|
54
57
|
this._isGreedy = isGreedy;
|
|
55
58
|
}
|
|
@@ -67,8 +70,10 @@ export class Or implements Pattern {
|
|
|
67
70
|
return ast?.value === text;
|
|
68
71
|
}
|
|
69
72
|
|
|
70
|
-
exec(text: string) {
|
|
73
|
+
exec(text: string, record = false): ParseResult {
|
|
71
74
|
const cursor = new Cursor(text);
|
|
75
|
+
record && cursor.startRecording();
|
|
76
|
+
|
|
72
77
|
const ast = this.parse(cursor);
|
|
73
78
|
|
|
74
79
|
return {
|
|
@@ -78,6 +83,7 @@ export class Or implements Pattern {
|
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
parse(cursor: Cursor): Node | null {
|
|
86
|
+
cursor.startParseWith(this);
|
|
81
87
|
this._firstIndex = cursor.index;
|
|
82
88
|
|
|
83
89
|
const node = this._tryToParse(cursor);
|
|
@@ -85,16 +91,13 @@ export class Or implements Pattern {
|
|
|
85
91
|
if (node != null) {
|
|
86
92
|
cursor.moveTo(node.lastIndex);
|
|
87
93
|
cursor.resolveError();
|
|
88
|
-
return node
|
|
89
|
-
}
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
return null;
|
|
95
|
+
cursor.endParse();
|
|
96
|
+
return node;
|
|
94
97
|
}
|
|
95
98
|
|
|
96
|
-
cursor.
|
|
97
|
-
cursor.
|
|
99
|
+
cursor.recordErrorAt(this._firstIndex, this._firstIndex, this);
|
|
100
|
+
cursor.endParse();
|
|
98
101
|
return null;
|
|
99
102
|
}
|
|
100
103
|
|
|
@@ -104,11 +107,12 @@ export class Or implements Pattern {
|
|
|
104
107
|
for (const pattern of this._children) {
|
|
105
108
|
cursor.moveTo(this._firstIndex);
|
|
106
109
|
const result = pattern.parse(cursor);
|
|
110
|
+
|
|
107
111
|
if (this._isGreedy) {
|
|
108
112
|
results.push(result);
|
|
109
113
|
}
|
|
110
114
|
|
|
111
|
-
if (
|
|
115
|
+
if (result != null && !this._isGreedy) {
|
|
112
116
|
return result;
|
|
113
117
|
}
|
|
114
118
|
|
|
@@ -141,7 +145,7 @@ export class Or implements Pattern {
|
|
|
141
145
|
|
|
142
146
|
getNextTokens(): string[] {
|
|
143
147
|
if (this._parent == null) {
|
|
144
|
-
return []
|
|
148
|
+
return [];
|
|
145
149
|
}
|
|
146
150
|
|
|
147
151
|
return this._parent.getTokensAfter(this);
|
|
@@ -162,7 +166,7 @@ export class Or implements Pattern {
|
|
|
162
166
|
return [];
|
|
163
167
|
}
|
|
164
168
|
|
|
165
|
-
return this._parent.getPatternsAfter(this)
|
|
169
|
+
return this._parent.getPatternsAfter(this);
|
|
166
170
|
}
|
|
167
171
|
|
|
168
172
|
getNextPatterns(): Pattern[] {
|
|
@@ -170,15 +174,20 @@ export class Or implements Pattern {
|
|
|
170
174
|
return [];
|
|
171
175
|
}
|
|
172
176
|
|
|
173
|
-
return this.parent.getPatternsAfter(this)
|
|
177
|
+
return this.parent.getPatternsAfter(this);
|
|
174
178
|
}
|
|
175
179
|
|
|
176
180
|
find(predicate: (p: Pattern) => boolean): Pattern | null {
|
|
177
181
|
return findPattern(this, predicate);
|
|
178
182
|
}
|
|
179
183
|
|
|
180
|
-
clone(name = this._name
|
|
181
|
-
const or = new
|
|
184
|
+
clone(name = this._name): Pattern {
|
|
185
|
+
const or = new Options(name, this._children, this._isGreedy);
|
|
186
|
+
or._id = this._id;
|
|
182
187
|
return or;
|
|
183
188
|
}
|
|
189
|
+
|
|
190
|
+
isEqual(pattern: Options): boolean {
|
|
191
|
+
return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
|
|
192
|
+
}
|
|
184
193
|
}
|
package/src/patterns/Pattern.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { Cursor } from "./Cursor";
|
|
2
2
|
import { Node } from "../ast/Node";
|
|
3
|
-
import { ParseResult } from "./ParseResult"
|
|
3
|
+
import { ParseResult } from "./ParseResult";
|
|
4
4
|
|
|
5
5
|
export interface Pattern {
|
|
6
|
+
id: string;
|
|
6
7
|
type: string;
|
|
7
8
|
name: string;
|
|
8
9
|
parent: Pattern | null;
|
|
9
10
|
children: Pattern[];
|
|
10
|
-
isOptional: boolean;
|
|
11
11
|
|
|
12
12
|
parse(cursor: Cursor): Node | null;
|
|
13
|
-
exec(text: string): ParseResult;
|
|
14
|
-
test(text: string): boolean;
|
|
15
|
-
clone(name?: string
|
|
13
|
+
exec(text: string, record?: boolean): ParseResult;
|
|
14
|
+
test(text: string, record?: boolean): boolean;
|
|
15
|
+
clone(name?: string): Pattern;
|
|
16
16
|
getTokens(): string[];
|
|
17
17
|
getTokensAfter(childReference: Pattern): string[];
|
|
18
18
|
getNextTokens(): string[];
|
|
@@ -20,4 +20,5 @@ export interface Pattern {
|
|
|
20
20
|
getPatternsAfter(childReference: Pattern): Pattern[];
|
|
21
21
|
getNextPatterns(): Pattern[];
|
|
22
22
|
find(predicate: (p: Pattern) => boolean): Pattern | null;
|
|
23
|
+
isEqual(pattern: Pattern): boolean;
|
|
23
24
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Node } from "../ast/Node";
|
|
2
|
-
import {
|
|
2
|
+
import { Sequence } from "./Sequence";
|
|
3
3
|
import { Cursor } from "./Cursor";
|
|
4
4
|
import { findPattern } from "./findPattern";
|
|
5
5
|
import { Literal } from "./Literal";
|
|
6
|
-
import {
|
|
6
|
+
import { Options } from "./Options";
|
|
7
7
|
import { Pattern } from "./Pattern";
|
|
8
8
|
import { Reference } from "./Reference";
|
|
9
9
|
import { Regex } from "./Regex";
|
|
@@ -20,8 +20,8 @@ function createValuePattern() {
|
|
|
20
20
|
|
|
21
21
|
const valueRef = new Reference("value");
|
|
22
22
|
const values = new Repeat("values", valueRef, { divider });
|
|
23
|
-
const array = new
|
|
24
|
-
const value = new
|
|
23
|
+
const array = new Sequence("array", [openBracket, values, closeBracket]);
|
|
24
|
+
const value = new Options("value", [number, array]);
|
|
25
25
|
|
|
26
26
|
return value;
|
|
27
27
|
}
|
|
@@ -32,7 +32,7 @@ describe("Reference", () => {
|
|
|
32
32
|
const cursor = new Cursor("[1, 2]");
|
|
33
33
|
const result = value.parse(cursor);
|
|
34
34
|
|
|
35
|
-
const expected = new Node("
|
|
35
|
+
const expected = new Node("sequence", "array", 0, 5, [
|
|
36
36
|
new Node("literal", "open-bracket", 0, 0, [], "["),
|
|
37
37
|
new Node("infinite-repeat", "values", 1, 4, [
|
|
38
38
|
new Node("regex", "number", 1, 1, [], "1"),
|
|
@@ -40,7 +40,7 @@ describe("Reference", () => {
|
|
|
40
40
|
new Node("regex", "number", 4, 4, [], "2")
|
|
41
41
|
]),
|
|
42
42
|
new Node("literal", "close-bracket", 5, 5, [], "]"),
|
|
43
|
-
])
|
|
43
|
+
]);
|
|
44
44
|
|
|
45
45
|
expect(result).toEqual(expected);
|
|
46
46
|
});
|
|
@@ -49,8 +49,8 @@ describe("Reference", () => {
|
|
|
49
49
|
const ref = new Reference("bad-reference");
|
|
50
50
|
|
|
51
51
|
expect(() => {
|
|
52
|
-
ref.parse(new Cursor("text"))
|
|
53
|
-
}).toThrowError()
|
|
52
|
+
ref.parse(new Cursor("text"));
|
|
53
|
+
}).toThrowError();
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
test("Get Tokens", () => {
|
|
@@ -76,7 +76,7 @@ describe("Reference", () => {
|
|
|
76
76
|
|
|
77
77
|
test("Get Tokens After With No Parent", () => {
|
|
78
78
|
const ref = new Reference("bad-reference");
|
|
79
|
-
const tokens = ref.getTokensAfter(new Literal("bogus", "bogus"))
|
|
79
|
+
const tokens = ref.getTokensAfter(new Literal("bogus", "bogus"));
|
|
80
80
|
|
|
81
81
|
expect(tokens).toEqual([]);
|
|
82
82
|
});
|
|
@@ -86,30 +86,29 @@ describe("Reference", () => {
|
|
|
86
86
|
|
|
87
87
|
expect(ref.type).toBe("reference");
|
|
88
88
|
expect(ref.name).toBe("ref");
|
|
89
|
-
expect(ref.
|
|
90
|
-
expect(ref.
|
|
91
|
-
expect(ref.children).toEqual([])
|
|
89
|
+
expect(ref.parent).toBe(null);
|
|
90
|
+
expect(ref.children).toEqual([]);
|
|
92
91
|
});
|
|
93
92
|
|
|
94
93
|
test("Exec", () => {
|
|
95
94
|
const value = createValuePattern();
|
|
96
|
-
const reference = findPattern(value, p => p.type === "reference") as Reference
|
|
95
|
+
const reference = findPattern(value, p => p.type === "reference") as Reference;
|
|
97
96
|
const { ast: result } = reference.exec("B");
|
|
98
|
-
expect(result).toBeNull()
|
|
97
|
+
expect(result).toBeNull();
|
|
99
98
|
});
|
|
100
99
|
|
|
101
100
|
test("Test With Match", () => {
|
|
102
101
|
const value = createValuePattern();
|
|
103
|
-
const reference = findPattern(value, p => p.type === "reference") as Reference
|
|
102
|
+
const reference = findPattern(value, p => p.type === "reference") as Reference;
|
|
104
103
|
const result = reference.test("[1]");
|
|
105
|
-
expect(result).toBeTruthy()
|
|
104
|
+
expect(result).toBeTruthy();
|
|
106
105
|
});
|
|
107
106
|
|
|
108
107
|
test("Test No Match", () => {
|
|
109
108
|
const value = createValuePattern();
|
|
110
|
-
const reference = findPattern(value, p => p.type === "reference") as Reference
|
|
109
|
+
const reference = findPattern(value, p => p.type === "reference") as Reference;
|
|
111
110
|
const result = reference.test("B");
|
|
112
|
-
expect(result).toBeFalsy()
|
|
111
|
+
expect(result).toBeFalsy();
|
|
113
112
|
});
|
|
114
113
|
|
|
115
114
|
test("Find Pattern", () => {
|
|
@@ -134,7 +133,7 @@ describe("Reference", () => {
|
|
|
134
133
|
const reference = new Reference("ref-name");
|
|
135
134
|
const tokens = reference.getNextTokens();
|
|
136
135
|
|
|
137
|
-
expect(tokens).toEqual([])
|
|
136
|
+
expect(tokens).toEqual([]);
|
|
138
137
|
});
|
|
139
138
|
|
|
140
139
|
test("Get Tokens After", () => {
|
|
@@ -149,7 +148,7 @@ describe("Reference", () => {
|
|
|
149
148
|
const reference = new Reference("ref-name");
|
|
150
149
|
const tokens = reference.getTokensAfter(new Literal("bogus", "Bogus"));
|
|
151
150
|
|
|
152
|
-
expect(tokens).toEqual([])
|
|
151
|
+
expect(tokens).toEqual([]);
|
|
153
152
|
});
|
|
154
153
|
|
|
155
154
|
test("Get Patterns", () => {
|
|
@@ -178,7 +177,7 @@ describe("Reference", () => {
|
|
|
178
177
|
const reference = new Reference("ref-name");
|
|
179
178
|
const patterns = reference.getPatternsAfter(new Literal("bogus", "Bogus"));
|
|
180
179
|
|
|
181
|
-
expect(patterns).toEqual([])
|
|
180
|
+
expect(patterns).toEqual([]);
|
|
182
181
|
});
|
|
183
182
|
|
|
184
183
|
test("Get Next Patterns", () => {
|
|
@@ -197,7 +196,7 @@ describe("Reference", () => {
|
|
|
197
196
|
const reference = new Reference("ref-name");
|
|
198
197
|
const patterns = reference.getNextPatterns();
|
|
199
198
|
|
|
200
|
-
expect(patterns).toEqual([])
|
|
199
|
+
expect(patterns).toEqual([]);
|
|
201
200
|
});
|
|
202
201
|
|
|
203
202
|
});
|
|
@@ -2,15 +2,22 @@ import { Node } from "../ast/Node";
|
|
|
2
2
|
import { Cursor } from "./Cursor";
|
|
3
3
|
import { Pattern } from "./Pattern";
|
|
4
4
|
import { findPattern } from "./findPattern";
|
|
5
|
+
import { ParseResult } from "./ParseResult";
|
|
6
|
+
|
|
7
|
+
let idIndex = 0;
|
|
5
8
|
|
|
6
9
|
export class Reference implements Pattern {
|
|
10
|
+
private _id: string;
|
|
7
11
|
private _type: string;
|
|
8
12
|
private _name: string;
|
|
9
13
|
private _parent: Pattern | null;
|
|
10
|
-
private _isOptional: boolean;
|
|
11
14
|
private _pattern: Pattern | null;
|
|
12
15
|
private _children: Pattern[];
|
|
13
16
|
|
|
17
|
+
get id(): string {
|
|
18
|
+
return this._id;
|
|
19
|
+
}
|
|
20
|
+
|
|
14
21
|
get type(): string {
|
|
15
22
|
return this._type;
|
|
16
23
|
}
|
|
@@ -28,18 +35,14 @@ export class Reference implements Pattern {
|
|
|
28
35
|
}
|
|
29
36
|
|
|
30
37
|
get children(): Pattern[] {
|
|
31
|
-
return this._children
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
get isOptional(): boolean {
|
|
35
|
-
return this._isOptional;
|
|
38
|
+
return this._children;
|
|
36
39
|
}
|
|
37
40
|
|
|
38
|
-
constructor(name: string
|
|
41
|
+
constructor(name: string) {
|
|
42
|
+
this._id = `reference-${idIndex++}`;
|
|
39
43
|
this._type = "reference";
|
|
40
44
|
this._name = name;
|
|
41
45
|
this._parent = null;
|
|
42
|
-
this._isOptional = isOptional;
|
|
43
46
|
this._pattern = null;
|
|
44
47
|
this._children = [];
|
|
45
48
|
}
|
|
@@ -51,8 +54,10 @@ export class Reference implements Pattern {
|
|
|
51
54
|
return ast?.value === text;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
exec(text: string) {
|
|
57
|
+
exec(text: string, record = false): ParseResult {
|
|
55
58
|
const cursor = new Cursor(text);
|
|
59
|
+
record && cursor.startRecording();
|
|
60
|
+
|
|
56
61
|
const ast = this.parse(cursor);
|
|
57
62
|
|
|
58
63
|
return {
|
|
@@ -73,7 +78,7 @@ export class Reference implements Pattern {
|
|
|
73
78
|
throw new Error(`Couldn't find '${this._name}' pattern within tree.`);
|
|
74
79
|
}
|
|
75
80
|
|
|
76
|
-
const clonedPattern = pattern.clone(
|
|
81
|
+
const clonedPattern = pattern.clone();
|
|
77
82
|
clonedPattern.parent = this;
|
|
78
83
|
|
|
79
84
|
this._pattern = clonedPattern;
|
|
@@ -100,7 +105,7 @@ export class Reference implements Pattern {
|
|
|
100
105
|
if (parent == null) {
|
|
101
106
|
break;
|
|
102
107
|
} else {
|
|
103
|
-
node = parent
|
|
108
|
+
node = parent;
|
|
104
109
|
}
|
|
105
110
|
}
|
|
106
111
|
|
|
@@ -121,7 +126,7 @@ export class Reference implements Pattern {
|
|
|
121
126
|
|
|
122
127
|
getNextTokens(): string[] {
|
|
123
128
|
if (this.parent == null) {
|
|
124
|
-
return []
|
|
129
|
+
return [];
|
|
125
130
|
}
|
|
126
131
|
|
|
127
132
|
return this.parent.getTokensAfter(this);
|
|
@@ -144,14 +149,20 @@ export class Reference implements Pattern {
|
|
|
144
149
|
return [];
|
|
145
150
|
}
|
|
146
151
|
|
|
147
|
-
return this.parent.getPatternsAfter(this)
|
|
152
|
+
return this.parent.getPatternsAfter(this);
|
|
148
153
|
}
|
|
149
154
|
|
|
150
155
|
find(_predicate: (p: Pattern) => boolean): Pattern | null {
|
|
151
156
|
return null;
|
|
152
157
|
}
|
|
153
158
|
|
|
154
|
-
clone(name = this._name
|
|
155
|
-
|
|
159
|
+
clone(name = this._name): Pattern {
|
|
160
|
+
const clone = new Reference(name);
|
|
161
|
+
clone._id = this._id;
|
|
162
|
+
return clone;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
isEqual(pattern: Reference): boolean {
|
|
166
|
+
return pattern.type === this.type && pattern.name === this.name;
|
|
156
167
|
}
|
|
157
168
|
}
|