clarity-pattern-parser 5.0.0 → 6.0.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/README.md +328 -38
- package/TODO.md +63 -7
- package/dist/ast/Node.d.ts +8 -2
- package/dist/index.browser.js +520 -205
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/dist/index.esm.js +519 -206
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +520 -205
- package/dist/index.js.map +1 -1
- package/dist/intellisense/AutoComplete.d.ts +34 -0
- package/dist/intellisense/Suggestion.d.ts +10 -0
- package/dist/intellisense/SuggestionOption.d.ts +4 -0
- package/dist/patterns/And.d.ts +8 -7
- package/dist/patterns/Cursor.d.ts +6 -4
- package/dist/patterns/CursorHistory.d.ts +2 -2
- package/dist/patterns/Literal.d.ts +8 -8
- package/dist/patterns/Not.d.ts +9 -5
- package/dist/patterns/Or.d.ts +8 -5
- package/dist/patterns/Pattern.d.ts +8 -4
- package/dist/patterns/Reference.d.ts +11 -7
- package/dist/patterns/Regex.d.ts +8 -8
- package/dist/patterns/Repeat.d.ts +8 -7
- package/package.json +1 -1
- package/src/ast/Node.test.ts +116 -0
- package/src/ast/Node.ts +71 -5
- package/src/index.ts +14 -3
- package/src/intellisense/AutoComplete.test.ts +168 -23
- package/src/intellisense/AutoComplete.ts +102 -21
- package/src/intellisense/Suggestion.ts +3 -4
- package/src/intellisense/javascript/Javascript.test.ts +86 -62
- package/src/intellisense/javascript/{expressionStatement.ts → assignment.ts} +7 -8
- package/src/intellisense/javascript/escapedCharacter.ts +0 -1
- package/src/intellisense/javascript/exponent.ts +0 -2
- package/src/intellisense/javascript/expression.ts +44 -26
- package/src/intellisense/javascript/fraction.ts +0 -2
- package/src/intellisense/javascript/infixOperator.ts +6 -2
- package/src/intellisense/javascript/keywords.ts +3 -0
- package/src/intellisense/javascript/objectAccess.ts +9 -0
- package/src/intellisense/javascript/objectLiteral.ts +3 -3
- package/src/intellisense/javascript/propertyAccess.ts +8 -3
- package/src/intellisense/javascript/stringLiteral.ts +16 -8
- package/src/patterns/And.test.ts +74 -50
- package/src/patterns/And.ts +72 -36
- package/src/patterns/Cursor.ts +17 -14
- package/src/patterns/CursorHistory.ts +8 -8
- package/src/patterns/Literal.test.ts +79 -38
- package/src/patterns/Literal.ts +34 -41
- package/src/patterns/Not.test.ts +99 -8
- package/src/patterns/Not.ts +58 -14
- package/src/patterns/Or.test.ts +128 -13
- package/src/patterns/Or.ts +46 -13
- package/src/patterns/Pattern.ts +8 -4
- package/src/patterns/Reference.test.ts +127 -28
- package/src/patterns/Reference.ts +62 -32
- package/src/patterns/Regex.test.ts +76 -35
- package/src/patterns/Regex.ts +35 -43
- package/src/patterns/Repeat.test.ts +72 -41
- package/src/patterns/Repeat.ts +55 -38
- package/src/patterns/getNextPattern.test.ts +0 -39
- package/src/patterns/getNextPattern.ts +0 -18
|
@@ -10,8 +10,10 @@ const greaterOrEqual = new Literal("greater-or-equal", ">=");
|
|
|
10
10
|
const lessOrEqual = new Literal("less-or-equal", "<=");
|
|
11
11
|
const greater = new Literal("greater", ">");
|
|
12
12
|
const less = new Literal("less", "<");
|
|
13
|
-
const equal = new Literal("equal", "
|
|
14
|
-
const notEqual = new Literal("not-equal", "
|
|
13
|
+
const equal = new Literal("equal", "==");
|
|
14
|
+
const notEqual = new Literal("not-equal", "!=");
|
|
15
|
+
const strictEqual = new Literal("strict-equal", "===");
|
|
16
|
+
const strictNotEqual = new Literal("strict-not-equal", "!==");
|
|
15
17
|
const logicalOr = new Literal("logical-or", "||");
|
|
16
18
|
const logicalAnd = new Literal("logical-and", "&&");
|
|
17
19
|
|
|
@@ -25,6 +27,8 @@ const infixOperator = new Or("infix-operator", [
|
|
|
25
27
|
lessOrEqual,
|
|
26
28
|
greater,
|
|
27
29
|
less,
|
|
30
|
+
strictEqual,
|
|
31
|
+
strictNotEqual,
|
|
28
32
|
equal,
|
|
29
33
|
notEqual,
|
|
30
34
|
logicalOr,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { And } from "../../patterns/And";
|
|
2
|
+
import { Reference } from "../../patterns/Reference";
|
|
3
|
+
import { name } from "./name";
|
|
4
|
+
import { propertyAccess } from "./propertyAccess";
|
|
5
|
+
|
|
6
|
+
export const objectAccess = new And("object-access", [
|
|
7
|
+
name.clone("variable-name"),
|
|
8
|
+
propertyAccess,
|
|
9
|
+
]);
|
|
@@ -8,7 +8,7 @@ import { name } from "./name";
|
|
|
8
8
|
import { optionalSpaces } from "./optionalSpaces";
|
|
9
9
|
import { stringLiteral } from "./stringLiteral";
|
|
10
10
|
|
|
11
|
-
const propertyName = new Or("property-name", [stringLiteral, name]);
|
|
11
|
+
const propertyName = new Or("property-name", [stringLiteral.clone("object-property"), name.clone("object-property")]);
|
|
12
12
|
const property = new And("property", [
|
|
13
13
|
propertyName,
|
|
14
14
|
optionalSpaces,
|
|
@@ -17,12 +17,12 @@ const property = new And("property", [
|
|
|
17
17
|
new Reference("expression"),
|
|
18
18
|
]);
|
|
19
19
|
const divider = new Regex("property-divider", "\\s*,\\s*");
|
|
20
|
-
const
|
|
20
|
+
const optionalProperties = new Repeat("properties", property, divider, true);
|
|
21
21
|
|
|
22
22
|
const objectLiteral = new And("object-literal", [
|
|
23
23
|
new Literal("open-curly-bracket", "{"),
|
|
24
24
|
optionalSpaces,
|
|
25
|
-
|
|
25
|
+
optionalProperties,
|
|
26
26
|
optionalSpaces,
|
|
27
27
|
new Literal("close-curly-bracket", "}"),
|
|
28
28
|
]);
|
|
@@ -6,7 +6,7 @@ import { name } from "./name";
|
|
|
6
6
|
|
|
7
7
|
const dotPropertyAccess = new And("dot-property-access", [
|
|
8
8
|
new Literal("period", "."),
|
|
9
|
-
name
|
|
9
|
+
name.clone("property-name")
|
|
10
10
|
]);
|
|
11
11
|
|
|
12
12
|
const bracketPropertyAccess = new And("bracket-property-access", [
|
|
@@ -15,9 +15,14 @@ const bracketPropertyAccess = new And("bracket-property-access", [
|
|
|
15
15
|
new Literal("close-square-bracket", "]"),
|
|
16
16
|
]);
|
|
17
17
|
|
|
18
|
-
const
|
|
18
|
+
const propertyAccessTypes = new Or("property-access-types", [
|
|
19
19
|
dotPropertyAccess,
|
|
20
|
-
bracketPropertyAccess
|
|
20
|
+
bracketPropertyAccess
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
const propertyAccess = new And("property-access", [
|
|
24
|
+
propertyAccessTypes,
|
|
25
|
+
new Reference("property-access", true)
|
|
21
26
|
]);
|
|
22
27
|
|
|
23
28
|
export { propertyAccess }
|
|
@@ -7,19 +7,27 @@ import { escapedCharacter } from "./escapedCharacter";
|
|
|
7
7
|
|
|
8
8
|
const doubleQuoteStringLiteral = new And("double-string-literal", [
|
|
9
9
|
new Literal("double-quote", "\""),
|
|
10
|
-
new Repeat("characters",
|
|
11
|
-
new
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
new Repeat("characters",
|
|
11
|
+
new Or("characters", [
|
|
12
|
+
new Regex("normal-characters", "[^\\\"]+"),
|
|
13
|
+
escapedCharacter
|
|
14
|
+
]),
|
|
15
|
+
undefined,
|
|
16
|
+
true
|
|
17
|
+
),
|
|
14
18
|
new Literal("double-quote", "\""),
|
|
15
19
|
]);
|
|
16
20
|
|
|
17
21
|
const singleQuoteStringLiteral = new And("single-string-literal", [
|
|
18
22
|
new Literal("single-quote", "'"),
|
|
19
|
-
new Repeat("characters",
|
|
20
|
-
new
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
new Repeat("characters",
|
|
24
|
+
new Or("characters", [
|
|
25
|
+
new Regex("normal-characters", "[^\\']+"),
|
|
26
|
+
escapedCharacter
|
|
27
|
+
]),
|
|
28
|
+
undefined,
|
|
29
|
+
true
|
|
30
|
+
),
|
|
23
31
|
new Literal("single-quote", "'"),
|
|
24
32
|
]);
|
|
25
33
|
|
package/src/patterns/And.test.ts
CHANGED
|
@@ -77,7 +77,7 @@ describe("And", () => {
|
|
|
77
77
|
const sequence = new And("sequence", [
|
|
78
78
|
new Literal("a", "A"),
|
|
79
79
|
new Literal("b", "B", true)
|
|
80
|
-
]
|
|
80
|
+
]);
|
|
81
81
|
const cursor = new Cursor("AD");
|
|
82
82
|
const result = sequence.parse(cursor);
|
|
83
83
|
const expected = new Node("and", "sequence", 0, 0, [
|
|
@@ -93,7 +93,7 @@ describe("And", () => {
|
|
|
93
93
|
const sequence = new And("sequence", [
|
|
94
94
|
new Literal("a", "A"),
|
|
95
95
|
new Literal("b", "B", true)
|
|
96
|
-
]
|
|
96
|
+
]);
|
|
97
97
|
const cursor = new Cursor("A");
|
|
98
98
|
const result = sequence.parse(cursor);
|
|
99
99
|
const expected = new Node("and", "sequence", 0, 0, [
|
|
@@ -105,7 +105,7 @@ describe("And", () => {
|
|
|
105
105
|
expect(cursor.index).toBe(0);
|
|
106
106
|
});
|
|
107
107
|
|
|
108
|
-
test("Incomplete Parse", () => {
|
|
108
|
+
test("Incomplete Parse (Optional)", () => {
|
|
109
109
|
const sequence = new And("sequence", [
|
|
110
110
|
new Literal("a", "A"),
|
|
111
111
|
new Literal("b", "B")
|
|
@@ -175,6 +175,32 @@ describe("And", () => {
|
|
|
175
175
|
expect(sequence.children[0].name).toBe("a");
|
|
176
176
|
});
|
|
177
177
|
|
|
178
|
+
test("Exec", () => {
|
|
179
|
+
const sequence = new And("sequence", [new Literal("a", "A")]);
|
|
180
|
+
|
|
181
|
+
const { ast: result, cursor } = sequence.exec("A");
|
|
182
|
+
const expected = new Node("and", "sequence", 0, 0, [
|
|
183
|
+
new Node("literal", "a", 0, 0, undefined, "A")
|
|
184
|
+
]);
|
|
185
|
+
|
|
186
|
+
expect(result).toEqual(expected)
|
|
187
|
+
expect(cursor).not.toBeNull();
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
test("Test With Match", () => {
|
|
191
|
+
const sequence = new And("sequence", [new Literal("a", "A")]);
|
|
192
|
+
const hasMatch = sequence.test("A");
|
|
193
|
+
|
|
194
|
+
expect(hasMatch).toBeTruthy();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test("Test With No Match", () => {
|
|
198
|
+
const sequence = new And("sequence", [new Literal("a", "A")]);
|
|
199
|
+
const hasMatch = sequence.test("B");
|
|
200
|
+
|
|
201
|
+
expect(hasMatch).toBeFalsy();
|
|
202
|
+
});
|
|
203
|
+
|
|
178
204
|
test("Set Parent", () => {
|
|
179
205
|
const a = new Literal("a", "A", true)
|
|
180
206
|
const sequence = new And("sequence", [
|
|
@@ -186,33 +212,6 @@ describe("And", () => {
|
|
|
186
212
|
expect(parent.children[0].type).toBe("and");
|
|
187
213
|
});
|
|
188
214
|
|
|
189
|
-
test("Reduce Ast", () => {
|
|
190
|
-
const sequence = new And("sequence", [
|
|
191
|
-
new Literal("a", "A"),
|
|
192
|
-
], true);
|
|
193
|
-
sequence.enableAstReduction();
|
|
194
|
-
|
|
195
|
-
const cursor = new Cursor("A");
|
|
196
|
-
let result = sequence.parse(cursor);
|
|
197
|
-
let expected = new Node("and", "sequence", 0, 0, [], "A");
|
|
198
|
-
|
|
199
|
-
expect(result).toEqual(expected);
|
|
200
|
-
expect(cursor.error).toBe(null)
|
|
201
|
-
expect(cursor.index).toBe(0);
|
|
202
|
-
|
|
203
|
-
sequence.disableAstReduction()
|
|
204
|
-
|
|
205
|
-
cursor.moveTo(0)
|
|
206
|
-
result = sequence.parse(cursor);
|
|
207
|
-
expected = new Node("and", "sequence", 0, 0, [
|
|
208
|
-
new Node("literal", "a", 0, 0, [], "A"),
|
|
209
|
-
]);
|
|
210
|
-
|
|
211
|
-
expect(result).toEqual(expected);
|
|
212
|
-
expect(cursor.error).toBe(null)
|
|
213
|
-
expect(cursor.index).toBe(0);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
215
|
test("Get Tokens", () => {
|
|
217
216
|
const sequence = new And("sequence", [
|
|
218
217
|
new Literal("a", "A", true),
|
|
@@ -224,76 +223,101 @@ describe("And", () => {
|
|
|
224
223
|
expect(tokens).toEqual(expected);
|
|
225
224
|
});
|
|
226
225
|
|
|
227
|
-
test("Get
|
|
226
|
+
test("Get Tokens After", () => {
|
|
228
227
|
const sequence = new And("sequence", [
|
|
229
228
|
new Literal("a", "A"),
|
|
230
229
|
new Literal("b", "B", true),
|
|
231
230
|
new Literal("c", "C"),
|
|
232
231
|
], true);
|
|
233
232
|
|
|
234
|
-
const tokens = sequence.
|
|
233
|
+
const tokens = sequence.getTokensAfter(sequence.children[0])
|
|
235
234
|
const expected = ["B", "C"];
|
|
236
235
|
|
|
237
236
|
expect(tokens).toEqual(expected);
|
|
238
237
|
});
|
|
239
238
|
|
|
240
|
-
test("Get
|
|
239
|
+
test("Get Tokens After With Invalid Pattern", () => {
|
|
241
240
|
const sequence = new And("sequence", [
|
|
242
241
|
new Literal("a", "A"),
|
|
243
242
|
new Literal("b", "B", true),
|
|
244
243
|
new Literal("c", "C"),
|
|
245
244
|
], true);
|
|
246
245
|
|
|
247
|
-
const tokens = sequence.
|
|
246
|
+
const tokens = sequence.getTokensAfter(new Literal("not-child", "not-child"))
|
|
248
247
|
|
|
249
248
|
expect(tokens).toEqual([]);
|
|
250
249
|
});
|
|
251
250
|
|
|
252
|
-
test("Get
|
|
251
|
+
test("Get Tokens After With Last Child", () => {
|
|
253
252
|
const sequence = new And("sequence", [
|
|
254
253
|
new Literal("a", "A"),
|
|
255
254
|
], true);
|
|
256
255
|
const parent = new And("parent", [sequence, new Literal("b", "B")]);
|
|
257
256
|
|
|
258
257
|
|
|
259
|
-
const tokens = parent.children[0].
|
|
258
|
+
const tokens = parent.children[0].getTokensAfter(parent.children[0].children[0])
|
|
260
259
|
|
|
261
260
|
expect(tokens).toEqual(["B"]);
|
|
262
261
|
});
|
|
263
262
|
|
|
264
|
-
test("Get
|
|
263
|
+
test("Get Tokens After With Last Optional Child", () => {
|
|
265
264
|
const sequence = new And("sequence", [
|
|
266
265
|
new Literal("a", "A"),
|
|
267
266
|
new Literal("b", "B", true),
|
|
268
267
|
], true);
|
|
269
268
|
const parent = new And("parent", [sequence, new Literal("c", "C")]);
|
|
270
269
|
|
|
271
|
-
|
|
272
|
-
const tokens = parent.children[0].getNextTokens(parent.children[0].children[0])
|
|
270
|
+
const tokens = parent.children[0].getTokensAfter(parent.children[0].children[0])
|
|
273
271
|
|
|
274
272
|
expect(tokens).toEqual(["B", "C"]);
|
|
275
273
|
});
|
|
276
274
|
|
|
277
|
-
test("
|
|
275
|
+
test("Get Next Tokens", () => {
|
|
278
276
|
const sequence = new And("sequence", [new Literal("a", "A")]);
|
|
279
|
-
sequence
|
|
277
|
+
const parent = new And("parent", [sequence, new Literal("b", "B")]);
|
|
280
278
|
|
|
281
|
-
const
|
|
282
|
-
const
|
|
279
|
+
const sequenceClone = parent.findPattern(p => p.name === "sequence");
|
|
280
|
+
const tokens = sequenceClone?.getNextTokens() || [];
|
|
283
281
|
|
|
284
|
-
expect(
|
|
282
|
+
expect(tokens[0]).toBe("B");
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
test("Get Next Tokens With Null Parent", () => {
|
|
286
|
+
const sequence = new And("sequence", [new Literal("a", "A")]);
|
|
287
|
+
const tokens = sequence.getNextTokens();
|
|
288
|
+
|
|
289
|
+
expect(tokens.length).toBe(0);
|
|
285
290
|
});
|
|
286
291
|
|
|
287
|
-
test("Get
|
|
292
|
+
test("Get Patterns", () => {
|
|
288
293
|
const sequence = new And("sequence", [
|
|
289
|
-
new Literal("a", "A"),
|
|
290
|
-
new Literal("b", "B"
|
|
294
|
+
new Literal("a", "A", true),
|
|
295
|
+
new Literal("b", "B"),
|
|
291
296
|
], true);
|
|
292
|
-
const
|
|
297
|
+
const tokens = sequence.getPatterns();
|
|
298
|
+
const a = sequence.findPattern(p=>p.name === "a");
|
|
299
|
+
const b = sequence.findPattern(p=>p.name === "b");
|
|
300
|
+
const expected = [a, b]
|
|
293
301
|
|
|
302
|
+
expect(tokens).toEqual(expected);
|
|
303
|
+
});
|
|
294
304
|
|
|
295
|
-
|
|
305
|
+
test("Get Next Patterns", () => {
|
|
306
|
+
const sequence = new And("sequence", [new Literal("a", "A")]);
|
|
307
|
+
const parent = new And("parent", [sequence, new Literal("b", "B")]);
|
|
308
|
+
|
|
309
|
+
const sequenceClone = parent.findPattern(p => p.name === "sequence");
|
|
310
|
+
const nextPatterns = sequenceClone?.getNextPatterns() || [];
|
|
311
|
+
const b = parent.findPattern(p => p.name === "b")
|
|
296
312
|
|
|
297
|
-
expect(
|
|
313
|
+
expect(nextPatterns[0]).toBe(b);
|
|
298
314
|
});
|
|
315
|
+
|
|
316
|
+
test("Get Next Patterns With Null Parent", () => {
|
|
317
|
+
const sequence = new And("sequence", [new Literal("a", "A")]);
|
|
318
|
+
const nextPatterns = sequence.getNextPatterns()
|
|
319
|
+
|
|
320
|
+
expect(nextPatterns.length).toBe(0);
|
|
321
|
+
});
|
|
322
|
+
|
|
299
323
|
});
|
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,45 @@ 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
|
+
getPatterns(): Pattern[] {
|
|
238
|
+
const patterns: Pattern[] = [];
|
|
239
|
+
|
|
240
|
+
for (const pattern of this._children) {
|
|
241
|
+
patterns.push(...pattern.getPatterns());
|
|
242
|
+
|
|
243
|
+
if (!pattern.isOptional) {
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
return patterns;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
getPatternsAfter(childReference: Pattern): Pattern[] {
|
|
221
252
|
let nextSibling: Pattern | null = null;
|
|
222
253
|
let nextSiblingIndex = -1;
|
|
223
254
|
let index = -1;
|
|
224
|
-
const
|
|
255
|
+
const patterns: Pattern[] = [];
|
|
225
256
|
|
|
226
257
|
for (let i = 0; i < this._children.length; i++) {
|
|
227
|
-
if (this._children[i] ===
|
|
258
|
+
if (this._children[i] === childReference) {
|
|
228
259
|
if (i + 1 < this._children.length) {
|
|
229
260
|
nextSibling = this._children[i + 1];
|
|
230
261
|
}
|
|
@@ -234,48 +265,53 @@ export class And implements Pattern {
|
|
|
234
265
|
}
|
|
235
266
|
}
|
|
236
267
|
|
|
268
|
+
// The child reference isn't one of the child patterns.
|
|
237
269
|
if (index === -1) {
|
|
238
270
|
return [];
|
|
239
271
|
}
|
|
240
272
|
|
|
273
|
+
// The reference pattern is the last child. So ask the parent for the next pattern.
|
|
241
274
|
if (nextSiblingIndex === this._children.length && this._parent !== null) {
|
|
242
|
-
return this._parent.
|
|
275
|
+
return this._parent.getPatternsAfter(this);
|
|
243
276
|
}
|
|
244
277
|
|
|
278
|
+
// Next pattern isn't optional so send it back as the next patterns.
|
|
245
279
|
if (nextSibling !== null && !nextSibling.isOptional) {
|
|
246
|
-
return nextSibling
|
|
280
|
+
return [nextSibling];
|
|
247
281
|
}
|
|
248
282
|
|
|
283
|
+
// Send back as many optional patterns as possible.
|
|
249
284
|
if (nextSibling !== null && nextSibling.isOptional) {
|
|
250
285
|
for (let i = nextSiblingIndex; i < this._children.length; i++) {
|
|
251
286
|
const child = this._children[i];
|
|
252
|
-
|
|
287
|
+
patterns.push(child);
|
|
253
288
|
|
|
254
289
|
if (!child.isOptional) {
|
|
255
290
|
break;
|
|
256
291
|
}
|
|
257
292
|
|
|
258
293
|
if (i === this._children.length - 1 && this._parent !== null) {
|
|
259
|
-
|
|
294
|
+
patterns.push(...this._parent.getPatternsAfter(this));
|
|
260
295
|
}
|
|
261
296
|
}
|
|
262
297
|
}
|
|
263
298
|
|
|
264
|
-
return
|
|
299
|
+
return patterns;
|
|
265
300
|
}
|
|
266
301
|
|
|
267
|
-
|
|
268
|
-
|
|
302
|
+
getNextPatterns(): Pattern[] {
|
|
303
|
+
if (this.parent == null) {
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return this.parent.getPatternsAfter(this)
|
|
269
308
|
}
|
|
270
309
|
|
|
271
|
-
findPattern(
|
|
272
|
-
return findPattern(this,
|
|
310
|
+
findPattern(predicate: (p: Pattern) => boolean): Pattern | null {
|
|
311
|
+
return findPattern(this, predicate);
|
|
273
312
|
}
|
|
274
313
|
|
|
275
314
|
clone(name = this._name, isOptional = this._isOptional): Pattern {
|
|
276
|
-
|
|
277
|
-
and._shouldReduceAst = this._shouldReduceAst;
|
|
278
|
-
|
|
279
|
-
return and
|
|
315
|
+
return new And(name, this._children, isOptional)
|
|
280
316
|
}
|
|
281
317
|
}
|
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);
|