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