clarity-pattern-parser 10.0.2 → 10.0.4
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/ast/Node.d.ts +1 -0
- package/dist/index.browser.js +44 -26
- package/dist/index.browser.js.map +1 -1
- package/dist/index.esm.js +44 -26
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +44 -26
- package/dist/index.js.map +1 -1
- package/dist/patterns/Cursor.d.ts +5 -0
- package/dist/patterns/Not.d.ts +0 -1
- package/dist/patterns/Repeat.d.ts +2 -2
- package/package.json +1 -1
- package/src/ast/Node.ts +4 -0
- package/src/grammar/Grammar.test.ts +34 -0
- package/src/grammar/Grammar.ts +2 -2
- package/src/grammar/patterns/import.ts +1 -1
- package/src/grammar/patterns/optionsLiteral.ts +1 -1
- package/src/grammar/patterns/repeatLiteral.ts +8 -8
- package/src/intellisense/AutoComplete.test.ts +1 -1
- package/src/intellisense/AutoComplete.ts +7 -7
- package/src/patterns/Cursor.ts +13 -4
- package/src/patterns/FiniteRepeat.test.ts +6 -0
- package/src/patterns/FiniteRepeat.ts +1 -1
- package/src/patterns/InfiniteRepeat.test.ts +6 -0
- package/src/patterns/InfiniteRepeat.ts +1 -1
- package/src/patterns/Not.test.ts +0 -1
- package/src/patterns/Not.ts +0 -4
- package/src/patterns/Options.test.ts +24 -0
- package/src/patterns/Options.ts +13 -1
- package/src/patterns/Repeat.ts +2 -2
- package/src/patterns/Sequence.test.ts +3 -2
- package/src/patterns/Sequence.ts +2 -2
|
@@ -2,6 +2,11 @@ import { Node } from "../ast/Node";
|
|
|
2
2
|
import { Match } from "./CursorHistory";
|
|
3
3
|
import { ParseError } from "./ParseError";
|
|
4
4
|
import { Pattern } from "./Pattern";
|
|
5
|
+
export declare class CyclicalParseError extends Error {
|
|
6
|
+
readonly patternId: string;
|
|
7
|
+
readonly patternName: string;
|
|
8
|
+
constructor(patternId: string, patternName: string);
|
|
9
|
+
}
|
|
5
10
|
export declare class Cursor {
|
|
6
11
|
private _text;
|
|
7
12
|
private _index;
|
package/dist/patterns/Not.d.ts
CHANGED
|
@@ -14,7 +14,6 @@ export declare class Not implements Pattern {
|
|
|
14
14
|
get parent(): Pattern | null;
|
|
15
15
|
set parent(pattern: Pattern | null);
|
|
16
16
|
get children(): Pattern[];
|
|
17
|
-
get isOptional(): boolean;
|
|
18
17
|
constructor(name: string, pattern: Pattern);
|
|
19
18
|
test(text: string): boolean;
|
|
20
19
|
exec(text: string, record?: boolean): ParseResult;
|
|
@@ -21,8 +21,8 @@ export declare class Repeat implements Pattern {
|
|
|
21
21
|
get parent(): Pattern | null;
|
|
22
22
|
set parent(value: Pattern | null);
|
|
23
23
|
get children(): Pattern[];
|
|
24
|
-
get min():
|
|
25
|
-
get max():
|
|
24
|
+
get min(): number;
|
|
25
|
+
get max(): number;
|
|
26
26
|
constructor(name: string, pattern: Pattern, options?: RepeatOptions);
|
|
27
27
|
parse(cursor: Cursor): Node | null;
|
|
28
28
|
exec(text: string): ParseResult;
|
package/package.json
CHANGED
package/src/ast/Node.ts
CHANGED
|
@@ -315,6 +315,10 @@ export class Node {
|
|
|
315
315
|
return JSON.stringify(this.toCycleFreeObject(), null, space);
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
+
isEqual(node: Node) {
|
|
319
|
+
return node.toJson(0) === this.toJson(0);
|
|
320
|
+
}
|
|
321
|
+
|
|
318
322
|
static createValueNode(name: string, value: string) {
|
|
319
323
|
return new Node("custom-value-node", name, 0, 0, [], value);
|
|
320
324
|
}
|
|
@@ -511,4 +511,38 @@ describe("Grammar", () => {
|
|
|
511
511
|
expect(patterns.john).not.toBeNull();
|
|
512
512
|
expect(patterns.jane).not.toBeNull();
|
|
513
513
|
});
|
|
514
|
+
|
|
515
|
+
test("Grammar Import", async () => {
|
|
516
|
+
const importExpression = `first-name = "John"`;
|
|
517
|
+
const spaceExpression = `
|
|
518
|
+
use params { custom-space }
|
|
519
|
+
space = custom-space
|
|
520
|
+
`;
|
|
521
|
+
const expression = `
|
|
522
|
+
use params {
|
|
523
|
+
custom-space
|
|
524
|
+
}
|
|
525
|
+
import { first-name } from "first-name.cpat"
|
|
526
|
+
import { space } from "space.cpat" with params {
|
|
527
|
+
custom-space = custom-space
|
|
528
|
+
}
|
|
529
|
+
last-name = "Doe"
|
|
530
|
+
full-name = first-name + space + last-name
|
|
531
|
+
`;
|
|
532
|
+
|
|
533
|
+
const pathMap: Record<string, string> = {
|
|
534
|
+
"space.cpat": spaceExpression,
|
|
535
|
+
"first-name.cpat": importExpression,
|
|
536
|
+
"root.cpat": expression
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
function resolveImport(resource: string) {
|
|
540
|
+
return Promise.resolve({ expression: pathMap[resource], resource });
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
const patterns = await Grammar.import("root.cpat", { resolveImport, params: [new Literal("custom-space", " ")] });
|
|
544
|
+
const fullname = patterns["full-name"] as Pattern;
|
|
545
|
+
const result = fullname.exec("John Doe");
|
|
546
|
+
expect(result?.ast?.value).toBe("John Doe");
|
|
547
|
+
});
|
|
514
548
|
});
|
package/src/grammar/Grammar.ts
CHANGED
|
@@ -322,7 +322,7 @@ export class Grammar {
|
|
|
322
322
|
const trimDivider = repeatNode.find(n => n.name === "trim-flag") != null;
|
|
323
323
|
const patterNode = repeatNode.children[1].type === "spaces" ? repeatNode.children[2] : repeatNode.children[1];
|
|
324
324
|
const pattern = this._buildPattern(patterNode);
|
|
325
|
-
const dividerSectionNode = repeatNode.find(n => n.name === "divider-section");
|
|
325
|
+
const dividerSectionNode = repeatNode.find(n => n.name === "repeat-divider-section");
|
|
326
326
|
|
|
327
327
|
const options: RepeatOptions = {
|
|
328
328
|
min: 1,
|
|
@@ -462,7 +462,7 @@ export class Grammar {
|
|
|
462
462
|
);
|
|
463
463
|
|
|
464
464
|
const grammar = new Grammar({
|
|
465
|
-
params: importedValues,
|
|
465
|
+
params: [...importedValues, ...this._parseContext.paramsByName.values()],
|
|
466
466
|
originResource: this._originResource,
|
|
467
467
|
resolveImport: this._resolveImport
|
|
468
468
|
});
|
|
@@ -9,7 +9,7 @@ import { allSpaces, lineSpaces } from "./spaces";
|
|
|
9
9
|
import { Optional } from "../../patterns/Optional";
|
|
10
10
|
|
|
11
11
|
const optionalSpaces = new Optional("optional-spaces", allSpaces);
|
|
12
|
-
const optionalLineSpaces = new Optional("
|
|
12
|
+
const optionalLineSpaces = new Optional("optional-line-spaces", lineSpaces);
|
|
13
13
|
|
|
14
14
|
const importNameDivider = new Regex("import-name-divider", "(\\s+)?,(\\s+)?");
|
|
15
15
|
importNameDivider.setTokens([", "]);
|
|
@@ -7,7 +7,7 @@ import { Options } from "../../patterns/Options";
|
|
|
7
7
|
const patternName = name.clone("pattern-name");
|
|
8
8
|
patternName.setTokens(["[PATTERN_NAME]"]);
|
|
9
9
|
|
|
10
|
-
const patterns = new Options("
|
|
10
|
+
const patterns = new Options("options-patterns", [patternName, anonymousPattern]);
|
|
11
11
|
const defaultDivider = new Regex("default-divider", "\\s*[|]\\s*");
|
|
12
12
|
defaultDivider.setTokens(["|"]);
|
|
13
13
|
|
|
@@ -8,8 +8,8 @@ import { lineSpaces, spaces } from "./spaces";
|
|
|
8
8
|
import { Optional } from "../../patterns/Optional";
|
|
9
9
|
|
|
10
10
|
const optionalSpaces = new Optional("optional-spaces", spaces);
|
|
11
|
-
const openBracket = new Literal("open-bracket", "{");
|
|
12
|
-
const closeBracket = new Literal("close-bracket", "}");
|
|
11
|
+
const openBracket = new Literal("repeat-open-bracket", "{");
|
|
12
|
+
const closeBracket = new Literal("repeat-close-bracket", "}");
|
|
13
13
|
const comma = new Literal("comma", ",");
|
|
14
14
|
|
|
15
15
|
const integer = new Regex("integer", "([1-9][0-9]*)|0");
|
|
@@ -55,16 +55,16 @@ dividerComma.setTokens([", "]);
|
|
|
55
55
|
|
|
56
56
|
|
|
57
57
|
const patternName = name.clone("pattern-name");
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
const
|
|
58
|
+
const repeatPattern = new Options("repeat-pattern", [patternName, anonymousPattern]);
|
|
59
|
+
const repeatDividerPattern = repeatPattern.clone("repeat-divider-pattern");
|
|
60
|
+
const repeatDividerSection = new Sequence("repeat-divider-section", [dividerComma, repeatDividerPattern, trimFlag]);
|
|
61
|
+
const repeatOptionalDividerSection = new Optional("repeat-optional-divider-section", repeatDividerSection);
|
|
62
62
|
|
|
63
63
|
export const repeatLiteral = new Sequence("repeat-literal", [
|
|
64
64
|
openParen,
|
|
65
65
|
optionalSpaces,
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
repeatPattern,
|
|
67
|
+
repeatOptionalDividerSection,
|
|
68
68
|
optionalSpaces,
|
|
69
69
|
closeParen,
|
|
70
70
|
new Sequence("quantifier-section", [quantifier]),
|
|
@@ -118,7 +118,7 @@ describe("AutoComplete", () => {
|
|
|
118
118
|
|
|
119
119
|
expect(result.ast).toBeNull();
|
|
120
120
|
expect(result.options).toEqual(expectedOptions);
|
|
121
|
-
expect(result.errorAtIndex).toBe(text.length)
|
|
121
|
+
expect(result.errorAtIndex).toBe(text.length);
|
|
122
122
|
expect(result.isComplete).toBeFalsy();
|
|
123
123
|
expect(result.cursor).not.toBeNull();
|
|
124
124
|
});
|
|
@@ -48,11 +48,11 @@ export class AutoComplete {
|
|
|
48
48
|
errorAtIndex: 0,
|
|
49
49
|
cursor,
|
|
50
50
|
ast: null
|
|
51
|
-
}
|
|
51
|
+
};
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
let errorAtIndex = null;
|
|
55
|
-
let error = null
|
|
55
|
+
let error = null;
|
|
56
56
|
|
|
57
57
|
const ast = this._pattern.parse(this._cursor);
|
|
58
58
|
const isComplete = ast?.value === this._text;
|
|
@@ -74,7 +74,7 @@ export class AutoComplete {
|
|
|
74
74
|
errorAtIndex = startIndex;
|
|
75
75
|
} else if (!isComplete && this._cursor.hasError && this._cursor.furthestError != null) {
|
|
76
76
|
errorAtIndex = this._cursor.furthestError.endIndex;
|
|
77
|
-
error = this._cursor.furthestError
|
|
77
|
+
error = this._cursor.furthestError;
|
|
78
78
|
|
|
79
79
|
errorAtIndex = options.reduce((errorAtIndex, option) =>
|
|
80
80
|
Math.max(errorAtIndex, option.startIndex),
|
|
@@ -88,7 +88,7 @@ export class AutoComplete {
|
|
|
88
88
|
errorAtIndex,
|
|
89
89
|
cursor: cursor,
|
|
90
90
|
ast,
|
|
91
|
-
}
|
|
91
|
+
};
|
|
92
92
|
|
|
93
93
|
}
|
|
94
94
|
|
|
@@ -108,7 +108,7 @@ export class AutoComplete {
|
|
|
108
108
|
}
|
|
109
109
|
});
|
|
110
110
|
|
|
111
|
-
return finalResults
|
|
111
|
+
return finalResults;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
private _getOptionsFromErrors() {
|
|
@@ -159,7 +159,7 @@ export class AutoComplete {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
private _getTokensForPattern(pattern: Pattern) {
|
|
162
|
-
const augmentedTokens = this._getAugmentedTokens(pattern)
|
|
162
|
+
const augmentedTokens = this._getAugmentedTokens(pattern);
|
|
163
163
|
|
|
164
164
|
if (this._options.greedyPatternNames != null && this._options.greedyPatternNames.includes(pattern.name)) {
|
|
165
165
|
const nextPatterns = pattern.getNextPatterns();
|
|
@@ -225,7 +225,7 @@ export class AutoComplete {
|
|
|
225
225
|
return {
|
|
226
226
|
text: text,
|
|
227
227
|
startIndex: furthestMatch,
|
|
228
|
-
}
|
|
228
|
+
};
|
|
229
229
|
}
|
|
230
230
|
|
|
231
231
|
static suggestFor(text: string, pattern: Pattern, options?: AutoCompleteOptions) {
|
package/src/patterns/Cursor.ts
CHANGED
|
@@ -3,6 +3,17 @@ import { CursorHistory, Match, Trace } from "./CursorHistory";
|
|
|
3
3
|
import { ParseError } from "./ParseError";
|
|
4
4
|
import { Pattern } from "./Pattern";
|
|
5
5
|
|
|
6
|
+
export class CyclicalParseError extends Error {
|
|
7
|
+
readonly patternId: string;
|
|
8
|
+
readonly patternName: string;
|
|
9
|
+
|
|
10
|
+
constructor(patternId: string, patternName: string) {
|
|
11
|
+
super("Cyclical Parse Error");
|
|
12
|
+
this.patternId = patternId;
|
|
13
|
+
this.patternName = patternName;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
6
17
|
export class Cursor {
|
|
7
18
|
private _text: string;
|
|
8
19
|
private _index: number;
|
|
@@ -145,16 +156,14 @@ export class Cursor {
|
|
|
145
156
|
}
|
|
146
157
|
|
|
147
158
|
startParseWith(pattern: Pattern) {
|
|
148
|
-
const patternName = pattern.name;
|
|
149
|
-
|
|
150
159
|
const trace = {
|
|
151
160
|
pattern,
|
|
152
161
|
cursorIndex: this.index
|
|
153
162
|
};
|
|
154
163
|
|
|
155
|
-
const hasCycle = this._stackTrace.
|
|
164
|
+
const hasCycle = this._stackTrace.filter(t => t.pattern.id === pattern.id && this.index === t.cursorIndex).length > 1;
|
|
156
165
|
if (hasCycle) {
|
|
157
|
-
throw new
|
|
166
|
+
throw new CyclicalParseError(pattern.id, pattern.name);
|
|
158
167
|
}
|
|
159
168
|
|
|
160
169
|
this._history.pushStackTrace(trace);
|
|
@@ -478,4 +478,10 @@ describe("BoundedRepeat", () => {
|
|
|
478
478
|
expect(comma).toBe(numbers.children[1]);
|
|
479
479
|
});
|
|
480
480
|
|
|
481
|
+
test("Trim Trailing Complex Delimiter Pattern", () => {
|
|
482
|
+
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), { divider: new Sequence("comma", [new Literal(",", ","), new Literal("space", " ")]), trimDivider: true, max: 3 });
|
|
483
|
+
const result = numbers.parse(new Cursor("1, 2,"));
|
|
484
|
+
expect(result?.value).toBe("1, 2");
|
|
485
|
+
});
|
|
486
|
+
|
|
481
487
|
});
|
|
@@ -117,7 +117,7 @@ export class FiniteRepeat implements Pattern {
|
|
|
117
117
|
}
|
|
118
118
|
|
|
119
119
|
if (this._trimDivider && this._hasDivider) {
|
|
120
|
-
const isDividerLastMatch =
|
|
120
|
+
const isDividerLastMatch = this.children.length > 1 && nodes[nodes.length - 1].name === this.children[1].name;
|
|
121
121
|
if (isDividerLastMatch) {
|
|
122
122
|
const node = nodes.pop() as Node;
|
|
123
123
|
cursor.moveTo(node.firstIndex);
|
|
@@ -264,5 +264,11 @@ describe("InfiniteRepeat", () => {
|
|
|
264
264
|
expect(result.cursor.hasError).toBeTruthy();
|
|
265
265
|
});
|
|
266
266
|
|
|
267
|
+
test("Trim Trailing Complex Delimiter Pattern", () => {
|
|
268
|
+
const numbers = new InfiniteRepeat("numbers", new Regex("number", "\\d"), { divider: new Sequence("comma", [new Literal(",", ","), new Literal("space", " ")]), trimDivider: true });
|
|
269
|
+
const result = numbers.parse(new Cursor("1, 2,"));
|
|
270
|
+
expect(result?.value).toBe("1, 2");
|
|
271
|
+
});
|
|
272
|
+
|
|
267
273
|
|
|
268
274
|
});
|
|
@@ -235,7 +235,7 @@ export class InfiniteRepeat implements Pattern {
|
|
|
235
235
|
if (
|
|
236
236
|
hasDivider &&
|
|
237
237
|
this._trimDivider &&
|
|
238
|
-
|
|
238
|
+
this._nodes[this._nodes.length - 1].name === this._divider?.name
|
|
239
239
|
) {
|
|
240
240
|
const dividerNode = this._nodes.pop() as Node;
|
|
241
241
|
cursor.moveTo(dividerNode.firstIndex);
|
package/src/patterns/Not.test.ts
CHANGED
package/src/patterns/Not.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { Options } from "./Options";
|
|
|
5
5
|
import { Sequence } from "./Sequence";
|
|
6
6
|
import { Pattern } from "./Pattern";
|
|
7
7
|
import { Optional } from "./Optional";
|
|
8
|
+
import { Regex } from "./Regex";
|
|
9
|
+
import { Reference } from "./Reference";
|
|
8
10
|
|
|
9
11
|
describe("Options", () => {
|
|
10
12
|
test("Empty Options", () => {
|
|
@@ -271,4 +273,26 @@ describe("Options", () => {
|
|
|
271
273
|
const result = firstName.exec("Jane");
|
|
272
274
|
expect(result.ast?.value).toBe("Jane");
|
|
273
275
|
});
|
|
276
|
+
|
|
277
|
+
test("Cyclical Error Recorvery", () => {
|
|
278
|
+
const john = new Literal("john", "John");
|
|
279
|
+
const jane = new Literal("jane", "Jane");
|
|
280
|
+
const names = new Options("names", [john, jane]);
|
|
281
|
+
const questionMark = new Literal("?", "?");
|
|
282
|
+
const colon = new Literal(":", ":");
|
|
283
|
+
const space = new Regex("space", "\\s+");
|
|
284
|
+
const expressionReference = new Reference("expression");
|
|
285
|
+
const ternary = new Sequence("ternary", [expressionReference, space, questionMark, space, expressionReference, space, colon, space, expressionReference]);
|
|
286
|
+
const expression = new Options("expression", [names, ternary], true);
|
|
287
|
+
|
|
288
|
+
let result = expression.exec("John");
|
|
289
|
+
expect(result.ast?.toString()).toBe("John");
|
|
290
|
+
|
|
291
|
+
result = expression.exec("John ? Jane : John");
|
|
292
|
+
expect(result.ast?.toString()).toBe("John ? Jane : John");
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
result = expression.exec("John ? Jane : John ? Jane : John");
|
|
296
|
+
expect(result.ast?.toString()).toBe("John ? Jane : John ? Jane : John");
|
|
297
|
+
});
|
|
274
298
|
});
|
package/src/patterns/Options.ts
CHANGED
|
@@ -84,6 +84,7 @@ export class Options implements Pattern {
|
|
|
84
84
|
|
|
85
85
|
parse(cursor: Cursor): Node | null {
|
|
86
86
|
cursor.startParseWith(this);
|
|
87
|
+
|
|
87
88
|
this._firstIndex = cursor.index;
|
|
88
89
|
|
|
89
90
|
const node = this._tryToParse(cursor);
|
|
@@ -106,7 +107,18 @@ export class Options implements Pattern {
|
|
|
106
107
|
|
|
107
108
|
for (const pattern of this._children) {
|
|
108
109
|
cursor.moveTo(this._firstIndex);
|
|
109
|
-
|
|
110
|
+
let result = null;
|
|
111
|
+
|
|
112
|
+
try {
|
|
113
|
+
result = pattern.parse(cursor);
|
|
114
|
+
} catch (error: any) {
|
|
115
|
+
if (error.patternId === this._id) {
|
|
116
|
+
continue;
|
|
117
|
+
} else {
|
|
118
|
+
cursor.endParse();
|
|
119
|
+
throw error;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
110
122
|
|
|
111
123
|
if (this._isGreedy) {
|
|
112
124
|
results.push(result);
|
package/src/patterns/Repeat.ts
CHANGED
|
@@ -53,11 +53,11 @@ export class Repeat implements Pattern {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
get min() {
|
|
56
|
-
return
|
|
56
|
+
return this._options.min;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
get max() {
|
|
60
|
-
return
|
|
60
|
+
return this._options.max;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
constructor(name: string, pattern: Pattern, options: RepeatOptions = {}) {
|
|
@@ -3,6 +3,7 @@ import { Sequence } from "./Sequence";
|
|
|
3
3
|
import { Literal } from "./Literal";
|
|
4
4
|
import { Node } from "../ast/Node";
|
|
5
5
|
import { Optional } from "./Optional";
|
|
6
|
+
import { Pattern } from "./Pattern";
|
|
6
7
|
|
|
7
8
|
describe("Sequence", () => {
|
|
8
9
|
test("No Patterns", () => {
|
|
@@ -310,9 +311,9 @@ describe("Sequence", () => {
|
|
|
310
311
|
|
|
311
312
|
const sequenceClone = parent.find(p => p.name === "sequence");
|
|
312
313
|
const nextPatterns = sequenceClone?.getNextPatterns() || [];
|
|
313
|
-
const b = parent.find(p => p.name === "b")
|
|
314
|
+
const b = parent.find(p => p.name === "b") as Pattern;
|
|
314
315
|
|
|
315
|
-
expect(nextPatterns[0]
|
|
316
|
+
expect(nextPatterns[0].isEqual(b)).toBeTruthy();
|
|
316
317
|
});
|
|
317
318
|
|
|
318
319
|
test("Get Next Patterns With Null Parent", () => {
|
package/src/patterns/Sequence.ts
CHANGED
|
@@ -212,7 +212,7 @@ export class Sequence implements Pattern {
|
|
|
212
212
|
for (const child of this._children) {
|
|
213
213
|
tokens.push(...child.getTokens());
|
|
214
214
|
|
|
215
|
-
if (child.type !== "optional") {
|
|
215
|
+
if (child.type !== "optional" && child.type !== "not") {
|
|
216
216
|
break;
|
|
217
217
|
}
|
|
218
218
|
}
|
|
@@ -243,7 +243,7 @@ export class Sequence implements Pattern {
|
|
|
243
243
|
for (const child of this._children) {
|
|
244
244
|
patterns.push(...child.getPatterns());
|
|
245
245
|
|
|
246
|
-
if (child.type !== "optional") {
|
|
246
|
+
if (child.type !== "optional" && child.type !== "not") {
|
|
247
247
|
break;
|
|
248
248
|
}
|
|
249
249
|
}
|