clarity-pattern-parser 4.0.3 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +176 -1
- package/TODO.md +22 -2
- package/dist/ast/Node.d.ts +43 -11
- package/dist/ast/Visitor.d.ts +31 -31
- package/dist/index.browser.js +1248 -1495
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +12 -17
- package/dist/index.esm.js +1218 -1460
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1217 -1464
- package/dist/index.js.map +1 -1
- package/dist/patterns/And.d.ts +37 -24
- package/dist/patterns/Cursor.d.ts +35 -0
- package/dist/patterns/CursorHistory.d.ts +30 -0
- package/dist/patterns/Literal.d.ts +36 -19
- package/dist/patterns/Not.d.ts +26 -11
- package/dist/patterns/Or.d.ts +31 -22
- package/dist/patterns/ParseError.d.ts +6 -8
- package/dist/patterns/ParseResult.d.ts +6 -0
- package/dist/patterns/Pattern.d.ts +17 -26
- package/dist/patterns/Reference.d.ts +31 -12
- package/dist/patterns/Regex.d.ts +42 -21
- package/dist/patterns/Repeat.d.ts +38 -20
- package/dist/patterns/clonePatterns.d.ts +2 -0
- package/dist/patterns/filterOutNull.d.ts +2 -0
- package/dist/patterns/findPattern.d.ts +2 -0
- package/dist/patterns/getNextPattern.d.ts +2 -0
- package/jest.config.js +2 -1
- package/package.json +4 -5
- package/rollup.config.js +1 -1
- package/src/ast/Node.test.ts +254 -0
- package/src/ast/Node.ts +171 -23
- package/src/index.ts +11 -24
- package/src/intellisense/AutoComplete.test.ts +72 -0
- package/src/intellisense/AutoComplete.ts +146 -0
- package/src/intellisense/Suggestion.ts +13 -0
- package/src/intellisense/SuggestionOption.ts +4 -0
- package/src/{tests/cssPatterns → intellisense/css}/cssValue.ts +1 -1
- package/src/{tests/cssPatterns → intellisense/css}/divider.ts +2 -1
- package/src/intellisense/css/hex.ts +6 -0
- package/src/{tests/cssPatterns → intellisense/css}/method.ts +8 -9
- package/src/intellisense/css/name.ts +5 -0
- package/src/{tests/javascriptPatterns → intellisense/css}/number.ts +3 -3
- package/src/intellisense/css/spaces.ts +6 -0
- package/src/intellisense/css/unit.ts +10 -0
- package/src/{tests/cssPatterns → intellisense/css}/value.ts +1 -1
- package/src/{tests/cssPatterns → intellisense/css}/values.ts +1 -1
- package/src/intellisense/javascript/Javascript.test.ts +203 -0
- package/src/intellisense/javascript/arrayLiteral.ts +25 -0
- package/src/intellisense/javascript/deleteStatement.ts +14 -0
- package/src/intellisense/javascript/escapedCharacter.ts +50 -0
- package/src/intellisense/javascript/exponent.ts +26 -0
- package/src/intellisense/javascript/expression.ts +87 -0
- package/src/intellisense/javascript/expressionStatement.ts +29 -0
- package/src/intellisense/javascript/fraction.ts +13 -0
- package/src/intellisense/javascript/infixOperator.ts +36 -0
- package/src/intellisense/javascript/integer.ts +7 -0
- package/src/intellisense/javascript/invocation.ts +28 -0
- package/src/intellisense/javascript/literal.ts +14 -0
- package/src/intellisense/javascript/name.ts +3 -0
- package/src/intellisense/javascript/numberLiteral.ts +10 -0
- package/src/intellisense/javascript/objectLiteral.ts +30 -0
- package/src/intellisense/javascript/optionalSpaces.ts +3 -0
- package/src/intellisense/javascript/parameters.ts +20 -0
- package/src/intellisense/javascript/prefixOperator.ts +13 -0
- package/src/intellisense/javascript/propertyAccess.ts +23 -0
- package/src/intellisense/javascript/stringLiteral.ts +28 -0
- package/src/patterns/And.test.ts +299 -0
- package/src/patterns/And.ts +222 -119
- package/src/patterns/Cursor.test.ts +93 -0
- package/src/patterns/Cursor.ts +130 -0
- package/src/patterns/CursorHistory.test.ts +54 -0
- package/src/patterns/CursorHistory.ts +95 -0
- package/src/patterns/Literal.test.ts +134 -0
- package/src/patterns/Literal.ts +151 -61
- package/src/patterns/Not.test.ts +88 -0
- package/src/patterns/Not.ts +74 -33
- package/src/patterns/Or.test.ts +105 -0
- package/src/patterns/Or.ts +106 -98
- package/src/patterns/ParseError.ts +3 -7
- package/src/patterns/ParseResult.ts +7 -0
- package/src/patterns/Pattern.ts +18 -150
- package/src/patterns/Reference.test.ts +104 -0
- package/src/patterns/Reference.ts +94 -94
- package/src/patterns/Regex.test.ts +101 -0
- package/src/patterns/Regex.ts +129 -60
- package/src/patterns/Repeat.test.ts +196 -0
- package/src/patterns/Repeat.ts +208 -104
- package/src/patterns/clonePatterns.ts +5 -0
- package/src/patterns/filterOutNull.ts +13 -0
- package/src/patterns/findPattern.ts +25 -0
- package/src/patterns/getNextPattern.test.ts +39 -0
- package/src/patterns/getNextPattern.ts +18 -0
- package/src/Cursor.ts +0 -141
- package/src/CursorHistory.ts +0 -146
- package/src/TextSuggester.ts +0 -317
- package/src/ast/Visitor.ts +0 -271
- package/src/patterns/LookAhead.ts +0 -32
- package/src/patterns/Recursive.ts +0 -92
- package/src/tests/And.test.ts +0 -180
- package/src/tests/ComplexExamples.test.ts +0 -86
- package/src/tests/CssPatterns.test.ts +0 -90
- package/src/tests/CursorHistory.test.ts +0 -107
- package/src/tests/Cusor.test.ts +0 -174
- package/src/tests/HtmlPatterns.test.ts +0 -34
- package/src/tests/Literal.test.ts +0 -79
- package/src/tests/LookAhead.test.ts +0 -44
- package/src/tests/Not.test.ts +0 -51
- package/src/tests/Or.test.ts +0 -113
- package/src/tests/Pattern.test.ts +0 -290
- package/src/tests/Recursive.test.ts +0 -64
- package/src/tests/Reference.test.ts +0 -16
- package/src/tests/Repeat.test.ts +0 -75
- package/src/tests/SpeedTest.test.ts +0 -31
- package/src/tests/TextSuggester.test.ts +0 -297
- package/src/tests/Visitor.test.ts +0 -331
- package/src/tests/cssPatterns/hex.ts +0 -5
- package/src/tests/cssPatterns/name.ts +0 -5
- package/src/tests/cssPatterns/number.ts +0 -8
- package/src/tests/cssPatterns/spaces.ts +0 -5
- package/src/tests/cssPatterns/unit.ts +0 -8
- package/src/tests/htmlPatterns/element.ts +0 -49
- package/src/tests/javascriptPatterns/boolean.ts +0 -10
- package/src/tests/javascriptPatterns/json.ts +0 -67
- package/src/tests/javascriptPatterns/name.ts +0 -5
- package/src/tests/javascriptPatterns/objectLiteral.ts +0 -40
- package/src/tests/javascriptPatterns/string.ts +0 -84
- package/src/tests/javascriptPatterns/unit.ts +0 -8
- package/src/tests/javascriptPatterns/whitespace.ts +0 -44
- package/src/tests/naturalLanguage/filter.ts +0 -37
- package/src/tests/patterns/sentence.ts +0 -37
- /package/src/{tests/cssPatterns → intellisense/css}/optionalSpaces.ts +0 -0
package/dist/index.esm.js
CHANGED
|
@@ -1,1491 +1,1249 @@
|
|
|
1
|
-
class Node {
|
|
2
|
-
|
|
3
|
-
this.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
this.
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
class Node {
|
|
2
|
+
get type() {
|
|
3
|
+
return this._type;
|
|
4
|
+
}
|
|
5
|
+
get name() {
|
|
6
|
+
return this._name;
|
|
7
|
+
}
|
|
8
|
+
get firstIndex() {
|
|
9
|
+
return this._firstIndex;
|
|
10
|
+
}
|
|
11
|
+
get lastIndex() {
|
|
12
|
+
return this._lastIndex;
|
|
13
|
+
}
|
|
14
|
+
get startIndex() {
|
|
15
|
+
return this._firstIndex;
|
|
16
|
+
}
|
|
17
|
+
get endIndex() {
|
|
18
|
+
return this._lastIndex + 1;
|
|
19
|
+
}
|
|
20
|
+
get parent() {
|
|
21
|
+
return this._parent;
|
|
22
|
+
}
|
|
23
|
+
get children() {
|
|
24
|
+
return this._children;
|
|
25
|
+
}
|
|
26
|
+
get value() {
|
|
27
|
+
return this.toString();
|
|
28
|
+
}
|
|
29
|
+
constructor(type, name, firstIndex, lastIndex, children = [], value = "") {
|
|
30
|
+
this._type = type;
|
|
31
|
+
this._name = name;
|
|
32
|
+
this._firstIndex = firstIndex;
|
|
33
|
+
this._lastIndex = lastIndex;
|
|
34
|
+
this._parent = null;
|
|
35
|
+
this._children = children;
|
|
36
|
+
this._value = value;
|
|
37
|
+
this._children.forEach(c => c._parent = this);
|
|
38
|
+
}
|
|
39
|
+
removeChild(node) {
|
|
40
|
+
const index = this._children.indexOf(node);
|
|
41
|
+
if (index > -1) {
|
|
42
|
+
this._children.splice(index, 1);
|
|
43
|
+
node._parent = null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
removeAllChildren() {
|
|
47
|
+
this._children.forEach(c => c._parent = null);
|
|
48
|
+
this._children.length = 0;
|
|
49
|
+
}
|
|
50
|
+
replaceChild(newNode, referenceNode) {
|
|
51
|
+
const index = this._children.indexOf(referenceNode);
|
|
52
|
+
if (index > -1) {
|
|
53
|
+
this._children.splice(index, 1, newNode);
|
|
54
|
+
newNode._parent = this;
|
|
55
|
+
referenceNode._parent = null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
insertBefore(newNode, referenceNode) {
|
|
59
|
+
newNode._parent = this;
|
|
60
|
+
if (referenceNode == null) {
|
|
61
|
+
this._children.push(newNode);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const index = this._children.indexOf(referenceNode);
|
|
65
|
+
if (index > -1) {
|
|
66
|
+
this._children.splice(index, 0, newNode);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
appendChild(newNode) {
|
|
70
|
+
newNode._parent = this;
|
|
71
|
+
this._children.push(newNode);
|
|
72
|
+
}
|
|
73
|
+
spliceChildren(index, deleteCount, ...items) {
|
|
74
|
+
const removedItems = this._children.splice(index, deleteCount, ...items);
|
|
75
|
+
items.forEach(i => i._parent = this);
|
|
76
|
+
removedItems.forEach(i => i._parent = null);
|
|
77
|
+
return removedItems;
|
|
78
|
+
}
|
|
79
|
+
find(isMatch) {
|
|
80
|
+
return this.findAll(isMatch)[0] || null;
|
|
81
|
+
}
|
|
82
|
+
findAll(isMatch) {
|
|
83
|
+
const matches = [];
|
|
84
|
+
this.walkUp(n => {
|
|
85
|
+
if (isMatch(n)) {
|
|
86
|
+
matches.push(n);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return matches;
|
|
90
|
+
}
|
|
91
|
+
walkUp(callback) {
|
|
92
|
+
this.children.forEach(c => c.walkUp(callback));
|
|
93
|
+
callback(this);
|
|
94
|
+
}
|
|
95
|
+
walkDown(callback) {
|
|
96
|
+
callback(this);
|
|
97
|
+
this.children.forEach(c => c.walkDown(callback));
|
|
98
|
+
}
|
|
99
|
+
clone() {
|
|
100
|
+
return new Node(this._type, this._name, this._firstIndex, this._lastIndex, this._children.map((c) => c.clone()), this._value);
|
|
101
|
+
}
|
|
102
|
+
toString() {
|
|
103
|
+
if (this._children.length === 0) {
|
|
104
|
+
return this._value;
|
|
105
|
+
}
|
|
106
|
+
return this._children.map(c => c.toString()).join("");
|
|
107
|
+
}
|
|
108
|
+
toCycleFreeObject() {
|
|
109
|
+
return {
|
|
110
|
+
type: this._type,
|
|
111
|
+
name: this._name,
|
|
112
|
+
value: this.toString(),
|
|
113
|
+
firstIndex: this._firstIndex,
|
|
114
|
+
lastIndex: this._lastIndex,
|
|
115
|
+
startIndex: this.startIndex,
|
|
116
|
+
endIndex: this.endIndex,
|
|
117
|
+
children: this._children.map(c => c.toCycleFreeObject()),
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
toJson(space) {
|
|
121
|
+
return JSON.stringify(this.toCycleFreeObject(), null, space);
|
|
122
|
+
}
|
|
16
123
|
}
|
|
17
124
|
|
|
18
|
-
class
|
|
19
|
-
constructor() {
|
|
20
|
-
this.
|
|
21
|
-
this.
|
|
22
|
-
|
|
23
|
-
astNode: null,
|
|
24
|
-
};
|
|
25
|
-
this.furthestError = null;
|
|
26
|
-
this.patterns = [];
|
|
27
|
-
this.astNodes = [];
|
|
28
|
-
this.errors = [];
|
|
29
|
-
}
|
|
30
|
-
addMatch(pattern, astNode) {
|
|
31
|
-
if (this.isRecording) {
|
|
32
|
-
this.patterns.push(pattern);
|
|
33
|
-
this.astNodes.push(astNode);
|
|
34
|
-
}
|
|
35
|
-
if (this.furthestMatch.astNode == null ||
|
|
36
|
-
astNode.endIndex >= this.furthestMatch.astNode.endIndex) {
|
|
37
|
-
this.furthestMatch.pattern = pattern;
|
|
38
|
-
this.furthestMatch.astNode = astNode;
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
addError(error) {
|
|
42
|
-
if (this.isRecording) {
|
|
43
|
-
this.errors.push(error);
|
|
44
|
-
}
|
|
45
|
-
if (this.furthestError == null || error.index >= this.furthestError.index) {
|
|
46
|
-
this.furthestError = error;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
startRecording() {
|
|
50
|
-
this.isRecording = true;
|
|
51
|
-
}
|
|
52
|
-
stopRecording() {
|
|
53
|
-
this.isRecording = false;
|
|
54
|
-
this.clear();
|
|
55
|
-
}
|
|
56
|
-
clear() {
|
|
57
|
-
this.patterns.length = 0;
|
|
58
|
-
this.astNodes.length = 0;
|
|
59
|
-
this.errors.length = 0;
|
|
60
|
-
}
|
|
61
|
-
getFurthestError() {
|
|
62
|
-
return this.furthestError;
|
|
63
|
-
}
|
|
64
|
-
getFurthestMatch() {
|
|
65
|
-
return this.furthestMatch;
|
|
66
|
-
}
|
|
67
|
-
getLastMatch() {
|
|
68
|
-
if (this.isRecording) {
|
|
69
|
-
return {
|
|
70
|
-
pattern: this.patterns[this.patterns.length - 1] || null,
|
|
71
|
-
astNode: this.astNodes[this.astNodes.length - 1] || null,
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
return this.furthestMatch;
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
getLastError() {
|
|
79
|
-
return this.errors[this.errors.length - 1] || null;
|
|
80
|
-
}
|
|
81
|
-
getAllParseStacks() {
|
|
82
|
-
const stacks = this.astNodes.reduce((acc, node) => {
|
|
83
|
-
let container = acc[acc.length - 1];
|
|
84
|
-
if (node.startIndex === 0) {
|
|
85
|
-
container = [];
|
|
86
|
-
acc.push(container);
|
|
87
|
-
}
|
|
88
|
-
container.push(node);
|
|
89
|
-
return acc;
|
|
90
|
-
}, []);
|
|
91
|
-
// There are times when the matching will fail and hit again on the same node.
|
|
92
|
-
// This filters them out.
|
|
93
|
-
// We simply check to see if there is any overlap with the previous one,
|
|
94
|
-
// and if there is we don't add it. This is why we move backwards.
|
|
95
|
-
const cleanedStack = stacks.map((stack) => {
|
|
96
|
-
const cleanedStack = [];
|
|
97
|
-
for (let x = stack.length - 1; x >= 0; x--) {
|
|
98
|
-
const currentNode = stack[x];
|
|
99
|
-
const previousNode = stack[x + 1];
|
|
100
|
-
if (previousNode == null) {
|
|
101
|
-
cleanedStack.unshift(currentNode);
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
const left = Math.max(currentNode.startIndex, previousNode.startIndex);
|
|
105
|
-
const right = Math.min(currentNode.endIndex, previousNode.endIndex);
|
|
106
|
-
const isOverlapping = left <= right;
|
|
107
|
-
if (!isOverlapping) {
|
|
108
|
-
cleanedStack.unshift(currentNode);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return cleanedStack;
|
|
113
|
-
});
|
|
114
|
-
return cleanedStack;
|
|
115
|
-
}
|
|
116
|
-
getLastParseStack() {
|
|
117
|
-
const stacks = this.getAllParseStacks();
|
|
118
|
-
return stacks[stacks.length - 1] || [];
|
|
119
|
-
}
|
|
125
|
+
class ParseError {
|
|
126
|
+
constructor(index, pattern) {
|
|
127
|
+
this.index = index;
|
|
128
|
+
this.pattern = pattern;
|
|
129
|
+
}
|
|
120
130
|
}
|
|
121
131
|
|
|
122
|
-
class
|
|
123
|
-
constructor(
|
|
124
|
-
this.
|
|
125
|
-
this.
|
|
126
|
-
this.
|
|
127
|
-
this.
|
|
128
|
-
this.
|
|
129
|
-
this.
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
this.
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
this.
|
|
141
|
-
}
|
|
142
|
-
get
|
|
143
|
-
return this.
|
|
144
|
-
}
|
|
145
|
-
get
|
|
146
|
-
return this.
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
this.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
moveToMark(mark) {
|
|
190
|
-
this.index = mark;
|
|
191
|
-
}
|
|
192
|
-
moveToBeginning() {
|
|
193
|
-
this.index = 0;
|
|
194
|
-
}
|
|
195
|
-
moveToEnd() {
|
|
196
|
-
this.index = this.text.length - 1;
|
|
197
|
-
}
|
|
198
|
-
getChar() {
|
|
199
|
-
return this.text.charAt(this.index);
|
|
200
|
-
}
|
|
201
|
-
getIndex() {
|
|
202
|
-
return this.index;
|
|
203
|
-
}
|
|
204
|
-
setIndex(index) {
|
|
205
|
-
if (typeof index === "number") {
|
|
206
|
-
if (index < 0 || index > this.lastIndex()) {
|
|
207
|
-
throw new Error("Cursor: Out of Bounds Exception.");
|
|
208
|
-
}
|
|
209
|
-
this.index = index;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
isAtBeginning() {
|
|
213
|
-
return this.index === 0;
|
|
214
|
-
}
|
|
215
|
-
isAtEnd() {
|
|
216
|
-
return this.index === this.text.length - 1;
|
|
217
|
-
}
|
|
218
|
-
lastIndex() {
|
|
219
|
-
return this.length - 1;
|
|
220
|
-
}
|
|
221
|
-
didSuccessfullyParse() {
|
|
222
|
-
return !this.hasUnresolvedError() && this.isAtEnd();
|
|
223
|
-
}
|
|
132
|
+
class CursorHistory {
|
|
133
|
+
constructor() {
|
|
134
|
+
this._isRecording = false;
|
|
135
|
+
this._leafMatch = { pattern: null, node: null };
|
|
136
|
+
this._furthestError = null;
|
|
137
|
+
this._currentError = null;
|
|
138
|
+
this._rootMatch = { pattern: null, node: null };
|
|
139
|
+
this._patterns = [];
|
|
140
|
+
this._nodes = [];
|
|
141
|
+
this._errors = [];
|
|
142
|
+
}
|
|
143
|
+
get leafMatch() {
|
|
144
|
+
return this._leafMatch;
|
|
145
|
+
}
|
|
146
|
+
get furthestError() {
|
|
147
|
+
return this._furthestError;
|
|
148
|
+
}
|
|
149
|
+
get isRecording() {
|
|
150
|
+
return this._isRecording;
|
|
151
|
+
}
|
|
152
|
+
get errors() {
|
|
153
|
+
return this._errors;
|
|
154
|
+
}
|
|
155
|
+
get error() {
|
|
156
|
+
return this._currentError;
|
|
157
|
+
}
|
|
158
|
+
get nodes() {
|
|
159
|
+
return this._nodes;
|
|
160
|
+
}
|
|
161
|
+
get patterns() {
|
|
162
|
+
return this._patterns;
|
|
163
|
+
}
|
|
164
|
+
get rootMatch() {
|
|
165
|
+
return this._rootMatch;
|
|
166
|
+
}
|
|
167
|
+
recordMatch(pattern, node) {
|
|
168
|
+
if (this._isRecording) {
|
|
169
|
+
this._patterns.push(pattern);
|
|
170
|
+
this._nodes.push(node);
|
|
171
|
+
}
|
|
172
|
+
this._rootMatch.pattern = pattern;
|
|
173
|
+
this._rootMatch.node = node;
|
|
174
|
+
const isFurthestMatch = this._leafMatch.node === null || node.lastIndex > this._leafMatch.node.lastIndex;
|
|
175
|
+
if (isFurthestMatch) {
|
|
176
|
+
this._leafMatch.pattern = pattern;
|
|
177
|
+
this._leafMatch.node = node;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
recordErrorAt(index, pattern) {
|
|
181
|
+
const error = new ParseError(index, pattern);
|
|
182
|
+
this._currentError = error;
|
|
183
|
+
if (this._furthestError === null || index > this._furthestError.index) {
|
|
184
|
+
this._furthestError = error;
|
|
185
|
+
}
|
|
186
|
+
if (this._isRecording) {
|
|
187
|
+
this._errors.push(error);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
startRecording() {
|
|
191
|
+
this._isRecording = true;
|
|
192
|
+
}
|
|
193
|
+
stopRecording() {
|
|
194
|
+
this._isRecording = false;
|
|
195
|
+
}
|
|
196
|
+
resolveError() {
|
|
197
|
+
this._currentError = null;
|
|
198
|
+
}
|
|
224
199
|
}
|
|
225
200
|
|
|
226
|
-
class
|
|
227
|
-
|
|
228
|
-
this.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
this.
|
|
232
|
-
}
|
|
201
|
+
class Cursor {
|
|
202
|
+
get text() {
|
|
203
|
+
return this._text;
|
|
204
|
+
}
|
|
205
|
+
get isOnFirst() {
|
|
206
|
+
return this._index === 0;
|
|
207
|
+
}
|
|
208
|
+
get isOnLast() {
|
|
209
|
+
return this._index === this._getLastIndex();
|
|
210
|
+
}
|
|
211
|
+
get isRecording() {
|
|
212
|
+
return this._history.isRecording;
|
|
213
|
+
}
|
|
214
|
+
get leafMatch() {
|
|
215
|
+
return this._history.leafMatch;
|
|
216
|
+
}
|
|
217
|
+
get rootMatch() {
|
|
218
|
+
return this._history.rootMatch;
|
|
219
|
+
}
|
|
220
|
+
get furthestError() {
|
|
221
|
+
return this._history.furthestError;
|
|
222
|
+
}
|
|
223
|
+
get error() {
|
|
224
|
+
return this._history.error;
|
|
225
|
+
}
|
|
226
|
+
get index() {
|
|
227
|
+
return this._index;
|
|
228
|
+
}
|
|
229
|
+
get length() {
|
|
230
|
+
return this._length;
|
|
231
|
+
}
|
|
232
|
+
get hasError() {
|
|
233
|
+
return this._history.error != null;
|
|
234
|
+
}
|
|
235
|
+
get currentChar() {
|
|
236
|
+
return this._text[this._index];
|
|
237
|
+
}
|
|
238
|
+
constructor(text) {
|
|
239
|
+
if (text.length === 0) {
|
|
240
|
+
throw new Error("Cannot have a empty string.");
|
|
241
|
+
}
|
|
242
|
+
this._text = text;
|
|
243
|
+
this._index = 0;
|
|
244
|
+
this._length = text.length;
|
|
245
|
+
this._history = new CursorHistory();
|
|
246
|
+
}
|
|
247
|
+
hasNext() {
|
|
248
|
+
return this._index + 1 < this._length;
|
|
249
|
+
}
|
|
250
|
+
hasPrevious() {
|
|
251
|
+
return this._index - 1 >= 0;
|
|
252
|
+
}
|
|
253
|
+
next() {
|
|
254
|
+
if (this.hasNext()) {
|
|
255
|
+
this._index++;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
previous() {
|
|
259
|
+
if (this.hasPrevious()) {
|
|
260
|
+
this._index--;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
moveTo(position) {
|
|
264
|
+
if (position >= 0 && position < this._length) {
|
|
265
|
+
this._index = position;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
moveToFirstChar() {
|
|
269
|
+
this._index = 0;
|
|
270
|
+
}
|
|
271
|
+
moveToLastChar() {
|
|
272
|
+
this._index = this._getLastIndex();
|
|
273
|
+
}
|
|
274
|
+
getChars(first, last) {
|
|
275
|
+
return this._text.slice(first, last + 1);
|
|
276
|
+
}
|
|
277
|
+
recordMatch(pattern, node) {
|
|
278
|
+
this._history.recordMatch(pattern, node);
|
|
279
|
+
}
|
|
280
|
+
recordErrorAt(index, onPattern) {
|
|
281
|
+
this._history.recordErrorAt(index, onPattern);
|
|
282
|
+
}
|
|
283
|
+
resolveError() {
|
|
284
|
+
this._history.resolveError();
|
|
285
|
+
}
|
|
286
|
+
startRecording() {
|
|
287
|
+
this._history.startRecording();
|
|
288
|
+
}
|
|
289
|
+
stopRecording() {
|
|
290
|
+
this._history.stopRecording();
|
|
291
|
+
}
|
|
292
|
+
_getLastIndex() {
|
|
293
|
+
return this._length - 1;
|
|
294
|
+
}
|
|
233
295
|
}
|
|
234
296
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return this._isOptional;
|
|
247
|
-
}
|
|
248
|
-
exec(text) {
|
|
249
|
-
const cursor = new Cursor(text);
|
|
250
|
-
const node = this.parse(cursor);
|
|
251
|
-
if (cursor.didSuccessfullyParse()) {
|
|
252
|
-
return node;
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
return null;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
test(text) {
|
|
259
|
-
return this.exec(text) != null;
|
|
260
|
-
}
|
|
261
|
-
get name() {
|
|
262
|
-
return this._name;
|
|
263
|
-
}
|
|
264
|
-
get type() {
|
|
265
|
-
return this._type;
|
|
266
|
-
}
|
|
267
|
-
get parent() {
|
|
268
|
-
return this._parent;
|
|
269
|
-
}
|
|
270
|
-
set parent(value) {
|
|
271
|
-
this._parent = value;
|
|
272
|
-
}
|
|
273
|
-
get children() {
|
|
274
|
-
return this._children;
|
|
275
|
-
}
|
|
276
|
-
set children(value) {
|
|
277
|
-
this._children = value;
|
|
278
|
-
this.cloneChildren();
|
|
279
|
-
this.assignAsParent();
|
|
280
|
-
}
|
|
281
|
-
getTokenValue() {
|
|
282
|
-
return null;
|
|
283
|
-
}
|
|
284
|
-
getNextTokens() {
|
|
285
|
-
var _a, _b;
|
|
286
|
-
const parent = this._parent;
|
|
287
|
-
if (parent != null) {
|
|
288
|
-
const siblings = parent.children;
|
|
289
|
-
const index = siblings.findIndex((c) => c === this);
|
|
290
|
-
const nextSibling = siblings[index + 1];
|
|
291
|
-
// I don't like this, so I think we need to rethink this.
|
|
292
|
-
if (parent.type.indexOf("repeat") === 0) {
|
|
293
|
-
const tokens = parent.getNextTokens();
|
|
294
|
-
if (index === 0 && siblings.length > 1) {
|
|
295
|
-
return nextSibling.getTokens().concat(tokens);
|
|
296
|
-
}
|
|
297
|
-
else if (index === 1) {
|
|
298
|
-
return siblings[0].getTokens();
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
301
|
-
return this.getTokens().concat(tokens);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
// Another thing I don't like.
|
|
305
|
-
if (((_b = (_a = this._parent) === null || _a === void 0 ? void 0 : _a.type) === null || _b === void 0 ? void 0 : _b.indexOf("and")) === 0 &&
|
|
306
|
-
nextSibling != null &&
|
|
307
|
-
nextSibling.isOptional) {
|
|
308
|
-
let tokens = [];
|
|
309
|
-
for (let x = index + 1; x < siblings.length; x++) {
|
|
310
|
-
const child = siblings[x];
|
|
311
|
-
if (child.isOptional) {
|
|
312
|
-
tokens = tokens.concat(child.getTokens());
|
|
313
|
-
}
|
|
314
|
-
else {
|
|
315
|
-
tokens = tokens.concat(child.getTokens());
|
|
316
|
-
break;
|
|
317
|
-
}
|
|
318
|
-
if (x === siblings.length - 1) {
|
|
319
|
-
tokens = tokens.concat(this._parent.getNextTokens());
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return tokens;
|
|
323
|
-
}
|
|
324
|
-
// If you are an or you have already qualified.
|
|
325
|
-
if (parent.type.indexOf("or") === 0) {
|
|
326
|
-
return parent.getNextTokens();
|
|
327
|
-
}
|
|
328
|
-
if (nextSibling != null) {
|
|
329
|
-
return nextSibling.getTokens();
|
|
330
|
-
}
|
|
331
|
-
else {
|
|
332
|
-
return parent.getNextTokens();
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
return [];
|
|
336
|
-
}
|
|
337
|
-
cloneChildren() {
|
|
338
|
-
this._children = this._children.map((pattern) => {
|
|
339
|
-
return pattern.clone();
|
|
340
|
-
});
|
|
341
|
-
Object.freeze(this._children);
|
|
342
|
-
}
|
|
343
|
-
assignAsParent() {
|
|
344
|
-
this._children.forEach((child) => (child.parent = this));
|
|
345
|
-
}
|
|
297
|
+
function getNextPattern(pattern) {
|
|
298
|
+
const parent = pattern.parent;
|
|
299
|
+
if (parent == null) {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
const patternIndex = parent.children.indexOf(pattern);
|
|
303
|
+
const nextPattern = parent.children[patternIndex + 1] || null;
|
|
304
|
+
if (nextPattern == null) {
|
|
305
|
+
return parent.getNextPattern();
|
|
306
|
+
}
|
|
307
|
+
return nextPattern;
|
|
346
308
|
}
|
|
347
309
|
|
|
348
|
-
class Regex
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
this.
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
this.
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
this.
|
|
371
|
-
this.
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
this.
|
|
376
|
-
this.
|
|
377
|
-
this.
|
|
378
|
-
this.
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
cursor
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
this.
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
if (
|
|
415
|
-
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
}
|
|
310
|
+
class Regex {
|
|
311
|
+
get type() {
|
|
312
|
+
return this._type;
|
|
313
|
+
}
|
|
314
|
+
get name() {
|
|
315
|
+
return this._name;
|
|
316
|
+
}
|
|
317
|
+
get parent() {
|
|
318
|
+
return this._parent;
|
|
319
|
+
}
|
|
320
|
+
set parent(pattern) {
|
|
321
|
+
this._parent = pattern;
|
|
322
|
+
}
|
|
323
|
+
get children() {
|
|
324
|
+
return [];
|
|
325
|
+
}
|
|
326
|
+
get isOptional() {
|
|
327
|
+
return this._isOptional;
|
|
328
|
+
}
|
|
329
|
+
constructor(name, regex, isOptional = false) {
|
|
330
|
+
this._node = null;
|
|
331
|
+
this._cursor = null;
|
|
332
|
+
this._substring = "";
|
|
333
|
+
this._tokens = [];
|
|
334
|
+
this._hasContextualTokenAggregation = false;
|
|
335
|
+
this._isRetrievingContextualTokens = false;
|
|
336
|
+
this._type = "regex";
|
|
337
|
+
this._name = name;
|
|
338
|
+
this._isOptional = isOptional;
|
|
339
|
+
this._parent = null;
|
|
340
|
+
this._originalRegexString = regex;
|
|
341
|
+
this._regex = new RegExp(`^${regex}`, "g");
|
|
342
|
+
this.assertArguments();
|
|
343
|
+
}
|
|
344
|
+
assertArguments() {
|
|
345
|
+
if (this._originalRegexString.length < 1) {
|
|
346
|
+
throw new Error("Invalid Arguments: The regex string argument needs to be at least one character long.");
|
|
347
|
+
}
|
|
348
|
+
if (this._originalRegexString.charAt(0) === "^") {
|
|
349
|
+
throw new Error("Invalid Arguments: The regex string cannot start with a '^' because it is expected to be in the middle of a string.");
|
|
350
|
+
}
|
|
351
|
+
if (this._originalRegexString.charAt(this._originalRegexString.length - 1) === "$") {
|
|
352
|
+
throw new Error("Invalid Arguments: The regex string cannot end with a '$' because it is expected to be in the middle of a string.");
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
parseText(text) {
|
|
356
|
+
const cursor = new Cursor(text);
|
|
357
|
+
const ast = this.parse(cursor);
|
|
358
|
+
return {
|
|
359
|
+
ast,
|
|
360
|
+
cursor
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
parse(cursor) {
|
|
364
|
+
this.resetState(cursor);
|
|
365
|
+
this.tryToParse(cursor);
|
|
366
|
+
return this._node;
|
|
367
|
+
}
|
|
368
|
+
resetState(cursor) {
|
|
369
|
+
this._cursor = cursor;
|
|
370
|
+
this._regex.lastIndex = 0;
|
|
371
|
+
this._substring = this._cursor.text.substr(this._cursor.index);
|
|
372
|
+
this._node = null;
|
|
373
|
+
}
|
|
374
|
+
tryToParse(cursor) {
|
|
375
|
+
const result = this._regex.exec(this._substring);
|
|
376
|
+
if (result != null && result.index === 0) {
|
|
377
|
+
this.processResult(cursor, result);
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
this.processError(cursor);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
processResult(cursor, result) {
|
|
384
|
+
const currentIndex = cursor.index;
|
|
385
|
+
const newIndex = currentIndex + result[0].length - 1;
|
|
386
|
+
this._node = new Node("regex", this._name, currentIndex, newIndex, [], result[0]);
|
|
387
|
+
cursor.moveTo(newIndex);
|
|
388
|
+
cursor.recordMatch(this, this._node);
|
|
389
|
+
}
|
|
390
|
+
processError(cursor) {
|
|
391
|
+
if (!this._isOptional) {
|
|
392
|
+
cursor.recordErrorAt(cursor.index, this);
|
|
393
|
+
}
|
|
394
|
+
this._node = null;
|
|
395
|
+
}
|
|
396
|
+
clone(name = this._name, isOptional = this._isOptional) {
|
|
397
|
+
const pattern = new Regex(name, this._originalRegexString, isOptional);
|
|
398
|
+
pattern._tokens = this._tokens.slice();
|
|
399
|
+
pattern._hasContextualTokenAggregation =
|
|
400
|
+
this._hasContextualTokenAggregation;
|
|
401
|
+
return pattern;
|
|
402
|
+
}
|
|
403
|
+
getTokens() {
|
|
404
|
+
const parent = this._parent;
|
|
405
|
+
if (this._hasContextualTokenAggregation &&
|
|
406
|
+
parent != null &&
|
|
407
|
+
!this._isRetrievingContextualTokens) {
|
|
408
|
+
this._isRetrievingContextualTokens = true;
|
|
409
|
+
const tokens = this._tokens;
|
|
410
|
+
const aggregateTokens = [];
|
|
411
|
+
const nextTokens = parent.getNextTokens(this);
|
|
412
|
+
for (let nextToken of nextTokens) {
|
|
413
|
+
for (let token of tokens) {
|
|
414
|
+
aggregateTokens.push(token + nextToken);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
this._isRetrievingContextualTokens = false;
|
|
418
|
+
return aggregateTokens;
|
|
419
|
+
}
|
|
420
|
+
return this._tokens;
|
|
421
|
+
}
|
|
422
|
+
getNextTokens(_reference) {
|
|
423
|
+
return [];
|
|
424
|
+
}
|
|
425
|
+
getNextPattern() {
|
|
426
|
+
return getNextPattern(this);
|
|
427
|
+
}
|
|
428
|
+
findPattern(_isMatch) {
|
|
429
|
+
return null;
|
|
430
|
+
}
|
|
431
|
+
setTokens(tokens) {
|
|
432
|
+
this._tokens = tokens;
|
|
433
|
+
}
|
|
434
|
+
enableContextualTokenAggregation() {
|
|
435
|
+
this._hasContextualTokenAggregation = true;
|
|
436
|
+
}
|
|
437
|
+
disableContextualTokenAggregation() {
|
|
438
|
+
this._hasContextualTokenAggregation = false;
|
|
439
|
+
}
|
|
428
440
|
}
|
|
429
441
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
super("and", name, patterns, isOptional);
|
|
433
|
-
this.onPatternIndex = 0;
|
|
434
|
-
this.nodes = [];
|
|
435
|
-
this.node = null;
|
|
436
|
-
this.cursor = null;
|
|
437
|
-
this.mark = 0;
|
|
438
|
-
}
|
|
439
|
-
parse(cursor) {
|
|
440
|
-
this.resetState(cursor);
|
|
441
|
-
this.tryToParse();
|
|
442
|
-
return this.node;
|
|
443
|
-
}
|
|
444
|
-
clone(name, isOptional) {
|
|
445
|
-
if (name == null) {
|
|
446
|
-
name = this.name;
|
|
447
|
-
}
|
|
448
|
-
if (isOptional == null) {
|
|
449
|
-
isOptional = this._isOptional;
|
|
450
|
-
}
|
|
451
|
-
return new And(name, this._children, isOptional);
|
|
452
|
-
}
|
|
453
|
-
getTokens() {
|
|
454
|
-
let tokens = [];
|
|
455
|
-
for (let x = 0; x < this._children.length; x++) {
|
|
456
|
-
const child = this._children[x];
|
|
457
|
-
if (child.isOptional) {
|
|
458
|
-
tokens = tokens.concat(child.getTokens());
|
|
459
|
-
}
|
|
460
|
-
else {
|
|
461
|
-
tokens = tokens.concat(child.getTokens());
|
|
462
|
-
break;
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
return tokens;
|
|
466
|
-
}
|
|
467
|
-
resetState(cursor) {
|
|
468
|
-
this.onPatternIndex = 0;
|
|
469
|
-
this.nodes = [];
|
|
470
|
-
this.node = null;
|
|
471
|
-
this.cursor = cursor;
|
|
472
|
-
this.mark = this.cursor.mark();
|
|
473
|
-
}
|
|
474
|
-
tryToParse() {
|
|
475
|
-
const cursor = this.safelyGetCursor();
|
|
476
|
-
while (true) {
|
|
477
|
-
const pattern = this._children[this.onPatternIndex];
|
|
478
|
-
const node = pattern.parse(cursor);
|
|
479
|
-
if (cursor.hasUnresolvedError()) {
|
|
480
|
-
this.processError();
|
|
481
|
-
break;
|
|
482
|
-
}
|
|
483
|
-
else {
|
|
484
|
-
this.nodes.push(node);
|
|
485
|
-
}
|
|
486
|
-
if (!this.shouldProceed()) {
|
|
487
|
-
this.processResult();
|
|
488
|
-
break;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
safelyGetCursor() {
|
|
493
|
-
const cursor = this.cursor;
|
|
494
|
-
if (cursor == null) {
|
|
495
|
-
throw new Error("Couldn't find cursor.");
|
|
496
|
-
}
|
|
497
|
-
return cursor;
|
|
498
|
-
}
|
|
499
|
-
processResult() {
|
|
500
|
-
const cursor = this.safelyGetCursor();
|
|
501
|
-
if (cursor.hasUnresolvedError()) {
|
|
502
|
-
this.processError();
|
|
503
|
-
}
|
|
504
|
-
else {
|
|
505
|
-
this.processSuccess();
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
processError() {
|
|
509
|
-
const cursor = this.safelyGetCursor();
|
|
510
|
-
if (this.isOptional) {
|
|
511
|
-
cursor.moveToMark(this.mark);
|
|
512
|
-
cursor.resolveError();
|
|
513
|
-
}
|
|
514
|
-
this.node = null;
|
|
515
|
-
}
|
|
516
|
-
shouldProceed() {
|
|
517
|
-
const cursor = this.safelyGetCursor();
|
|
518
|
-
if (this.hasMorePatterns()) {
|
|
519
|
-
const lastNode = this.nodes[this.nodes.length - 1];
|
|
520
|
-
const wasOptional = lastNode == null;
|
|
521
|
-
if (cursor.hasNext()) {
|
|
522
|
-
if (!wasOptional) {
|
|
523
|
-
cursor.next();
|
|
524
|
-
}
|
|
525
|
-
this.onPatternIndex++;
|
|
526
|
-
return true;
|
|
527
|
-
}
|
|
528
|
-
else if (wasOptional) {
|
|
529
|
-
this.onPatternIndex++;
|
|
530
|
-
return true;
|
|
531
|
-
}
|
|
532
|
-
this.assertRestOfPatternsAreOptional();
|
|
533
|
-
return false;
|
|
534
|
-
}
|
|
535
|
-
else {
|
|
536
|
-
return false;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
hasMorePatterns() {
|
|
540
|
-
return this.onPatternIndex + 1 < this._children.length;
|
|
541
|
-
}
|
|
542
|
-
assertRestOfPatternsAreOptional() {
|
|
543
|
-
const cursor = this.safelyGetCursor();
|
|
544
|
-
const areTheRestOptional = this.areTheRemainingPatternsOptional();
|
|
545
|
-
if (!areTheRestOptional) {
|
|
546
|
-
const parseError = new ParseError(`Could not match ${this.name} before string ran out.`, this.onPatternIndex, this);
|
|
547
|
-
cursor.throwError(parseError);
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
areTheRemainingPatternsOptional() {
|
|
551
|
-
return this.children
|
|
552
|
-
.slice(this.onPatternIndex + 1)
|
|
553
|
-
.map((p) => p.isOptional)
|
|
554
|
-
.every((r) => r);
|
|
555
|
-
}
|
|
556
|
-
processSuccess() {
|
|
557
|
-
const cursor = this.safelyGetCursor();
|
|
558
|
-
const nodes = this.nodes.filter((node) => node != null);
|
|
559
|
-
this.nodes = nodes;
|
|
560
|
-
const lastNode = nodes[this.nodes.length - 1];
|
|
561
|
-
const startIndex = this.mark;
|
|
562
|
-
const endIndex = lastNode.endIndex;
|
|
563
|
-
const value = nodes.map((node) => node.value).join("");
|
|
564
|
-
this.node = new Node("and", this.name, startIndex, endIndex, nodes, value);
|
|
565
|
-
cursor.index = this.node.endIndex;
|
|
566
|
-
cursor.addMatch(this, this.node);
|
|
567
|
-
}
|
|
442
|
+
function clonePatterns(patterns, isOptional) {
|
|
443
|
+
return patterns.map(p => p.clone(p.name, isOptional));
|
|
568
444
|
}
|
|
569
445
|
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
}
|
|
579
|
-
parse(cursor) {
|
|
580
|
-
this.resetState(cursor);
|
|
581
|
-
this.tryToParse();
|
|
582
|
-
return this.node;
|
|
583
|
-
}
|
|
584
|
-
clone(name, isOptional) {
|
|
585
|
-
if (name == null) {
|
|
586
|
-
name = this.name;
|
|
587
|
-
}
|
|
588
|
-
if (isOptional == null) {
|
|
589
|
-
isOptional = this._isOptional;
|
|
590
|
-
}
|
|
591
|
-
return new Literal(name, this.literal, isOptional);
|
|
592
|
-
}
|
|
593
|
-
getTokens() {
|
|
594
|
-
return [this.literal];
|
|
595
|
-
}
|
|
596
|
-
assertArguments() {
|
|
597
|
-
if (this.literal.length < 1) {
|
|
598
|
-
throw new Error("Invalid Arguments: The `literal` argument needs to be at least one character long.");
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
resetState(cursor) {
|
|
602
|
-
this.cursor = cursor;
|
|
603
|
-
this.mark = this.cursor.mark();
|
|
604
|
-
this.substring = this.cursor.text.substring(this.mark, this.mark + this.literal.length);
|
|
605
|
-
this.node = null;
|
|
606
|
-
}
|
|
607
|
-
tryToParse() {
|
|
608
|
-
if (this.substring === this.literal) {
|
|
609
|
-
this.processResult();
|
|
610
|
-
}
|
|
611
|
-
else {
|
|
612
|
-
this.processError();
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
processError() {
|
|
616
|
-
this.node = null;
|
|
617
|
-
if (!this._isOptional) {
|
|
618
|
-
const message = `ParseError: Expected '${this.literal}' but found '${this.substring}'.`;
|
|
619
|
-
const parseError = new ParseError(message, this.cursor.getIndex(), this);
|
|
620
|
-
this.cursor.throwError(parseError);
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
processResult() {
|
|
624
|
-
this.node = new Node("literal", this.name, this.mark, this.mark + this.literal.length - 1, [], this.substring);
|
|
625
|
-
this.cursor.index = this.node.endIndex;
|
|
626
|
-
this.cursor.addMatch(this, this.node);
|
|
627
|
-
}
|
|
446
|
+
function filterOutNull(nodes) {
|
|
447
|
+
const filteredNodes = [];
|
|
448
|
+
for (const node of nodes) {
|
|
449
|
+
if (node !== null) {
|
|
450
|
+
filteredNodes.push(node);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return filteredNodes;
|
|
628
454
|
}
|
|
629
455
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
return
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
return
|
|
649
|
-
}
|
|
456
|
+
function findPattern(pattern, predicate) {
|
|
457
|
+
let children = [];
|
|
458
|
+
if (pattern.type === "reference") {
|
|
459
|
+
children = [];
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
children = pattern.children;
|
|
463
|
+
}
|
|
464
|
+
for (const child of children) {
|
|
465
|
+
const result = findPattern(child, predicate);
|
|
466
|
+
if (result !== null) {
|
|
467
|
+
return result;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (predicate(pattern)) {
|
|
471
|
+
return pattern;
|
|
472
|
+
}
|
|
473
|
+
else {
|
|
474
|
+
return null;
|
|
475
|
+
}
|
|
650
476
|
}
|
|
651
477
|
|
|
652
|
-
class
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
this.
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
this.
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
}
|
|
478
|
+
class And {
|
|
479
|
+
get type() {
|
|
480
|
+
return this._type;
|
|
481
|
+
}
|
|
482
|
+
get name() {
|
|
483
|
+
return this._name;
|
|
484
|
+
}
|
|
485
|
+
get parent() {
|
|
486
|
+
return this._parent;
|
|
487
|
+
}
|
|
488
|
+
set parent(pattern) {
|
|
489
|
+
this._parent = pattern;
|
|
490
|
+
}
|
|
491
|
+
get children() {
|
|
492
|
+
return this._children;
|
|
493
|
+
}
|
|
494
|
+
get isOptional() {
|
|
495
|
+
return this._isOptional;
|
|
496
|
+
}
|
|
497
|
+
constructor(name, sequence, isOptional = false) {
|
|
498
|
+
if (sequence.length === 0) {
|
|
499
|
+
throw new Error("Need at least one pattern with an 'and' pattern.");
|
|
500
|
+
}
|
|
501
|
+
const children = clonePatterns(sequence);
|
|
502
|
+
this._assignChildrenToParent(children);
|
|
503
|
+
this._type = "and";
|
|
504
|
+
this._name = name;
|
|
505
|
+
this._isOptional = isOptional;
|
|
506
|
+
this._parent = null;
|
|
507
|
+
this._children = children;
|
|
508
|
+
this._firstIndex = -1;
|
|
509
|
+
this._shouldReduceAst = false;
|
|
510
|
+
this._nodes = [];
|
|
511
|
+
}
|
|
512
|
+
_assignChildrenToParent(children) {
|
|
513
|
+
for (const child of children) {
|
|
514
|
+
child.parent = this;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
parseText(text) {
|
|
518
|
+
const cursor = new Cursor(text);
|
|
519
|
+
const ast = this.parse(cursor);
|
|
520
|
+
return {
|
|
521
|
+
ast,
|
|
522
|
+
cursor
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
parse(cursor) {
|
|
526
|
+
this._firstIndex = cursor.index;
|
|
527
|
+
this._nodes = [];
|
|
528
|
+
const passed = this.tryToParse(cursor);
|
|
529
|
+
if (passed) {
|
|
530
|
+
const node = this.createNode(cursor);
|
|
531
|
+
if (node !== null) {
|
|
532
|
+
cursor.recordMatch(this, node);
|
|
533
|
+
}
|
|
534
|
+
return node;
|
|
535
|
+
}
|
|
536
|
+
if (this._isOptional) {
|
|
537
|
+
cursor.resolveError();
|
|
538
|
+
}
|
|
539
|
+
return null;
|
|
540
|
+
}
|
|
541
|
+
tryToParse(cursor) {
|
|
542
|
+
let passed = false;
|
|
543
|
+
for (let i = 0; i < this._children.length; i++) {
|
|
544
|
+
const runningCursorIndex = cursor.index;
|
|
545
|
+
const nextPatternIndex = i + 1;
|
|
546
|
+
const hasMorePatterns = nextPatternIndex < this._children.length;
|
|
547
|
+
const node = this._children[i].parse(cursor);
|
|
548
|
+
const hasNoError = !cursor.hasError;
|
|
549
|
+
const hadMatch = node !== null;
|
|
550
|
+
if (hasNoError) {
|
|
551
|
+
this._nodes.push(node);
|
|
552
|
+
if (hasMorePatterns) {
|
|
553
|
+
if (hadMatch) {
|
|
554
|
+
if (cursor.hasNext()) {
|
|
555
|
+
cursor.next();
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
if (this.areRemainingPatternsOptional(i)) {
|
|
560
|
+
passed = true;
|
|
561
|
+
break;
|
|
562
|
+
}
|
|
563
|
+
cursor.recordErrorAt(cursor.index + 1, this);
|
|
564
|
+
break;
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
else {
|
|
568
|
+
cursor.moveTo(runningCursorIndex);
|
|
569
|
+
continue;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
const lastNode = this.getLastValidNode();
|
|
574
|
+
if (lastNode === null) {
|
|
575
|
+
cursor.recordErrorAt(cursor.index, this);
|
|
576
|
+
break;
|
|
577
|
+
}
|
|
578
|
+
passed = true;
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
else {
|
|
583
|
+
cursor.moveTo(this._firstIndex);
|
|
584
|
+
break;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
return passed;
|
|
588
|
+
}
|
|
589
|
+
getLastValidNode() {
|
|
590
|
+
const nodes = filterOutNull(this._nodes);
|
|
591
|
+
if (nodes.length === 0) {
|
|
592
|
+
return null;
|
|
593
|
+
}
|
|
594
|
+
return nodes[nodes.length - 1];
|
|
595
|
+
}
|
|
596
|
+
areRemainingPatternsOptional(fromIndex) {
|
|
597
|
+
const startOnIndex = fromIndex + 1;
|
|
598
|
+
const length = this._children.length;
|
|
599
|
+
for (let i = startOnIndex; i < length; i++) {
|
|
600
|
+
const pattern = this._children[i];
|
|
601
|
+
if (!pattern.isOptional) {
|
|
602
|
+
return false;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
return true;
|
|
606
|
+
}
|
|
607
|
+
createNode(cursor) {
|
|
608
|
+
const children = filterOutNull(this._nodes);
|
|
609
|
+
const lastIndex = children[children.length - 1].lastIndex;
|
|
610
|
+
const value = cursor.getChars(this._firstIndex, lastIndex);
|
|
611
|
+
cursor.moveTo(lastIndex);
|
|
612
|
+
if (this._shouldReduceAst) {
|
|
613
|
+
children.length = 0;
|
|
614
|
+
}
|
|
615
|
+
return new Node("and", this._name, this._firstIndex, lastIndex, children, this._shouldReduceAst ? value : undefined);
|
|
616
|
+
}
|
|
617
|
+
enableAstReduction() {
|
|
618
|
+
this._shouldReduceAst = true;
|
|
619
|
+
}
|
|
620
|
+
disableAstReduction() {
|
|
621
|
+
this._shouldReduceAst = false;
|
|
622
|
+
}
|
|
623
|
+
getTokens() {
|
|
624
|
+
const tokens = [];
|
|
625
|
+
for (const child of this._children) {
|
|
626
|
+
tokens.push(...child.getTokens());
|
|
627
|
+
if (!child.isOptional) {
|
|
628
|
+
break;
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
return tokens;
|
|
632
|
+
}
|
|
633
|
+
getNextTokens(lastMatched) {
|
|
634
|
+
let nextSibling = null;
|
|
635
|
+
let nextSiblingIndex = -1;
|
|
636
|
+
let index = -1;
|
|
637
|
+
const tokens = [];
|
|
638
|
+
for (let i = 0; i < this._children.length; i++) {
|
|
639
|
+
if (this._children[i] === lastMatched) {
|
|
640
|
+
if (i + 1 < this._children.length) {
|
|
641
|
+
nextSibling = this._children[i + 1];
|
|
642
|
+
}
|
|
643
|
+
nextSiblingIndex = i + 1;
|
|
644
|
+
index = i;
|
|
645
|
+
break;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
if (index === -1) {
|
|
649
|
+
return [];
|
|
650
|
+
}
|
|
651
|
+
if (nextSiblingIndex === this._children.length && this._parent !== null) {
|
|
652
|
+
return this._parent.getNextTokens(this);
|
|
653
|
+
}
|
|
654
|
+
if (nextSibling !== null && !nextSibling.isOptional) {
|
|
655
|
+
return nextSibling.getTokens();
|
|
656
|
+
}
|
|
657
|
+
if (nextSibling !== null && nextSibling.isOptional) {
|
|
658
|
+
for (let i = nextSiblingIndex; i < this._children.length; i++) {
|
|
659
|
+
const child = this._children[i];
|
|
660
|
+
tokens.push(...child.getTokens());
|
|
661
|
+
if (!child.isOptional) {
|
|
662
|
+
break;
|
|
663
|
+
}
|
|
664
|
+
if (i === this._children.length - 1 && this._parent !== null) {
|
|
665
|
+
tokens.push(...this._parent.getNextTokens(this));
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
return tokens;
|
|
670
|
+
}
|
|
671
|
+
getNextPattern() {
|
|
672
|
+
return getNextPattern(this);
|
|
673
|
+
}
|
|
674
|
+
findPattern(isMatch) {
|
|
675
|
+
return findPattern(this, isMatch);
|
|
676
|
+
}
|
|
677
|
+
clone(name = this._name, isOptional = this._isOptional) {
|
|
678
|
+
const and = new And(name, this._children, isOptional);
|
|
679
|
+
and._shouldReduceAst = this._shouldReduceAst;
|
|
680
|
+
return and;
|
|
681
|
+
}
|
|
686
682
|
}
|
|
687
683
|
|
|
688
|
-
class
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
this.
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
this.
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
this.
|
|
712
|
-
this.
|
|
713
|
-
this.
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
this.
|
|
725
|
-
return
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
684
|
+
class Literal {
|
|
685
|
+
get type() {
|
|
686
|
+
return this._type;
|
|
687
|
+
}
|
|
688
|
+
get name() {
|
|
689
|
+
return this._name;
|
|
690
|
+
}
|
|
691
|
+
get parent() {
|
|
692
|
+
return this._parent;
|
|
693
|
+
}
|
|
694
|
+
set parent(pattern) {
|
|
695
|
+
this._parent = pattern;
|
|
696
|
+
}
|
|
697
|
+
get children() {
|
|
698
|
+
return [];
|
|
699
|
+
}
|
|
700
|
+
get isOptional() {
|
|
701
|
+
return this._isOptional;
|
|
702
|
+
}
|
|
703
|
+
constructor(name, value, isOptional = false) {
|
|
704
|
+
if (value.length === 0) {
|
|
705
|
+
throw new Error("Value Cannot be empty.");
|
|
706
|
+
}
|
|
707
|
+
this._type = "literal";
|
|
708
|
+
this._name = name;
|
|
709
|
+
this._literal = value;
|
|
710
|
+
this._runes = Array.from(value);
|
|
711
|
+
this._isOptional = isOptional;
|
|
712
|
+
this._parent = null;
|
|
713
|
+
this._firstIndex = 0;
|
|
714
|
+
this._lastIndex = 0;
|
|
715
|
+
this._hasContextualTokenAggregation = false;
|
|
716
|
+
this._isRetrievingContextualTokens = false;
|
|
717
|
+
}
|
|
718
|
+
parseText(text) {
|
|
719
|
+
const cursor = new Cursor(text);
|
|
720
|
+
const ast = this.parse(cursor);
|
|
721
|
+
return {
|
|
722
|
+
ast,
|
|
723
|
+
cursor
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
parse(cursor) {
|
|
727
|
+
this._firstIndex = cursor.index;
|
|
728
|
+
const passed = this._tryToParse(cursor);
|
|
729
|
+
if (passed) {
|
|
730
|
+
cursor.resolveError();
|
|
731
|
+
const node = this._createNode();
|
|
732
|
+
cursor.recordMatch(this, node);
|
|
733
|
+
return node;
|
|
734
|
+
}
|
|
735
|
+
if (!this._isOptional) {
|
|
736
|
+
cursor.recordErrorAt(cursor.index, this);
|
|
737
|
+
return null;
|
|
738
|
+
}
|
|
739
|
+
cursor.resolveError();
|
|
740
|
+
cursor.moveTo(this._firstIndex);
|
|
741
|
+
return null;
|
|
742
|
+
}
|
|
743
|
+
_tryToParse(cursor) {
|
|
744
|
+
let passed = false;
|
|
745
|
+
const literalRuneLength = this._runes.length;
|
|
746
|
+
for (let i = 0; i < literalRuneLength; i++) {
|
|
747
|
+
const literalRune = this._runes[i];
|
|
748
|
+
const cursorRune = cursor.currentChar;
|
|
749
|
+
if (literalRune !== cursorRune) {
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
752
|
+
if (i + 1 === literalRuneLength) {
|
|
753
|
+
this._lastIndex = this._firstIndex + this._literal.length - 1;
|
|
754
|
+
passed = true;
|
|
755
|
+
break;
|
|
756
|
+
}
|
|
757
|
+
if (!cursor.hasNext()) {
|
|
758
|
+
break;
|
|
759
|
+
}
|
|
760
|
+
cursor.next();
|
|
761
|
+
}
|
|
762
|
+
return passed;
|
|
763
|
+
}
|
|
764
|
+
_createNode() {
|
|
765
|
+
return new Node("literal", this._name, this._firstIndex, this._lastIndex, [], this._literal);
|
|
766
|
+
}
|
|
767
|
+
clone(name = this._name, isOptional = this._isOptional) {
|
|
768
|
+
const clone = new Literal(name, this._literal, isOptional);
|
|
769
|
+
clone._hasContextualTokenAggregation = this._hasContextualTokenAggregation;
|
|
770
|
+
return clone;
|
|
771
|
+
}
|
|
772
|
+
getTokens() {
|
|
773
|
+
const parent = this._parent;
|
|
774
|
+
if (this._hasContextualTokenAggregation &&
|
|
775
|
+
parent != null &&
|
|
776
|
+
!this._isRetrievingContextualTokens) {
|
|
777
|
+
this._isRetrievingContextualTokens = true;
|
|
778
|
+
const aggregateTokens = [];
|
|
779
|
+
const nextTokens = parent.getNextTokens(this);
|
|
780
|
+
for (const nextToken of nextTokens) {
|
|
781
|
+
aggregateTokens.push(this._literal + nextToken);
|
|
782
|
+
}
|
|
783
|
+
this._isRetrievingContextualTokens = false;
|
|
784
|
+
return aggregateTokens;
|
|
785
|
+
}
|
|
786
|
+
else {
|
|
787
|
+
return [this._literal];
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
getNextTokens(_lastMatched) {
|
|
791
|
+
return [];
|
|
792
|
+
}
|
|
793
|
+
getNextPattern() {
|
|
794
|
+
return getNextPattern(this);
|
|
795
|
+
}
|
|
796
|
+
findPattern(_isMatch) {
|
|
797
|
+
return null;
|
|
798
|
+
}
|
|
799
|
+
enableContextualTokenAggregation() {
|
|
800
|
+
this._hasContextualTokenAggregation = true;
|
|
801
|
+
}
|
|
802
|
+
disableContextualTokenAggregation() {
|
|
803
|
+
this._hasContextualTokenAggregation = false;
|
|
804
|
+
}
|
|
781
805
|
}
|
|
782
806
|
|
|
783
|
-
class
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
this.
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
this.
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
this.
|
|
805
|
-
this.
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
this.cursor.resolveError();
|
|
848
|
-
if ((hasDivider && endsOnDivider) || noMatch) {
|
|
849
|
-
if (this._isOptional) {
|
|
850
|
-
this.cursor.moveToMark(this.mark);
|
|
851
|
-
}
|
|
852
|
-
else {
|
|
853
|
-
const parseError = new ParseError(`Did not find a repeating match of ${this.name}.`, this.mark, this);
|
|
854
|
-
this.cursor.throwError(parseError);
|
|
855
|
-
}
|
|
856
|
-
this.node = null;
|
|
857
|
-
}
|
|
858
|
-
else {
|
|
859
|
-
const value = this.nodes.map((node) => node.value).join("");
|
|
860
|
-
this.node = new Node("repeat", this.name, this.nodes[0].startIndex, this.nodes[this.nodes.length - 1].endIndex, this.nodes, value);
|
|
861
|
-
this.cursor.index = this.node.endIndex;
|
|
862
|
-
this.cursor.addMatch(this, this.node);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
safelyGetCursor() {
|
|
866
|
-
const cursor = this.cursor;
|
|
867
|
-
if (cursor == null) {
|
|
868
|
-
throw new Error("Couldn't find cursor.");
|
|
869
|
-
}
|
|
870
|
-
return cursor;
|
|
871
|
-
}
|
|
872
|
-
clone(name, isOptional) {
|
|
873
|
-
if (name == null) {
|
|
874
|
-
name = this.name;
|
|
875
|
-
}
|
|
876
|
-
if (isOptional == null) {
|
|
877
|
-
isOptional = this._isOptional;
|
|
878
|
-
}
|
|
879
|
-
return new Repeat(name, this._pattern, this._divider, isOptional);
|
|
880
|
-
}
|
|
881
|
-
getTokens() {
|
|
882
|
-
return this._pattern.getTokens();
|
|
883
|
-
}
|
|
807
|
+
class Not {
|
|
808
|
+
get type() {
|
|
809
|
+
return this._type;
|
|
810
|
+
}
|
|
811
|
+
get name() {
|
|
812
|
+
return this._name;
|
|
813
|
+
}
|
|
814
|
+
get isOptional() {
|
|
815
|
+
return false;
|
|
816
|
+
}
|
|
817
|
+
get parent() {
|
|
818
|
+
return this._parent;
|
|
819
|
+
}
|
|
820
|
+
set parent(pattern) {
|
|
821
|
+
this._parent = pattern;
|
|
822
|
+
}
|
|
823
|
+
get children() {
|
|
824
|
+
return this._children;
|
|
825
|
+
}
|
|
826
|
+
constructor(name, pattern) {
|
|
827
|
+
this._type = "not";
|
|
828
|
+
this._name = name;
|
|
829
|
+
this._parent = null;
|
|
830
|
+
this._children = [pattern.clone(pattern.name, false)];
|
|
831
|
+
this._children[0].parent = this;
|
|
832
|
+
}
|
|
833
|
+
parseText(text) {
|
|
834
|
+
const cursor = new Cursor(text);
|
|
835
|
+
const ast = this.parse(cursor);
|
|
836
|
+
return {
|
|
837
|
+
ast,
|
|
838
|
+
cursor
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
parse(cursor) {
|
|
842
|
+
const firstIndex = cursor.index;
|
|
843
|
+
this._children[0].parse(cursor);
|
|
844
|
+
if (cursor.hasError) {
|
|
845
|
+
cursor.resolveError();
|
|
846
|
+
cursor.moveTo(firstIndex);
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
cursor.moveTo(firstIndex);
|
|
850
|
+
cursor.resolveError();
|
|
851
|
+
cursor.recordErrorAt(firstIndex, this);
|
|
852
|
+
}
|
|
853
|
+
return null;
|
|
854
|
+
}
|
|
855
|
+
clone(name = this._name) {
|
|
856
|
+
const not = new Not(name, this._children[0]);
|
|
857
|
+
return not;
|
|
858
|
+
}
|
|
859
|
+
getNextPattern() {
|
|
860
|
+
return getNextPattern(this);
|
|
861
|
+
}
|
|
862
|
+
getTokens() {
|
|
863
|
+
return [];
|
|
864
|
+
}
|
|
865
|
+
getNextTokens(_lastMatched) {
|
|
866
|
+
return [];
|
|
867
|
+
}
|
|
868
|
+
findPattern(isMatch) {
|
|
869
|
+
return isMatch(this._children[0]) ? this._children[0] : null;
|
|
870
|
+
}
|
|
884
871
|
}
|
|
885
872
|
|
|
886
|
-
class
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
const
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
if (
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
return
|
|
947
|
-
}
|
|
873
|
+
class Or {
|
|
874
|
+
get type() {
|
|
875
|
+
return this._type;
|
|
876
|
+
}
|
|
877
|
+
get name() {
|
|
878
|
+
return this._name;
|
|
879
|
+
}
|
|
880
|
+
get parent() {
|
|
881
|
+
return this._parent;
|
|
882
|
+
}
|
|
883
|
+
set parent(pattern) {
|
|
884
|
+
this._parent = pattern;
|
|
885
|
+
}
|
|
886
|
+
get children() {
|
|
887
|
+
return this._children;
|
|
888
|
+
}
|
|
889
|
+
get isOptional() {
|
|
890
|
+
return this._isOptional;
|
|
891
|
+
}
|
|
892
|
+
constructor(name, options, isOptional = false) {
|
|
893
|
+
if (options.length === 0) {
|
|
894
|
+
throw new Error("Need at least one pattern with an 'or' pattern.");
|
|
895
|
+
}
|
|
896
|
+
const children = clonePatterns(options, false);
|
|
897
|
+
this._assignChildrenToParent(children);
|
|
898
|
+
this._type = "or";
|
|
899
|
+
this._name = name;
|
|
900
|
+
this._parent = null;
|
|
901
|
+
this._children = children;
|
|
902
|
+
this._isOptional = isOptional;
|
|
903
|
+
this._node = null;
|
|
904
|
+
this._firstIndex = 0;
|
|
905
|
+
}
|
|
906
|
+
_assignChildrenToParent(children) {
|
|
907
|
+
for (const child of children) {
|
|
908
|
+
child.parent = this;
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
parseText(text) {
|
|
912
|
+
const cursor = new Cursor(text);
|
|
913
|
+
const ast = this.parse(cursor);
|
|
914
|
+
return {
|
|
915
|
+
ast,
|
|
916
|
+
cursor
|
|
917
|
+
};
|
|
918
|
+
}
|
|
919
|
+
parse(cursor) {
|
|
920
|
+
this._firstIndex = cursor.index;
|
|
921
|
+
this._node = null;
|
|
922
|
+
const node = this._tryToParse(cursor);
|
|
923
|
+
if (node != null) {
|
|
924
|
+
cursor.resolveError();
|
|
925
|
+
return node;
|
|
926
|
+
}
|
|
927
|
+
if (!this._isOptional) {
|
|
928
|
+
cursor.recordErrorAt(this._firstIndex, this);
|
|
929
|
+
return null;
|
|
930
|
+
}
|
|
931
|
+
cursor.resolveError();
|
|
932
|
+
cursor.moveTo(this._firstIndex);
|
|
933
|
+
return null;
|
|
934
|
+
}
|
|
935
|
+
_tryToParse(cursor) {
|
|
936
|
+
for (const pattern of this._children) {
|
|
937
|
+
cursor.moveTo(this._firstIndex);
|
|
938
|
+
const result = pattern.parse(cursor);
|
|
939
|
+
if (!cursor.hasError) {
|
|
940
|
+
return result;
|
|
941
|
+
}
|
|
942
|
+
cursor.resolveError();
|
|
943
|
+
}
|
|
944
|
+
return null;
|
|
945
|
+
}
|
|
946
|
+
getTokens() {
|
|
947
|
+
const tokens = [];
|
|
948
|
+
for (const child of this._children) {
|
|
949
|
+
tokens.push(...child.getTokens());
|
|
950
|
+
}
|
|
951
|
+
return tokens;
|
|
952
|
+
}
|
|
953
|
+
getNextTokens(_lastMatched) {
|
|
954
|
+
if (this._parent === null) {
|
|
955
|
+
return [];
|
|
956
|
+
}
|
|
957
|
+
return this._parent.getNextTokens(this);
|
|
958
|
+
}
|
|
959
|
+
getNextPattern() {
|
|
960
|
+
return getNextPattern(this);
|
|
961
|
+
}
|
|
962
|
+
findPattern(isMatch) {
|
|
963
|
+
return findPattern(this, isMatch);
|
|
964
|
+
}
|
|
965
|
+
clone(name = this._name, isOptional = this._isOptional) {
|
|
966
|
+
const or = new Or(name, this._children, isOptional);
|
|
967
|
+
return or;
|
|
968
|
+
}
|
|
948
969
|
}
|
|
949
970
|
|
|
950
|
-
class
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
971
|
+
class Repeat {
|
|
972
|
+
get type() {
|
|
973
|
+
return this._type;
|
|
974
|
+
}
|
|
975
|
+
get name() {
|
|
976
|
+
return this._name;
|
|
977
|
+
}
|
|
978
|
+
get parent() {
|
|
979
|
+
return this._parent;
|
|
980
|
+
}
|
|
981
|
+
set parent(pattern) {
|
|
982
|
+
this._parent = pattern;
|
|
983
|
+
}
|
|
984
|
+
get children() {
|
|
985
|
+
return this._children;
|
|
986
|
+
}
|
|
987
|
+
get isOptional() {
|
|
988
|
+
return this._isOptional;
|
|
989
|
+
}
|
|
990
|
+
constructor(name, pattern, divider, isOptional = false) {
|
|
991
|
+
const patterns = divider != null ? [pattern, divider] : [pattern];
|
|
992
|
+
const children = clonePatterns(patterns, false);
|
|
993
|
+
this._assignChildrenToParent(children);
|
|
994
|
+
this._type = "repeat";
|
|
995
|
+
this._name = name;
|
|
996
|
+
this._isOptional = isOptional;
|
|
997
|
+
this._parent = null;
|
|
998
|
+
this._children = children;
|
|
999
|
+
this._pattern = children[0];
|
|
1000
|
+
this._divider = children[1];
|
|
1001
|
+
this._firstIndex = -1;
|
|
1002
|
+
this._shouldReduceAst = false;
|
|
1003
|
+
this._nodes = [];
|
|
1004
|
+
}
|
|
1005
|
+
_assignChildrenToParent(children) {
|
|
1006
|
+
for (const child of children) {
|
|
1007
|
+
child.parent = this;
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
parseText(text) {
|
|
1011
|
+
const cursor = new Cursor(text);
|
|
1012
|
+
const ast = this.parse(cursor);
|
|
1013
|
+
return {
|
|
1014
|
+
ast,
|
|
1015
|
+
cursor
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
1018
|
+
parse(cursor) {
|
|
1019
|
+
this._firstIndex = cursor.index;
|
|
1020
|
+
this._nodes = [];
|
|
1021
|
+
const passed = this.tryToParse(cursor);
|
|
1022
|
+
if (passed) {
|
|
1023
|
+
cursor.resolveError();
|
|
1024
|
+
const node = this.createNode(cursor);
|
|
1025
|
+
if (node) {
|
|
1026
|
+
cursor.recordMatch(this, node);
|
|
1027
|
+
}
|
|
1028
|
+
return node;
|
|
1029
|
+
}
|
|
1030
|
+
if (!this._isOptional) {
|
|
1031
|
+
return null;
|
|
1032
|
+
}
|
|
1033
|
+
cursor.resolveError();
|
|
1034
|
+
cursor.moveTo(this._firstIndex);
|
|
1035
|
+
return null;
|
|
1036
|
+
}
|
|
1037
|
+
tryToParse(cursor) {
|
|
1038
|
+
let passed = false;
|
|
1039
|
+
while (true) {
|
|
1040
|
+
const runningCursorIndex = cursor.index;
|
|
1041
|
+
const repeatedNode = this._pattern.parse(cursor);
|
|
1042
|
+
if (cursor.hasError) {
|
|
1043
|
+
const lastValidNode = this.getLastValidNode();
|
|
1044
|
+
if (lastValidNode) {
|
|
1045
|
+
passed = true;
|
|
1046
|
+
}
|
|
1047
|
+
else {
|
|
1048
|
+
cursor.moveTo(runningCursorIndex);
|
|
1049
|
+
cursor.recordErrorAt(runningCursorIndex, this._pattern);
|
|
1050
|
+
passed = false;
|
|
1051
|
+
}
|
|
1052
|
+
break;
|
|
1053
|
+
}
|
|
1054
|
+
else if (repeatedNode) {
|
|
1055
|
+
this._nodes.push(repeatedNode);
|
|
1056
|
+
if (!cursor.hasNext()) {
|
|
1057
|
+
passed = true;
|
|
1058
|
+
break;
|
|
1059
|
+
}
|
|
1060
|
+
cursor.next();
|
|
1061
|
+
if (this._divider) {
|
|
1062
|
+
const dividerNode = this._divider.parse(cursor);
|
|
1063
|
+
if (cursor.hasError) {
|
|
1064
|
+
passed = true;
|
|
1065
|
+
break;
|
|
1066
|
+
}
|
|
1067
|
+
else if (dividerNode) {
|
|
1068
|
+
this._nodes.push(dividerNode);
|
|
1069
|
+
if (!cursor.hasNext()) {
|
|
1070
|
+
passed = true;
|
|
1071
|
+
break;
|
|
1072
|
+
}
|
|
1073
|
+
cursor.next();
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
return passed;
|
|
1079
|
+
}
|
|
1080
|
+
createNode(cursor) {
|
|
1081
|
+
let children = [];
|
|
1082
|
+
if (!this._divider) {
|
|
1083
|
+
children = this._nodes;
|
|
1084
|
+
}
|
|
1085
|
+
else {
|
|
1086
|
+
if (this._nodes.length % 2 !== 1) {
|
|
1087
|
+
const dividerNode = this._nodes[this._nodes.length - 1];
|
|
1088
|
+
cursor.moveTo(dividerNode.firstIndex);
|
|
1089
|
+
children = this._nodes.slice(0, this._nodes.length - 1);
|
|
1090
|
+
}
|
|
1091
|
+
else {
|
|
1092
|
+
children = this._nodes;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
const lastIndex = children[children.length - 1].lastIndex;
|
|
1096
|
+
const value = cursor.getChars(this._firstIndex, lastIndex);
|
|
1097
|
+
cursor.moveTo(lastIndex);
|
|
1098
|
+
if (this._shouldReduceAst) {
|
|
1099
|
+
children = [];
|
|
1100
|
+
}
|
|
1101
|
+
return new Node("repeat", this._name, this._firstIndex, lastIndex, children, this._shouldReduceAst ? value : undefined);
|
|
1102
|
+
}
|
|
1103
|
+
getLastValidNode() {
|
|
1104
|
+
const nodes = this._nodes.filter((node) => node !== null);
|
|
1105
|
+
if (nodes.length === 0) {
|
|
1106
|
+
return null;
|
|
1107
|
+
}
|
|
1108
|
+
return nodes[nodes.length - 1];
|
|
1109
|
+
}
|
|
1110
|
+
enableAstReduction() {
|
|
1111
|
+
this._shouldReduceAst = true;
|
|
1112
|
+
}
|
|
1113
|
+
disableAstReduction() {
|
|
1114
|
+
this._shouldReduceAst = false;
|
|
1115
|
+
}
|
|
1116
|
+
getTokens() {
|
|
1117
|
+
return this._pattern.getTokens();
|
|
1118
|
+
}
|
|
1119
|
+
getNextTokens(lastMatched) {
|
|
1120
|
+
let index = -1;
|
|
1121
|
+
const tokens = [];
|
|
1122
|
+
for (let i = 0; i < this._children.length; i++) {
|
|
1123
|
+
if (this._children[i] === lastMatched) {
|
|
1124
|
+
index = i;
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
if (index === -1) {
|
|
1128
|
+
return [];
|
|
1129
|
+
}
|
|
1130
|
+
if (index === 0 && this._divider) {
|
|
1131
|
+
tokens.push(...this._children[1].getTokens());
|
|
1132
|
+
if (this._parent) {
|
|
1133
|
+
tokens.push(...this._parent.getNextTokens(this));
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
if (index === 1) {
|
|
1137
|
+
tokens.push(...this._children[0].getTokens());
|
|
1138
|
+
}
|
|
1139
|
+
if (index === 0 && !this._divider && this._parent) {
|
|
1140
|
+
tokens.push(...this._children[0].getTokens());
|
|
1141
|
+
tokens.push(...this._parent.getNextTokens(this));
|
|
1142
|
+
}
|
|
1143
|
+
return tokens;
|
|
1144
|
+
}
|
|
1145
|
+
getNextPattern() {
|
|
1146
|
+
return getNextPattern(this);
|
|
1147
|
+
}
|
|
1148
|
+
findPattern(isMatch) {
|
|
1149
|
+
return findPattern(this, isMatch);
|
|
1150
|
+
}
|
|
1151
|
+
clone(name = this._name, isOptional = this._isOptional) {
|
|
1152
|
+
const repeat = new Repeat(name, this._pattern, this._divider, isOptional);
|
|
1153
|
+
repeat._shouldReduceAst = this._shouldReduceAst;
|
|
1154
|
+
return repeat;
|
|
1155
|
+
}
|
|
1039
1156
|
}
|
|
1040
1157
|
|
|
1041
|
-
class
|
|
1042
|
-
|
|
1043
|
-
this.
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
return this;
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
this.
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
if (this.selectedNodes.includes(node)) {
|
|
1130
|
-
const parent = stack[stack.length - 1];
|
|
1131
|
-
if (parent != null) {
|
|
1132
|
-
const index = parent.children.indexOf(node);
|
|
1133
|
-
if (index > -1) {
|
|
1134
|
-
parent.children.splice(index + 1, 0, callback(node));
|
|
1135
|
-
}
|
|
1136
|
-
}
|
|
1137
|
-
}
|
|
1138
|
-
});
|
|
1139
|
-
return this;
|
|
1140
|
-
}
|
|
1141
|
-
transform(callback) {
|
|
1142
|
-
this.selectedNodes.forEach((node) => {
|
|
1143
|
-
return this.recursiveTransform(node, callback);
|
|
1144
|
-
});
|
|
1145
|
-
return this;
|
|
1146
|
-
}
|
|
1147
|
-
recursiveTransform(node, callback) {
|
|
1148
|
-
const length = node.children.length;
|
|
1149
|
-
for (let x = 0; x < length; x++) {
|
|
1150
|
-
node.children[x] = this.recursiveTransform(node.children[x], callback);
|
|
1151
|
-
}
|
|
1152
|
-
return callback(node);
|
|
1153
|
-
}
|
|
1154
|
-
selectAll() {
|
|
1155
|
-
return this.select((n) => true);
|
|
1156
|
-
}
|
|
1157
|
-
selectNode(node) {
|
|
1158
|
-
return new Visitor(this.root, [...this.selectedNodes, node]);
|
|
1159
|
-
}
|
|
1160
|
-
deselectNode(node) {
|
|
1161
|
-
const visitor = new Visitor(this.root, this.selectedNodes.slice());
|
|
1162
|
-
return visitor.filter((n) => n !== node);
|
|
1163
|
-
}
|
|
1164
|
-
select(callback) {
|
|
1165
|
-
if (this.root == null) {
|
|
1166
|
-
return this;
|
|
1167
|
-
}
|
|
1168
|
-
const node = this.root;
|
|
1169
|
-
const selectedNodes = [];
|
|
1170
|
-
if (node.children.length > 0) {
|
|
1171
|
-
Visitor.walkDown(node, (descendant) => {
|
|
1172
|
-
if (callback(descendant)) {
|
|
1173
|
-
selectedNodes.push(descendant);
|
|
1174
|
-
}
|
|
1175
|
-
});
|
|
1176
|
-
}
|
|
1177
|
-
return new Visitor(this.root, selectedNodes);
|
|
1178
|
-
}
|
|
1179
|
-
forEach(callback) {
|
|
1180
|
-
this.selectedNodes.forEach(callback);
|
|
1181
|
-
return this;
|
|
1182
|
-
}
|
|
1183
|
-
filter(callback) {
|
|
1184
|
-
return new Visitor(this.root, this.selectedNodes.filter(callback));
|
|
1185
|
-
}
|
|
1186
|
-
map(callback) {
|
|
1187
|
-
return new Visitor(this.root, this.selectedNodes.map(callback));
|
|
1188
|
-
}
|
|
1189
|
-
selectRoot() {
|
|
1190
|
-
if (this.root == null) {
|
|
1191
|
-
return this;
|
|
1192
|
-
}
|
|
1193
|
-
return new Visitor(this.root, [this.root]);
|
|
1194
|
-
}
|
|
1195
|
-
first() {
|
|
1196
|
-
return this.get(0);
|
|
1197
|
-
}
|
|
1198
|
-
last() {
|
|
1199
|
-
return this.get(this.selectedNodes.length - 1);
|
|
1200
|
-
}
|
|
1201
|
-
get(index) {
|
|
1202
|
-
const node = this.selectedNodes[index];
|
|
1203
|
-
if (node == null) {
|
|
1204
|
-
throw new Error(`Couldn't find node at index: ${index}, out of ${this.selectedNodes.length}.`);
|
|
1205
|
-
}
|
|
1206
|
-
return new Visitor(node, []);
|
|
1207
|
-
}
|
|
1208
|
-
clear() {
|
|
1209
|
-
this.selectedNodes = [];
|
|
1210
|
-
return this;
|
|
1211
|
-
}
|
|
1212
|
-
setRoot(root) {
|
|
1213
|
-
this.root = root;
|
|
1214
|
-
return this;
|
|
1215
|
-
}
|
|
1216
|
-
static select(root, callback) {
|
|
1217
|
-
if (callback != null) {
|
|
1218
|
-
return new Visitor(root).select(callback);
|
|
1219
|
-
}
|
|
1220
|
-
else {
|
|
1221
|
-
return new Visitor(root);
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
static walkUp(node, callback, ancestors = []) {
|
|
1225
|
-
ancestors.push(node);
|
|
1226
|
-
if (node.children.length > 0) {
|
|
1227
|
-
const children = node.children.slice();
|
|
1228
|
-
children.forEach((c) => this.walkUp(c, callback, ancestors));
|
|
1229
|
-
}
|
|
1230
|
-
ancestors.pop();
|
|
1231
|
-
callback(node, ancestors);
|
|
1232
|
-
return this;
|
|
1233
|
-
}
|
|
1234
|
-
static walkDown(node, callback, ancestors = []) {
|
|
1235
|
-
callback(node, ancestors);
|
|
1236
|
-
ancestors.push(node);
|
|
1237
|
-
if (node.children.length > 0) {
|
|
1238
|
-
const children = node.children.slice();
|
|
1239
|
-
children.forEach((c) => this.walkDown(c, callback, ancestors));
|
|
1240
|
-
}
|
|
1241
|
-
ancestors.pop();
|
|
1242
|
-
return this;
|
|
1243
|
-
}
|
|
1158
|
+
class Reference {
|
|
1159
|
+
get type() {
|
|
1160
|
+
return this._type;
|
|
1161
|
+
}
|
|
1162
|
+
get name() {
|
|
1163
|
+
return this._name;
|
|
1164
|
+
}
|
|
1165
|
+
get isOptional() {
|
|
1166
|
+
return this._isOptional;
|
|
1167
|
+
}
|
|
1168
|
+
get parent() {
|
|
1169
|
+
return this._parent;
|
|
1170
|
+
}
|
|
1171
|
+
set parent(pattern) {
|
|
1172
|
+
this._parent = pattern;
|
|
1173
|
+
}
|
|
1174
|
+
get children() {
|
|
1175
|
+
return this._children;
|
|
1176
|
+
}
|
|
1177
|
+
constructor(name, isOptional = false) {
|
|
1178
|
+
this._type = "reference";
|
|
1179
|
+
this._name = name;
|
|
1180
|
+
this._parent = null;
|
|
1181
|
+
this._isOptional = isOptional;
|
|
1182
|
+
this._pattern = null;
|
|
1183
|
+
this._children = [];
|
|
1184
|
+
}
|
|
1185
|
+
parseText(text) {
|
|
1186
|
+
const cursor = new Cursor(text);
|
|
1187
|
+
const ast = this.parse(cursor);
|
|
1188
|
+
return {
|
|
1189
|
+
ast,
|
|
1190
|
+
cursor
|
|
1191
|
+
};
|
|
1192
|
+
}
|
|
1193
|
+
parse(cursor) {
|
|
1194
|
+
return this._getPatternSafely().parse(cursor);
|
|
1195
|
+
}
|
|
1196
|
+
clone(name = this._name, isOptional = this._isOptional) {
|
|
1197
|
+
return new Reference(name, isOptional);
|
|
1198
|
+
}
|
|
1199
|
+
getTokens() {
|
|
1200
|
+
return this._getPatternSafely().getTokens();
|
|
1201
|
+
}
|
|
1202
|
+
getNextTokens(_lastMatched) {
|
|
1203
|
+
if (this.parent == null) {
|
|
1204
|
+
return [];
|
|
1205
|
+
}
|
|
1206
|
+
return this.parent.getNextTokens(this);
|
|
1207
|
+
}
|
|
1208
|
+
getNextPattern() {
|
|
1209
|
+
return getNextPattern(this);
|
|
1210
|
+
}
|
|
1211
|
+
findPattern(_isMatch) {
|
|
1212
|
+
return null;
|
|
1213
|
+
}
|
|
1214
|
+
_getPatternSafely() {
|
|
1215
|
+
if (this._pattern === null) {
|
|
1216
|
+
const pattern = this._findPattern();
|
|
1217
|
+
if (pattern === null) {
|
|
1218
|
+
throw new Error(`Couldn't find '${this._name}' pattern within tree.`);
|
|
1219
|
+
}
|
|
1220
|
+
const clonedPattern = pattern.clone(this._name, this._isOptional);
|
|
1221
|
+
clonedPattern.parent = this;
|
|
1222
|
+
this._pattern = clonedPattern;
|
|
1223
|
+
this._children = [this._pattern];
|
|
1224
|
+
}
|
|
1225
|
+
return this._pattern;
|
|
1226
|
+
}
|
|
1227
|
+
_findPattern() {
|
|
1228
|
+
const root = this._getRoot();
|
|
1229
|
+
return findPattern(root, (pattern) => {
|
|
1230
|
+
return pattern.name === this._name && pattern.type !== "reference";
|
|
1231
|
+
});
|
|
1232
|
+
}
|
|
1233
|
+
_getRoot() {
|
|
1234
|
+
let node = this;
|
|
1235
|
+
while (true) {
|
|
1236
|
+
const parent = node.parent;
|
|
1237
|
+
if (parent == null) {
|
|
1238
|
+
break;
|
|
1239
|
+
}
|
|
1240
|
+
else {
|
|
1241
|
+
node = parent;
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
return node;
|
|
1245
|
+
}
|
|
1244
1246
|
}
|
|
1245
1247
|
|
|
1246
|
-
|
|
1247
|
-
constructor() {
|
|
1248
|
-
this.cursor = null;
|
|
1249
|
-
this.result = null;
|
|
1250
|
-
this.text = "";
|
|
1251
|
-
this.match = null;
|
|
1252
|
-
this.error = null;
|
|
1253
|
-
this.patternMatch = null;
|
|
1254
|
-
this.matchedText = "";
|
|
1255
|
-
this.rootPattern = null;
|
|
1256
|
-
this.tokens = {
|
|
1257
|
-
startIndex: 0,
|
|
1258
|
-
values: [],
|
|
1259
|
-
};
|
|
1260
|
-
this.options = [];
|
|
1261
|
-
this.parseStack = [];
|
|
1262
|
-
}
|
|
1263
|
-
suggest(text, pattern) {
|
|
1264
|
-
var _a, _b, _c;
|
|
1265
|
-
this.reset();
|
|
1266
|
-
this.text = text;
|
|
1267
|
-
this.rootPattern = pattern;
|
|
1268
|
-
// If no text all options are available.
|
|
1269
|
-
if (text.length === 0) {
|
|
1270
|
-
return {
|
|
1271
|
-
pattern: null,
|
|
1272
|
-
astNode: null,
|
|
1273
|
-
match: null,
|
|
1274
|
-
error: null,
|
|
1275
|
-
options: {
|
|
1276
|
-
startIndex: 0,
|
|
1277
|
-
values: pattern.getTokens(),
|
|
1278
|
-
},
|
|
1279
|
-
isComplete: false,
|
|
1280
|
-
parseStack: [],
|
|
1281
|
-
};
|
|
1282
|
-
}
|
|
1283
|
-
this.parse();
|
|
1284
|
-
this.saveParseStack();
|
|
1285
|
-
this.saveMatchedText();
|
|
1286
|
-
this.saveMatch();
|
|
1287
|
-
this.saveError();
|
|
1288
|
-
this.saveOptions();
|
|
1289
|
-
this.saveNextToken();
|
|
1290
|
-
return {
|
|
1291
|
-
pattern: ((_a = this.patternMatch) === null || _a === void 0 ? void 0 : _a.pattern) || null,
|
|
1292
|
-
astNode: ((_b = this.patternMatch) === null || _b === void 0 ? void 0 : _b.astNode) || null,
|
|
1293
|
-
match: this.match,
|
|
1294
|
-
error: this.error,
|
|
1295
|
-
options: this.tokens,
|
|
1296
|
-
isComplete: ((_c = this.cursor) === null || _c === void 0 ? void 0 : _c.didSuccessfullyParse()) || false,
|
|
1297
|
-
parseStack: this.parseStack,
|
|
1298
|
-
};
|
|
1299
|
-
}
|
|
1300
|
-
reset() {
|
|
1301
|
-
this.cursor = null;
|
|
1302
|
-
this.result = null;
|
|
1303
|
-
this.text = "";
|
|
1304
|
-
this.match = null;
|
|
1305
|
-
this.error = null;
|
|
1306
|
-
this.patternMatch = null;
|
|
1307
|
-
this.matchedText = "";
|
|
1308
|
-
this.rootPattern = null;
|
|
1309
|
-
this.tokens = {
|
|
1310
|
-
startIndex: 0,
|
|
1311
|
-
values: [],
|
|
1312
|
-
};
|
|
1313
|
-
this.options = [];
|
|
1314
|
-
this.parseStack = [];
|
|
1315
|
-
}
|
|
1316
|
-
parse() {
|
|
1317
|
-
var _a;
|
|
1318
|
-
this.rootPattern = this.rootPattern;
|
|
1319
|
-
this.cursor = new Cursor(this.text || "");
|
|
1320
|
-
this.cursor.startRecording();
|
|
1321
|
-
this.result = ((_a = this.rootPattern) === null || _a === void 0 ? void 0 : _a.parse(this.cursor)) || null;
|
|
1322
|
-
this.patternMatch = this.cursor.lastMatch;
|
|
1323
|
-
}
|
|
1324
|
-
saveParseStack() {
|
|
1325
|
-
var _a;
|
|
1326
|
-
this.parseStack = ((_a = this.cursor) === null || _a === void 0 ? void 0 : _a.history.getLastParseStack()) || [];
|
|
1327
|
-
}
|
|
1328
|
-
saveMatchedText() {
|
|
1329
|
-
var _a, _b;
|
|
1330
|
-
if (((_a = this.patternMatch) === null || _a === void 0 ? void 0 : _a.astNode) != null) {
|
|
1331
|
-
this.matchedText =
|
|
1332
|
-
((_b = this.text) === null || _b === void 0 ? void 0 : _b.substring(0, this.patternMatch.astNode.endIndex + 1)) || "";
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
saveMatch() {
|
|
1336
|
-
var _a;
|
|
1337
|
-
const node = (_a = this.patternMatch) === null || _a === void 0 ? void 0 : _a.astNode;
|
|
1338
|
-
if (node == null) {
|
|
1339
|
-
this.match = null;
|
|
1340
|
-
return;
|
|
1341
|
-
}
|
|
1342
|
-
let endIndex = this.matchedText.length - 1;
|
|
1343
|
-
this.match = {
|
|
1344
|
-
text: this.matchedText,
|
|
1345
|
-
startIndex: 0,
|
|
1346
|
-
endIndex: endIndex,
|
|
1347
|
-
};
|
|
1348
|
-
}
|
|
1349
|
-
saveError() {
|
|
1350
|
-
var _a;
|
|
1351
|
-
if (((_a = this.patternMatch) === null || _a === void 0 ? void 0 : _a.astNode) == null) {
|
|
1352
|
-
this.error = {
|
|
1353
|
-
startIndex: 0,
|
|
1354
|
-
endIndex: this.text.length - 1,
|
|
1355
|
-
text: this.text,
|
|
1356
|
-
};
|
|
1357
|
-
return this;
|
|
1358
|
-
}
|
|
1359
|
-
if (this.patternMatch != null &&
|
|
1360
|
-
this.text.length > this.matchedText.length) {
|
|
1361
|
-
const difference = this.text.length - this.matchedText.length;
|
|
1362
|
-
const startIndex = this.patternMatch.astNode.endIndex + 1;
|
|
1363
|
-
const endIndex = startIndex + difference - 1;
|
|
1364
|
-
this.error = {
|
|
1365
|
-
startIndex: startIndex,
|
|
1366
|
-
endIndex: endIndex,
|
|
1367
|
-
text: this.text.substring(startIndex, endIndex + 1),
|
|
1368
|
-
};
|
|
1369
|
-
return;
|
|
1370
|
-
}
|
|
1371
|
-
else {
|
|
1372
|
-
this.error = null;
|
|
1373
|
-
return;
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
saveNextToken() {
|
|
1377
|
-
var _a, _b, _c, _d;
|
|
1378
|
-
const isCompleteMatch = ((_a = this.patternMatch) === null || _a === void 0 ? void 0 : _a.pattern) === this.rootPattern &&
|
|
1379
|
-
((_b = this.cursor) === null || _b === void 0 ? void 0 : _b.didSuccessfullyParse());
|
|
1380
|
-
const noMatch = ((_c = this.patternMatch) === null || _c === void 0 ? void 0 : _c.astNode) == null;
|
|
1381
|
-
const noOptions = this.options.length === 0;
|
|
1382
|
-
if (isCompleteMatch && noOptions) {
|
|
1383
|
-
this.tokens = null;
|
|
1384
|
-
return;
|
|
1385
|
-
}
|
|
1386
|
-
if (noMatch) {
|
|
1387
|
-
let options = (_d = this.rootPattern) === null || _d === void 0 ? void 0 : _d.getTokens();
|
|
1388
|
-
options = options === null || options === void 0 ? void 0 : options.filter((option) => {
|
|
1389
|
-
return option.indexOf(this.text) === 0;
|
|
1390
|
-
});
|
|
1391
|
-
if ((options === null || options === void 0 ? void 0 : options.length) === 0) {
|
|
1392
|
-
this.tokens = null;
|
|
1393
|
-
return;
|
|
1394
|
-
}
|
|
1395
|
-
const values = options === null || options === void 0 ? void 0 : options.map((option) => {
|
|
1396
|
-
const parts = option.split(this.text);
|
|
1397
|
-
return parts[1];
|
|
1398
|
-
});
|
|
1399
|
-
this.tokens = {
|
|
1400
|
-
startIndex: 0,
|
|
1401
|
-
values: values || [],
|
|
1402
|
-
};
|
|
1403
|
-
this.matchedText = this.text;
|
|
1404
|
-
this.match = {
|
|
1405
|
-
text: this.text,
|
|
1406
|
-
startIndex: 0,
|
|
1407
|
-
endIndex: this.text.length - 1,
|
|
1408
|
-
};
|
|
1409
|
-
this.error = null;
|
|
1410
|
-
return;
|
|
1411
|
-
}
|
|
1412
|
-
const options = this.options;
|
|
1413
|
-
let startIndex = this.matchedText.length;
|
|
1414
|
-
if (this.matchedText.length < this.text.length) {
|
|
1415
|
-
const leftOver = this.text.substring(this.matchedText.length);
|
|
1416
|
-
const partialMatchOptions = options
|
|
1417
|
-
.filter((option) => {
|
|
1418
|
-
return option.indexOf(leftOver) === 0;
|
|
1419
|
-
})
|
|
1420
|
-
.map((option) => {
|
|
1421
|
-
return option.substring(leftOver.length);
|
|
1422
|
-
});
|
|
1423
|
-
if (partialMatchOptions.length === 0) {
|
|
1424
|
-
this.tokens = null;
|
|
1425
|
-
return;
|
|
1426
|
-
}
|
|
1427
|
-
else {
|
|
1428
|
-
if (this.match == null) {
|
|
1429
|
-
return;
|
|
1430
|
-
}
|
|
1431
|
-
this.match = {
|
|
1432
|
-
text: this.match.text + leftOver,
|
|
1433
|
-
startIndex: this.match.startIndex,
|
|
1434
|
-
endIndex: this.match.endIndex + leftOver.length,
|
|
1435
|
-
};
|
|
1436
|
-
this.error = null;
|
|
1437
|
-
this.tokens = {
|
|
1438
|
-
startIndex: this.match.endIndex + 1,
|
|
1439
|
-
values: partialMatchOptions,
|
|
1440
|
-
};
|
|
1441
|
-
return;
|
|
1442
|
-
}
|
|
1443
|
-
}
|
|
1444
|
-
this.tokens = {
|
|
1445
|
-
startIndex,
|
|
1446
|
-
values: options,
|
|
1447
|
-
};
|
|
1448
|
-
}
|
|
1449
|
-
saveOptions() {
|
|
1450
|
-
const parents = new Map();
|
|
1451
|
-
const cursor = this.cursor;
|
|
1452
|
-
if (cursor == null) {
|
|
1453
|
-
this.options = [];
|
|
1454
|
-
return;
|
|
1455
|
-
}
|
|
1456
|
-
const furthestMatches = cursor.history.astNodes.reduce((acc, node, index) => {
|
|
1457
|
-
const pattern = cursor.history.patterns[index];
|
|
1458
|
-
const parent = pattern.parent;
|
|
1459
|
-
if (parent != null) {
|
|
1460
|
-
parents.set(parent, parent);
|
|
1461
|
-
}
|
|
1462
|
-
if (parents.has(pattern)) {
|
|
1463
|
-
return acc;
|
|
1464
|
-
}
|
|
1465
|
-
if (node.endIndex === acc.furthestTextIndex) {
|
|
1466
|
-
acc.nodeIndexes.push(index);
|
|
1467
|
-
}
|
|
1468
|
-
else if (node.endIndex > acc.furthestTextIndex) {
|
|
1469
|
-
acc.furthestTextIndex = node.endIndex;
|
|
1470
|
-
acc.nodeIndexes = [index];
|
|
1471
|
-
}
|
|
1472
|
-
return acc;
|
|
1473
|
-
}, { furthestTextIndex: -1, nodeIndexes: [] });
|
|
1474
|
-
const matches = furthestMatches.nodeIndexes.reduce((acc, index) => {
|
|
1475
|
-
var _a;
|
|
1476
|
-
const pattern = (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.history.patterns[index];
|
|
1477
|
-
const tokens = pattern === null || pattern === void 0 ? void 0 : pattern.getNextTokens();
|
|
1478
|
-
tokens === null || tokens === void 0 ? void 0 : tokens.forEach((token) => {
|
|
1479
|
-
acc[token] = true;
|
|
1480
|
-
});
|
|
1481
|
-
return acc;
|
|
1482
|
-
}, {});
|
|
1483
|
-
this.options = Object.keys(matches);
|
|
1484
|
-
}
|
|
1485
|
-
static suggest(text, pattern) {
|
|
1486
|
-
return new TextSuggester().suggest(text, pattern);
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
|
-
|
|
1490
|
-
export { And, Cursor, Literal, LookAhead, Node, Not, Or, ParseError, Pattern, Recursive, Reference, Regex, Repeat, TextSuggester, Visitor };
|
|
1248
|
+
export { And, Cursor, Literal, Node, Not, Or, ParseError, Reference, Regex, Repeat };
|
|
1491
1249
|
//# sourceMappingURL=index.esm.js.map
|