clarity-pattern-parser 3.0.16 → 4.0.1
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 +0 -191
- package/dist/ast/Node.d.ts +4 -5
- package/dist/index.browser.js +476 -731
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +10 -18
- package/dist/index.esm.js +469 -716
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +476 -731
- package/dist/index.js.map +1 -1
- package/dist/patterns/And.d.ts +24 -0
- package/dist/patterns/Literal.d.ts +19 -0
- package/dist/patterns/LookAhead.d.ts +8 -0
- package/dist/patterns/Not.d.ts +11 -0
- package/dist/patterns/Or.d.ts +22 -0
- package/dist/patterns/Pattern.d.ts +6 -7
- package/dist/patterns/{RecursivePattern.d.ts → Recursive.d.ts} +4 -4
- package/dist/patterns/Reference.d.ts +14 -0
- package/dist/patterns/Regex.d.ts +21 -0
- package/dist/patterns/Repeat.d.ts +20 -0
- package/package.json +1 -1
- package/src/CursorHistory.ts +1 -1
- package/src/TextSuggester.ts +1 -1
- package/src/ast/Node.ts +20 -17
- package/src/ast/Visitor.ts +14 -18
- package/src/index.ts +17 -33
- package/src/patterns/And.ts +178 -0
- package/src/patterns/Literal.ts +91 -0
- package/src/patterns/Not.ts +50 -0
- package/src/patterns/Or.ts +132 -0
- package/src/patterns/Pattern.ts +31 -47
- package/src/patterns/Recursive.ts +92 -0
- package/src/patterns/{ReferencePattern.ts → Reference.ts} +32 -28
- package/src/patterns/Regex.ts +123 -0
- package/src/patterns/Repeat.ts +155 -0
- package/src/tests/{AndValue.test.ts → And.test.ts} +31 -41
- package/src/tests/CursorHistory.test.ts +6 -6
- package/src/tests/Cusor.test.ts +7 -10
- package/src/tests/Literal.test.ts +3 -5
- package/src/tests/LookAhead.test.ts +2 -51
- package/src/tests/Not.test.ts +51 -0
- package/src/tests/Or.test.ts +113 -0
- package/src/tests/Pattern.test.ts +40 -139
- package/src/tests/{RecursivePattern.test.ts → Recursive.test.ts} +10 -8
- package/src/tests/Reference.test.ts +16 -0
- package/src/tests/{RepeatValue.test.ts → Repeat.test.ts} +10 -42
- package/src/tests/TextSuggester.test.ts +30 -28
- package/src/tests/{NodeVisitor.test.ts → Visitor.test.ts} +42 -21
- package/src/tests/cssPatterns/cssValue.ts +2 -2
- package/src/tests/cssPatterns/divider.ts +2 -2
- package/src/tests/cssPatterns/hex.ts +2 -2
- package/src/tests/cssPatterns/method.ts +7 -9
- package/src/tests/cssPatterns/name.ts +2 -2
- package/src/tests/cssPatterns/number.ts +2 -2
- package/src/tests/cssPatterns/optionalSpaces.ts +1 -2
- package/src/tests/cssPatterns/spaces.ts +2 -2
- package/src/tests/cssPatterns/unit.ts +3 -3
- package/src/tests/cssPatterns/value.ts +2 -2
- package/src/tests/cssPatterns/values.ts +2 -2
- package/src/tests/htmlPatterns/element.ts +18 -33
- package/src/tests/javascriptPatterns/boolean.ts +2 -3
- package/src/tests/javascriptPatterns/json.ts +14 -26
- package/src/tests/javascriptPatterns/name.ts +3 -20
- package/src/tests/javascriptPatterns/number.ts +2 -2
- package/src/tests/javascriptPatterns/objectLiteral.ts +9 -16
- package/src/tests/javascriptPatterns/string.ts +26 -24
- package/src/tests/javascriptPatterns/unit.ts +3 -6
- package/src/tests/javascriptPatterns/whitespace.ts +8 -12
- package/src/tests/naturalLanguage/filter.ts +16 -33
- package/src/tests/patterns/sentence.ts +8 -8
- package/dist/Cursor.js +0 -105
- package/dist/Cursor.js.map +0 -1
- package/dist/CursorHistory.js +0 -104
- package/dist/CursorHistory.js.map +0 -1
- package/dist/Permutor.d.ts +0 -13
- package/dist/Permutor.js +0 -52
- package/dist/Permutor.js.map +0 -1
- package/dist/TextSuggester.js +0 -244
- package/dist/TextSuggester.js.map +0 -1
- package/dist/ast/CompositeNode.d.ts +0 -6
- package/dist/ast/CompositeNode.js +0 -17
- package/dist/ast/CompositeNode.js.map +0 -1
- package/dist/ast/Node.js +0 -16
- package/dist/ast/Node.js.map +0 -1
- package/dist/ast/NodeVisitor.d.ts +0 -31
- package/dist/ast/ValueNode.d.ts +0 -6
- package/dist/ast/ValueNode.js +0 -14
- package/dist/ast/ValueNode.js.map +0 -1
- package/dist/ast/Visitor.js +0 -209
- package/dist/ast/Visitor.js.map +0 -1
- package/dist/patterns/ParseError.js +0 -9
- package/dist/patterns/ParseError.js.map +0 -1
- package/dist/patterns/Pattern.js +0 -127
- package/dist/patterns/Pattern.js.map +0 -1
- package/dist/patterns/RecursivePattern.js +0 -65
- package/dist/patterns/RecursivePattern.js.map +0 -1
- package/dist/patterns/composite/AndComposite.d.ts +0 -22
- package/dist/patterns/composite/AndComposite.js +0 -117
- package/dist/patterns/composite/AndComposite.js.map +0 -1
- package/dist/patterns/composite/CompositePattern.d.ts +0 -4
- package/dist/patterns/composite/CompositePattern.js +0 -7
- package/dist/patterns/composite/CompositePattern.js.map +0 -1
- package/dist/patterns/composite/OptionalComposite.d.ts +0 -10
- package/dist/patterns/composite/OptionalComposite.js +0 -29
- package/dist/patterns/composite/OptionalComposite.js.map +0 -1
- package/dist/patterns/composite/OrComposite.d.ts +0 -16
- package/dist/patterns/composite/OrComposite.js +0 -69
- package/dist/patterns/composite/OrComposite.js.map +0 -1
- package/dist/patterns/composite/RepeatComposite.d.ts +0 -21
- package/dist/patterns/composite/RepeatComposite.js +0 -88
- package/dist/patterns/composite/RepeatComposite.js.map +0 -1
- package/dist/patterns/value/AndValue.d.ts +0 -21
- package/dist/patterns/value/AndValue.js +0 -118
- package/dist/patterns/value/AndValue.js.map +0 -1
- package/dist/patterns/value/AnyOfThese.d.ts +0 -18
- package/dist/patterns/value/AnyOfThese.js +0 -59
- package/dist/patterns/value/AnyOfThese.js.map +0 -1
- package/dist/patterns/value/Literal.d.ts +0 -20
- package/dist/patterns/value/Literal.js +0 -63
- package/dist/patterns/value/Literal.js.map +0 -1
- package/dist/patterns/value/NotValue.d.ts +0 -17
- package/dist/patterns/value/NotValue.js +0 -70
- package/dist/patterns/value/NotValue.js.map +0 -1
- package/dist/patterns/value/OptionalValue.d.ts +0 -9
- package/dist/patterns/value/OptionalValue.js +0 -32
- package/dist/patterns/value/OptionalValue.js.map +0 -1
- package/dist/patterns/value/OrValue.d.ts +0 -19
- package/dist/patterns/value/OrValue.js +0 -73
- package/dist/patterns/value/OrValue.js.map +0 -1
- package/dist/patterns/value/RegexValue.d.ts +0 -19
- package/dist/patterns/value/RegexValue.js +0 -69
- package/dist/patterns/value/RegexValue.js.map +0 -1
- package/dist/patterns/value/RepeatValue.d.ts +0 -19
- package/dist/patterns/value/RepeatValue.js +0 -89
- package/dist/patterns/value/RepeatValue.js.map +0 -1
- package/dist/patterns/value/ValuePattern.d.ts +0 -5
- package/dist/patterns/value/ValuePattern.js +0 -7
- package/dist/patterns/value/ValuePattern.js.map +0 -1
- package/src/Permutor.ts +0 -64
- package/src/ast/CompositeNode.ts +0 -26
- package/src/ast/ValueNode.ts +0 -28
- package/src/patterns/RecursivePattern.ts +0 -86
- package/src/patterns/composite/AndComposite.ts +0 -159
- package/src/patterns/composite/CompositePattern.ts +0 -7
- package/src/patterns/composite/OptionalComposite.ts +0 -37
- package/src/patterns/composite/OrComposite.ts +0 -96
- package/src/patterns/composite/RepeatComposite.ts +0 -130
- package/src/patterns/value/AndValue.ts +0 -152
- package/src/patterns/value/AnyOfThese.ts +0 -81
- package/src/patterns/value/Literal.ts +0 -92
- package/src/patterns/value/NotValue.ts +0 -95
- package/src/patterns/value/OptionalValue.ts +0 -39
- package/src/patterns/value/OrValue.ts +0 -103
- package/src/patterns/value/RegexValue.ts +0 -103
- package/src/patterns/value/RepeatValue.ts +0 -131
- package/src/patterns/value/ValuePattern.ts +0 -8
- package/src/tests/AndComposite.test.ts +0 -102
- package/src/tests/AnyOfThese.test.ts +0 -74
- package/src/tests/CompositeNode.test.ts +0 -33
- package/src/tests/NotValue.test.ts +0 -76
- package/src/tests/OptionalValue.test.ts +0 -50
- package/src/tests/OrComposite.test.ts +0 -75
- package/src/tests/OrValue.test.ts +0 -171
- package/src/tests/Permutor.test.ts +0 -30
- package/src/tests/ReferencePattern.test.ts +0 -24
- package/src/tests/RegexValue.test.ts +0 -22
- package/src/tests/RepeatComposite.test.ts +0 -58
- package/src/tests/ValueNode.test.ts +0 -24
- package/src/tests/javascriptPatterns/varStatement.ts +0 -0
- package/src/tests/readmeDemo.test.ts +0 -124
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import Pattern from "./Pattern";
|
|
2
|
+
import ParseError from "./ParseError";
|
|
3
|
+
import Cursor from "../Cursor";
|
|
4
|
+
import Node from "../ast/Node";
|
|
5
|
+
|
|
6
|
+
export default class Or extends Pattern {
|
|
7
|
+
public patternIndex: number = 0;
|
|
8
|
+
public errors: ParseError[] = [];
|
|
9
|
+
public node: Node | null = null;
|
|
10
|
+
public cursor: Cursor | null = null;
|
|
11
|
+
public mark: number = 0;
|
|
12
|
+
public parseError: ParseError | null = null;
|
|
13
|
+
|
|
14
|
+
constructor(name: string, patterns: Pattern[], isOptional = false) {
|
|
15
|
+
super("or", name, patterns, isOptional);
|
|
16
|
+
this.assertArguments();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
private assertArguments() {
|
|
20
|
+
if (this._children.length < 2) {
|
|
21
|
+
throw new Error(
|
|
22
|
+
"Invalid Argument: OrValue needs to have more than one value pattern."
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const hasOptionalChildren = this._children.some(
|
|
27
|
+
(pattern) => pattern.isOptional
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
if (hasOptionalChildren) {
|
|
31
|
+
throw new Error("OrValues cannot have optional patterns.");
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private resetState(cursor: Cursor) {
|
|
36
|
+
this.patternIndex = 0;
|
|
37
|
+
this.errors = [];
|
|
38
|
+
this.node = null;
|
|
39
|
+
this.cursor = cursor;
|
|
40
|
+
this.mark = cursor.mark();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private safelyGetCursor() {
|
|
44
|
+
const cursor = this.cursor;
|
|
45
|
+
|
|
46
|
+
if (cursor == null) {
|
|
47
|
+
throw new Error("Couldn't find cursor.");
|
|
48
|
+
}
|
|
49
|
+
return cursor;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
parse(cursor: Cursor) {
|
|
53
|
+
this.resetState(cursor);
|
|
54
|
+
this.tryToParse();
|
|
55
|
+
|
|
56
|
+
return this.node;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private tryToParse() {
|
|
60
|
+
const cursor = this.safelyGetCursor();
|
|
61
|
+
|
|
62
|
+
while (true) {
|
|
63
|
+
const pattern = this._children[this.patternIndex];
|
|
64
|
+
const node = pattern.parse(cursor);
|
|
65
|
+
const hasError = cursor.hasUnresolvedError();
|
|
66
|
+
|
|
67
|
+
if (hasError) {
|
|
68
|
+
const shouldBreak = this.processError();
|
|
69
|
+
if (shouldBreak) {
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
} else if (node != null) {
|
|
73
|
+
this.processResult(node);
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
private processError() {
|
|
80
|
+
const cursor = this.safelyGetCursor();
|
|
81
|
+
const isLastPattern = this.patternIndex + 1 === this._children.length;
|
|
82
|
+
|
|
83
|
+
if (!isLastPattern) {
|
|
84
|
+
this.patternIndex++;
|
|
85
|
+
cursor.resolveError();
|
|
86
|
+
cursor.moveToMark(this.mark);
|
|
87
|
+
return false;
|
|
88
|
+
} else {
|
|
89
|
+
if (this._isOptional) {
|
|
90
|
+
cursor.resolveError();
|
|
91
|
+
cursor.moveToMark(this.mark);
|
|
92
|
+
}
|
|
93
|
+
this.node = null;
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
private processResult(node: Node) {
|
|
99
|
+
const cursor = this.safelyGetCursor();
|
|
100
|
+
|
|
101
|
+
this.node = new Node(
|
|
102
|
+
"or",
|
|
103
|
+
this.name,
|
|
104
|
+
node.startIndex,
|
|
105
|
+
node.endIndex,
|
|
106
|
+
[node],
|
|
107
|
+
node.value
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
cursor.index = this.node.endIndex;
|
|
111
|
+
cursor.addMatch(this, this.node);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
clone(name?: string, isOptional?: boolean) {
|
|
115
|
+
if (name == null) {
|
|
116
|
+
name = this.name;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (isOptional == null) {
|
|
120
|
+
isOptional = this._isOptional;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return new Or(name, this._children, isOptional);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
getTokens() {
|
|
127
|
+
return this._children.reduce<string[]>(
|
|
128
|
+
(acc, c) => acc.concat(c.getTokens()),
|
|
129
|
+
[]
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
package/src/patterns/Pattern.ts
CHANGED
|
@@ -6,27 +6,26 @@ export default abstract class Pattern {
|
|
|
6
6
|
protected _name: string;
|
|
7
7
|
protected _children: Pattern[];
|
|
8
8
|
protected _parent: Pattern | null;
|
|
9
|
-
|
|
9
|
+
protected _isOptional = false;
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
get isOptional() {
|
|
12
|
+
return this._isOptional;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
constructor(
|
|
16
|
+
type: string,
|
|
17
|
+
name: string,
|
|
18
|
+
children: Pattern[] = [],
|
|
19
|
+
isOptional = false
|
|
20
|
+
) {
|
|
12
21
|
this._type = type;
|
|
13
22
|
this._name = name;
|
|
14
23
|
this._children = [];
|
|
15
24
|
this._parent = null;
|
|
16
|
-
this.
|
|
17
|
-
|
|
18
|
-
this._assertName();
|
|
25
|
+
this._isOptional = isOptional;
|
|
19
26
|
this.children = children;
|
|
20
27
|
}
|
|
21
28
|
|
|
22
|
-
private _assertName() {
|
|
23
|
-
if (typeof this.name !== "string") {
|
|
24
|
-
throw new Error(
|
|
25
|
-
"Invalid Argument: Patterns needs to have a name that's a string."
|
|
26
|
-
);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
29
|
abstract parse(cursor: Cursor): Node | null;
|
|
31
30
|
|
|
32
31
|
exec(text: string) {
|
|
@@ -57,9 +56,7 @@ export default abstract class Pattern {
|
|
|
57
56
|
}
|
|
58
57
|
|
|
59
58
|
set parent(value: Pattern | null) {
|
|
60
|
-
|
|
61
|
-
this._parent = value;
|
|
62
|
-
}
|
|
59
|
+
this._parent = value;
|
|
63
60
|
}
|
|
64
61
|
|
|
65
62
|
get children() {
|
|
@@ -68,38 +65,17 @@ export default abstract class Pattern {
|
|
|
68
65
|
|
|
69
66
|
set children(value) {
|
|
70
67
|
this._children = value;
|
|
71
|
-
this.
|
|
72
|
-
this.
|
|
73
|
-
this._assignAsParent();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
protected _assertChildren() {
|
|
77
|
-
// Empty,can be overridden by subclasses.
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
private _cloneChildren() {
|
|
81
|
-
// We need to clone the patterns so nested patterns can be parsed.
|
|
82
|
-
this._children = this._children.map((pattern) => {
|
|
83
|
-
if (!(pattern instanceof Pattern)) {
|
|
84
|
-
throw new Error(
|
|
85
|
-
`The ${this.name} pattern has an invalid child pattern.`
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
return pattern.clone();
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
// We need to freeze the children so they aren't modified.
|
|
92
|
-
Object.freeze(this._children);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
private _assignAsParent() {
|
|
96
|
-
this._children.forEach((child) => (child.parent = this));
|
|
68
|
+
this.cloneChildren();
|
|
69
|
+
this.assignAsParent();
|
|
97
70
|
}
|
|
98
71
|
|
|
99
72
|
abstract clone(name?: string): Pattern;
|
|
100
|
-
|
|
101
73
|
abstract getTokens(): string[];
|
|
102
74
|
|
|
75
|
+
getTokenValue(): string | null {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
103
79
|
getNextTokens(): string[] {
|
|
104
80
|
const parent = this._parent;
|
|
105
81
|
|
|
@@ -124,14 +100,14 @@ export default abstract class Pattern {
|
|
|
124
100
|
if (
|
|
125
101
|
this._parent?.type?.indexOf("and") === 0 &&
|
|
126
102
|
nextSibling != null &&
|
|
127
|
-
nextSibling
|
|
103
|
+
nextSibling.isOptional
|
|
128
104
|
) {
|
|
129
105
|
let tokens: string[] = [];
|
|
130
106
|
|
|
131
107
|
for (let x = index + 1; x < siblings.length; x++) {
|
|
132
108
|
const child = siblings[x];
|
|
133
109
|
|
|
134
|
-
if (child.
|
|
110
|
+
if (child.isOptional) {
|
|
135
111
|
tokens = tokens.concat(child.getTokens());
|
|
136
112
|
} else {
|
|
137
113
|
tokens = tokens.concat(child.getTokens());
|
|
@@ -161,7 +137,15 @@ export default abstract class Pattern {
|
|
|
161
137
|
return [];
|
|
162
138
|
}
|
|
163
139
|
|
|
164
|
-
|
|
165
|
-
|
|
140
|
+
private cloneChildren() {
|
|
141
|
+
this._children = this._children.map((pattern) => {
|
|
142
|
+
return pattern.clone();
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
Object.freeze(this._children);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
private assignAsParent() {
|
|
149
|
+
this._children.forEach((child) => (child.parent = this));
|
|
166
150
|
}
|
|
167
151
|
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import Pattern from "./Pattern";
|
|
2
|
+
import ParserError from "./ParseError";
|
|
3
|
+
import Cursor from "../Cursor";
|
|
4
|
+
|
|
5
|
+
export default class Recursive extends Pattern {
|
|
6
|
+
public isRecursing: boolean;
|
|
7
|
+
public pattern: Pattern | null = null;
|
|
8
|
+
|
|
9
|
+
constructor(name: string, isOptional = false) {
|
|
10
|
+
super("recursive", name, [], isOptional);
|
|
11
|
+
this.isRecursing = false;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
getPattern() {
|
|
15
|
+
return this.climb(this.parent, (pattern: Pattern | null) => {
|
|
16
|
+
if (pattern == null) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
return (
|
|
20
|
+
pattern.type !== "recursive" &&
|
|
21
|
+
pattern.name === this.name
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private climb(
|
|
27
|
+
pattern: Pattern | null,
|
|
28
|
+
isMatch: (pattern: Pattern | null) => boolean
|
|
29
|
+
): Pattern | null {
|
|
30
|
+
if (isMatch(pattern)) {
|
|
31
|
+
return pattern;
|
|
32
|
+
} else {
|
|
33
|
+
if (pattern && pattern.parent != null) {
|
|
34
|
+
return this.climb(pattern.parent, isMatch);
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
parse(cursor: Cursor) {
|
|
41
|
+
if (this.pattern == null) {
|
|
42
|
+
const pattern = this.getPattern();
|
|
43
|
+
|
|
44
|
+
if (pattern == null) {
|
|
45
|
+
if (!this._isOptional) {
|
|
46
|
+
cursor.throwError(
|
|
47
|
+
new ParserError(
|
|
48
|
+
`Couldn't find parent pattern to recursively parse, with the name ${this.name}.`,
|
|
49
|
+
cursor.index,
|
|
50
|
+
this
|
|
51
|
+
)
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
this.pattern = pattern.clone();
|
|
59
|
+
this.pattern.parent = this;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const mark = cursor.mark();
|
|
63
|
+
const node = this.pattern.parse(cursor);
|
|
64
|
+
|
|
65
|
+
if (!cursor.hasUnresolvedError() && node != null) {
|
|
66
|
+
cursor.addMatch(this, node);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (cursor.hasUnresolvedError() && this._isOptional) {
|
|
70
|
+
cursor.resolveError();
|
|
71
|
+
cursor.moveToMark(mark);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return node;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
clone(name?: string, isOptional?: boolean) {
|
|
78
|
+
if (name == null) {
|
|
79
|
+
name = this.name;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (isOptional == null) {
|
|
83
|
+
isOptional = this._isOptional;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return new Recursive(name, isOptional);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
getTokens() {
|
|
90
|
+
return this.getPattern()?.getTokens() || [];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -2,12 +2,9 @@ import Pattern from "./Pattern";
|
|
|
2
2
|
import ParserError from "./ParseError";
|
|
3
3
|
import Cursor from "../Cursor";
|
|
4
4
|
|
|
5
|
-
export default class
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
constructor(name: string) {
|
|
9
|
-
super("reference", name);
|
|
10
|
-
this.isRecursing = false;
|
|
5
|
+
export default class Reference extends Pattern {
|
|
6
|
+
constructor(name: string, isOptional = false) {
|
|
7
|
+
super("reference", name, [], isOptional);
|
|
11
8
|
}
|
|
12
9
|
|
|
13
10
|
private getRoot() {
|
|
@@ -61,6 +58,8 @@ export default class ReferencePattern extends Pattern {
|
|
|
61
58
|
}
|
|
62
59
|
|
|
63
60
|
parse(cursor: Cursor) {
|
|
61
|
+
const mark = cursor.mark();
|
|
62
|
+
|
|
64
63
|
try {
|
|
65
64
|
const node = this.safelyGetPattern().parse(cursor);
|
|
66
65
|
|
|
@@ -68,29 +67,39 @@ export default class ReferencePattern extends Pattern {
|
|
|
68
67
|
cursor.addMatch(this, node);
|
|
69
68
|
}
|
|
70
69
|
|
|
70
|
+
if (cursor.hasUnresolvedError() && this._isOptional) {
|
|
71
|
+
cursor.resolveError();
|
|
72
|
+
cursor.moveToMark(mark);
|
|
73
|
+
}
|
|
74
|
+
|
|
71
75
|
return node;
|
|
72
76
|
} catch (error) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
if (this._isOptional) {
|
|
78
|
+
cursor.moveToMark(mark);
|
|
79
|
+
} else {
|
|
80
|
+
cursor.throwError(
|
|
81
|
+
new ParserError(
|
|
82
|
+
`Couldn't find reference pattern to parse, with the name ${this.name}.`,
|
|
83
|
+
cursor.index,
|
|
84
|
+
this as Pattern
|
|
85
|
+
)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
80
88
|
|
|
81
89
|
return null;
|
|
82
90
|
}
|
|
83
91
|
}
|
|
84
92
|
|
|
85
|
-
clone(name?: string)
|
|
86
|
-
if (
|
|
93
|
+
clone(name?: string, isOptional?: boolean) {
|
|
94
|
+
if (name == null) {
|
|
87
95
|
name = this.name;
|
|
88
96
|
}
|
|
89
|
-
return new ReferencePattern(name);
|
|
90
|
-
}
|
|
91
97
|
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
if (isOptional == null) {
|
|
99
|
+
isOptional = this._isOptional;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return new Reference(name, isOptional);
|
|
94
103
|
}
|
|
95
104
|
|
|
96
105
|
private safelyGetPattern() {
|
|
@@ -105,19 +114,14 @@ export default class ReferencePattern extends Pattern {
|
|
|
105
114
|
);
|
|
106
115
|
}
|
|
107
116
|
|
|
108
|
-
|
|
117
|
+
pattern = reference;
|
|
118
|
+
this.children = [pattern];
|
|
109
119
|
}
|
|
120
|
+
|
|
110
121
|
return pattern;
|
|
111
122
|
}
|
|
112
123
|
|
|
113
124
|
getTokens() {
|
|
114
|
-
|
|
115
|
-
this.isRecursing = true;
|
|
116
|
-
let pattern = this.safelyGetPattern();
|
|
117
|
-
const tokens = pattern.getTokens();
|
|
118
|
-
this.isRecursing = false;
|
|
119
|
-
return tokens;
|
|
120
|
-
}
|
|
121
|
-
return [];
|
|
125
|
+
return this.safelyGetPattern().getTokens();
|
|
122
126
|
}
|
|
123
127
|
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import ParseError from "./ParseError";
|
|
2
|
+
import Node from "../ast/Node";
|
|
3
|
+
import Pattern from "./Pattern";
|
|
4
|
+
import Cursor from "../Cursor";
|
|
5
|
+
|
|
6
|
+
export default class Regex extends Pattern {
|
|
7
|
+
private regexString: string;
|
|
8
|
+
private regex: RegExp;
|
|
9
|
+
private node: Node | null = null;
|
|
10
|
+
private cursor: Cursor | null = null;
|
|
11
|
+
private substring: string = "";
|
|
12
|
+
|
|
13
|
+
constructor(name: string, regex: string, isOptional = false) {
|
|
14
|
+
super("regex", name, [], isOptional);
|
|
15
|
+
this.regexString = regex;
|
|
16
|
+
this.regex = new RegExp(`^${regex}`, "g");
|
|
17
|
+
this.assertArguments();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
private assertArguments() {
|
|
21
|
+
if (this.regexString.length < 1) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
"Invalid Arguments: The regex string argument needs to be at least one character long."
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (this.regexString.charAt(0) === "^") {
|
|
28
|
+
throw new Error(
|
|
29
|
+
"Invalid Arguments: The regex string cannot start with a '^' because it is expected to be in the middle of a string."
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (this.regexString.charAt(this.regexString.length - 1) === "$") {
|
|
34
|
+
throw new Error(
|
|
35
|
+
"Invalid Arguments: The regex string cannot end with a '$' because it is expected to be in the middle of a string."
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
parse(cursor: Cursor) {
|
|
41
|
+
this.resetState(cursor);
|
|
42
|
+
this.tryToParse();
|
|
43
|
+
|
|
44
|
+
return this.node;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private resetState(cursor: Cursor) {
|
|
48
|
+
this.cursor = cursor;
|
|
49
|
+
this.regex.lastIndex = 0;
|
|
50
|
+
this.substring = this.cursor.text.substr(this.cursor.getIndex());
|
|
51
|
+
this.node = null;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private tryToParse() {
|
|
55
|
+
const result = this.regex.exec(this.substring);
|
|
56
|
+
|
|
57
|
+
if (result != null && result.index === 0) {
|
|
58
|
+
this.processResult(result);
|
|
59
|
+
} else {
|
|
60
|
+
this.processError();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private processResult(result: RegExpExecArray) {
|
|
65
|
+
const cursor = this.safelyGetCursor();
|
|
66
|
+
const currentIndex = cursor.getIndex();
|
|
67
|
+
const newIndex = currentIndex + result[0].length - 1;
|
|
68
|
+
|
|
69
|
+
this.node = new Node(
|
|
70
|
+
"regex",
|
|
71
|
+
this.name,
|
|
72
|
+
currentIndex,
|
|
73
|
+
newIndex,
|
|
74
|
+
[],
|
|
75
|
+
result[0]
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
cursor.moveToMark(newIndex);
|
|
79
|
+
cursor.addMatch(this, this.node);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private processError() {
|
|
83
|
+
const cursor = this.safelyGetCursor();
|
|
84
|
+
|
|
85
|
+
if (!this._isOptional) {
|
|
86
|
+
const message = `ParseError: Expected regex pattern of '${this.regexString}' but found '${this.substring}'.`;
|
|
87
|
+
const parseError = new ParseError(message, cursor.getIndex(), this);
|
|
88
|
+
|
|
89
|
+
cursor.throwError(parseError);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
this.node = null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private safelyGetCursor() {
|
|
96
|
+
const cursor = this.cursor;
|
|
97
|
+
|
|
98
|
+
if (cursor == null) {
|
|
99
|
+
throw new Error("Couldn't find cursor.");
|
|
100
|
+
}
|
|
101
|
+
return cursor;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
clone(name?: string, isOptional?: boolean) {
|
|
105
|
+
if (name == null) {
|
|
106
|
+
name = this.name;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (isOptional == null) {
|
|
110
|
+
isOptional = this._isOptional;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return new Regex(name, this.regexString, isOptional);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
getTokenValue() {
|
|
117
|
+
return this.name;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
getTokens() {
|
|
121
|
+
return [this.name];
|
|
122
|
+
}
|
|
123
|
+
}
|