clarity-pattern-parser 8.4.14 → 9.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/TODO.md +4 -1
- package/dist/grammar/Grammar.d.ts +18 -10
- package/dist/grammar/patterns/andLiteral.d.ts +2 -0
- package/dist/grammar/patterns/anonymousPattern.d.ts +2 -0
- package/dist/grammar/patterns/inlinePattern.d.ts +1 -0
- package/dist/grammar/patterns/literals.d.ts +3 -0
- package/dist/grammar/patterns/pattern.d.ts +2 -2
- package/dist/grammar/patterns.d.ts +2 -0
- package/dist/index.browser.js +472 -185
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.esm.js +471 -186
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +472 -185
- package/dist/index.js.map +1 -1
- package/dist/patterns/And.d.ts +4 -1
- package/dist/patterns/Cursor.d.ts +5 -0
- package/dist/patterns/CursorHistory.d.ts +7 -0
- package/dist/patterns/FiniteRepeat.d.ts +4 -1
- package/dist/patterns/InfiniteRepeat.d.ts +5 -4
- package/dist/patterns/Literal.d.ts +6 -5
- package/dist/patterns/Not.d.ts +5 -4
- package/dist/patterns/Or.d.ts +5 -4
- package/dist/patterns/Pattern.d.ts +4 -2
- package/dist/patterns/Reference.d.ts +5 -4
- package/dist/patterns/Regex.d.ts +5 -4
- package/dist/patterns/Repeat.d.ts +3 -0
- package/dist/patterns/arePatternsEqual.d.ts +2 -0
- package/package.json +1 -1
- package/src/grammar/Grammar.test.ts +126 -72
- package/src/grammar/Grammar.ts +241 -158
- package/src/grammar/patterns/anonymousPattern.ts +23 -0
- package/src/grammar/patterns/body.ts +9 -6
- package/src/grammar/patterns/comment.ts +3 -2
- package/src/grammar/patterns/grammar.ts +15 -12
- package/src/grammar/patterns/import.ts +18 -12
- package/src/grammar/patterns/literal.ts +2 -3
- package/src/grammar/patterns/literals.ts +20 -0
- package/src/grammar/patterns/optionsLiteral.ts +19 -0
- package/src/grammar/patterns/pattern.ts +23 -9
- package/src/grammar/patterns/regexLiteral.ts +1 -0
- package/src/grammar/patterns/repeatLiteral.ts +30 -25
- package/src/grammar/patterns/sequenceLiteral.ts +24 -0
- package/src/grammar/patterns/spaces.ts +8 -6
- package/src/grammar/patterns/statement.ts +8 -20
- package/src/grammar/patterns.test.ts +38 -0
- package/src/grammar/patterns.ts +24 -0
- package/src/grammar/spec.md +4 -12
- package/src/index.ts +11 -5
- package/src/intellisense/AutoComplete.test.ts +41 -40
- package/src/intellisense/css/method.ts +2 -2
- package/src/intellisense/css/unit.ts +2 -2
- package/src/intellisense/css/value.ts +1 -1
- package/src/intellisense/javascript/Javascript.test.ts +31 -32
- package/src/intellisense/javascript/arrayLiteral.ts +7 -6
- package/src/intellisense/javascript/assignment.ts +6 -6
- package/src/intellisense/javascript/deleteStatement.ts +2 -2
- package/src/intellisense/javascript/escapedCharacter.ts +6 -6
- package/src/intellisense/javascript/exponent.ts +6 -6
- package/src/intellisense/javascript/expression.ts +18 -17
- package/src/intellisense/javascript/fraction.ts +3 -3
- package/src/intellisense/javascript/infixOperator.ts +10 -10
- package/src/intellisense/javascript/integer.ts +1 -1
- package/src/intellisense/javascript/invocation.ts +8 -7
- package/src/intellisense/javascript/literal.ts +3 -3
- package/src/intellisense/javascript/numberLiteral.ts +5 -4
- package/src/intellisense/javascript/objectAccess.ts +2 -3
- package/src/intellisense/javascript/objectLiteral.ts +8 -7
- package/src/intellisense/javascript/optionalSpaces.ts +2 -1
- package/src/intellisense/javascript/parameters.ts +5 -5
- package/src/intellisense/javascript/prefixOperator.ts +3 -4
- package/src/intellisense/javascript/propertyAccess.ts +9 -8
- package/src/intellisense/javascript/stringLiteral.ts +14 -15
- package/src/patterns/Cursor.ts +42 -4
- package/src/patterns/CursorHistory.ts +20 -4
- package/src/patterns/FiniteRepeat.test.ts +52 -51
- package/src/patterns/FiniteRepeat.ts +60 -38
- package/src/patterns/InfiniteRepeat.test.ts +36 -49
- package/src/patterns/InfiniteRepeat.ts +70 -37
- package/src/patterns/Literal.test.ts +16 -27
- package/src/patterns/Literal.ts +34 -27
- package/src/patterns/Not.test.ts +7 -7
- package/src/patterns/Not.ts +24 -6
- package/src/patterns/Optional.test.ts +164 -0
- package/src/patterns/Optional.ts +143 -0
- package/src/patterns/{Or.test.ts → Options.test.ts} +51 -49
- package/src/patterns/{Or.ts → Options.ts} +32 -23
- package/src/patterns/Pattern.ts +6 -5
- package/src/patterns/Reference.test.ts +21 -22
- package/src/patterns/Reference.ts +26 -15
- package/src/patterns/Regex.test.ts +15 -15
- package/src/patterns/Regex.ts +29 -19
- package/src/patterns/Repeat.test.ts +12 -22
- package/src/patterns/Repeat.ts +22 -21
- package/src/patterns/{And.test.ts → Sequence.test.ts} +78 -78
- package/src/patterns/{And.ts → Sequence.ts} +40 -29
- package/src/patterns/arePatternsEqual.ts +12 -0
- package/src/patterns/clonePatterns.ts +2 -2
- package/src/grammar/patterns/andLiteral.ts +0 -8
- package/src/grammar/patterns/orLiteral.ts +0 -8
package/src/grammar/Grammar.ts
CHANGED
|
@@ -4,11 +4,24 @@ import { Pattern } from "../patterns/Pattern";
|
|
|
4
4
|
import { Regex } from "../patterns/Regex";
|
|
5
5
|
import { Reference } from "../patterns/Reference";
|
|
6
6
|
import { grammar } from "./patterns/grammar";
|
|
7
|
-
import {
|
|
7
|
+
import { Options } from "../patterns/Options";
|
|
8
8
|
import { Not } from "../patterns/Not";
|
|
9
|
-
import {
|
|
9
|
+
import { Sequence } from "../patterns/Sequence";
|
|
10
10
|
import { Repeat, RepeatOptions } from "../patterns/Repeat";
|
|
11
11
|
import { AutoComplete } from "../intellisense/AutoComplete";
|
|
12
|
+
import { Optional } from "../patterns/Optional";
|
|
13
|
+
|
|
14
|
+
let anonymousIndexId = 0;
|
|
15
|
+
|
|
16
|
+
const patternNodes: Record<string, boolean> = {
|
|
17
|
+
"literal": true,
|
|
18
|
+
"regex-literal": true,
|
|
19
|
+
"options-literal": true,
|
|
20
|
+
"sequence-literal": true,
|
|
21
|
+
"repeat-literal": true,
|
|
22
|
+
"alias-literal": true,
|
|
23
|
+
"configurable-anonymous-pattern": true
|
|
24
|
+
};
|
|
12
25
|
|
|
13
26
|
class ParseContext {
|
|
14
27
|
constructor(params: Pattern[]) {
|
|
@@ -75,7 +88,7 @@ export class Grammar {
|
|
|
75
88
|
await this._resolveImports(ast);
|
|
76
89
|
this._buildPatterns(ast);
|
|
77
90
|
|
|
78
|
-
return this._parseContext.patternsByName
|
|
91
|
+
return Object.fromEntries(this._parseContext.patternsByName) as Record<string, Pattern>;
|
|
79
92
|
}
|
|
80
93
|
|
|
81
94
|
parseString(expression: string) {
|
|
@@ -85,9 +98,8 @@ export class Grammar {
|
|
|
85
98
|
if (this._hasImports(ast)) {
|
|
86
99
|
throw new Error("Cannot use imports on parseString, use parse instead.");
|
|
87
100
|
}
|
|
88
|
-
|
|
89
101
|
this._buildPatterns(ast);
|
|
90
|
-
return this._parseContext.patternsByName
|
|
102
|
+
return Object.fromEntries(this._parseContext.patternsByName) as Record<string, Pattern>;
|
|
91
103
|
}
|
|
92
104
|
|
|
93
105
|
private _tryToParse(expression: string): Node {
|
|
@@ -101,7 +113,7 @@ export class Grammar {
|
|
|
101
113
|
const startText = text.slice(Math.max(o.startIndex - 10), o.startIndex);
|
|
102
114
|
return startText + o.text;
|
|
103
115
|
}).join("' or '") + "'";
|
|
104
|
-
const message = `[Parse Error] Found: '${foundText}', expected: ${expectedTexts}
|
|
116
|
+
const message = `[Parse Error] Found: '${foundText}', expected: ${expectedTexts}.`;
|
|
105
117
|
throw new Error(message);
|
|
106
118
|
}
|
|
107
119
|
|
|
@@ -125,38 +137,40 @@ export class Grammar {
|
|
|
125
137
|
return;
|
|
126
138
|
}
|
|
127
139
|
|
|
128
|
-
body.findAll(n => n.name === "assign-statement"
|
|
129
|
-
const
|
|
130
|
-
const type = n.name === "export-name" ? "export-name" : typeNode?.name || "unknown";
|
|
140
|
+
body.findAll(n => n.name === "assign-statement").forEach((n) => {
|
|
141
|
+
const patternNode = n.children.find(n => patternNodes[n.name] != null);
|
|
131
142
|
|
|
132
|
-
|
|
143
|
+
if (patternNode == null) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
switch (patternNode.name) {
|
|
133
148
|
case "literal": {
|
|
134
|
-
this.
|
|
149
|
+
this._saveLiteral(n);
|
|
135
150
|
break;
|
|
136
151
|
}
|
|
137
152
|
case "regex-literal": {
|
|
138
|
-
this.
|
|
153
|
+
this._saveRegex(n);
|
|
139
154
|
break;
|
|
140
155
|
}
|
|
141
|
-
case "
|
|
142
|
-
this.
|
|
156
|
+
case "options-literal": {
|
|
157
|
+
this._saveOptions(n);
|
|
143
158
|
break;
|
|
144
159
|
}
|
|
145
|
-
case "
|
|
146
|
-
this.
|
|
160
|
+
case "sequence-literal": {
|
|
161
|
+
this._saveSequence(n);
|
|
147
162
|
break;
|
|
148
163
|
}
|
|
149
164
|
case "repeat-literal": {
|
|
150
|
-
this.
|
|
165
|
+
this._saveRepeat(n);
|
|
151
166
|
break;
|
|
152
167
|
}
|
|
153
168
|
case "alias-literal": {
|
|
154
|
-
this.
|
|
169
|
+
this._saveAlias(n);
|
|
155
170
|
break;
|
|
156
171
|
}
|
|
157
|
-
case "
|
|
158
|
-
|
|
159
|
-
this._parseContext.patternsByName.set(n.value, pattern);
|
|
172
|
+
case "configurable-anonymous-pattern": {
|
|
173
|
+
this._saveConfigurableAnonymous(n);
|
|
160
174
|
break;
|
|
161
175
|
}
|
|
162
176
|
default: {
|
|
@@ -164,6 +178,205 @@ export class Grammar {
|
|
|
164
178
|
}
|
|
165
179
|
}
|
|
166
180
|
});
|
|
181
|
+
|
|
182
|
+
body.findAll(n => n.name === "export-name").forEach((n) => {
|
|
183
|
+
const pattern = this._getPattern(n.value).clone();
|
|
184
|
+
this._parseContext.patternsByName.set(n.value, pattern);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private _saveLiteral(statementNode: Node) {
|
|
189
|
+
const nameNode = statementNode.find(n => n.name === "name") as Node;
|
|
190
|
+
const literalNode = statementNode.find(n => n.name === "literal") as Node;
|
|
191
|
+
const name = nameNode.value;
|
|
192
|
+
const literal = this._buildLiteral(name, literalNode);
|
|
193
|
+
|
|
194
|
+
this._parseContext.patternsByName.set(name, literal);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
private _buildLiteral(name: string, node: Node) {
|
|
198
|
+
return new Literal(name, this._resolveStringValue(node.value));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
private _resolveStringValue(value: string) {
|
|
202
|
+
return value.replace(/\\n/g, '\n')
|
|
203
|
+
.replace(/\\r/g, '\r')
|
|
204
|
+
.replace(/\\t/g, '\t')
|
|
205
|
+
.replace(/\\b/g, '\b')
|
|
206
|
+
.replace(/\\f/g, '\f')
|
|
207
|
+
.replace(/\\v/g, '\v')
|
|
208
|
+
.replace(/\\0/g, '\0')
|
|
209
|
+
.replace(/\\x([0-9A-Fa-f]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
|
|
210
|
+
.replace(/\\u([0-9A-Fa-f]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
|
|
211
|
+
.replace(/\\(.)/g, '$1').slice(1, -1);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
private _saveRegex(statementNode: Node) {
|
|
215
|
+
const nameNode = statementNode.find(n => n.name === "name") as Node;
|
|
216
|
+
const regexNode = statementNode.find(n => n.name === "regex-literal") as Node;
|
|
217
|
+
const name = nameNode.value;
|
|
218
|
+
const regex = this._buildRegex(name, regexNode);
|
|
219
|
+
|
|
220
|
+
this._parseContext.patternsByName.set(name, regex);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
private _buildRegex(name: string, node: Node) {
|
|
224
|
+
const value = node.value.slice(1, node.value.length - 1);
|
|
225
|
+
return new Regex(name, value);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
private _saveOptions(statementNode: Node) {
|
|
229
|
+
const nameNode = statementNode.find(n => n.name === "name") as Node;
|
|
230
|
+
const name = nameNode.value;
|
|
231
|
+
const optionsNode = statementNode.find(n => n.name === "options-literal") as Node;
|
|
232
|
+
const options = this._buildOptions(name, optionsNode);
|
|
233
|
+
|
|
234
|
+
this._parseContext.patternsByName.set(name, options);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
private _buildOptions(name: string, node: Node) {
|
|
238
|
+
const patternNodes = node.children.filter(n => n.name !== "default-divider" && n.name !== "greedy-divider");
|
|
239
|
+
const isGreedy = node.find(n => n.name === "greedy-divider") != null;
|
|
240
|
+
const patterns = patternNodes.map(n => this._buildPattern(n));
|
|
241
|
+
const or = new Options(name, patterns, isGreedy);
|
|
242
|
+
|
|
243
|
+
return or;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
private _buildPattern(node: Node): Pattern {
|
|
247
|
+
const type = node.name;
|
|
248
|
+
const name = `anonymous-pattern-${anonymousIndexId++}`;
|
|
249
|
+
|
|
250
|
+
switch (type) {
|
|
251
|
+
case "pattern-name": {
|
|
252
|
+
return this._getPattern(node.value).clone();
|
|
253
|
+
}
|
|
254
|
+
case "literal": {
|
|
255
|
+
return this._buildLiteral(node.value.slice(1, -1), node);
|
|
256
|
+
}
|
|
257
|
+
case "regex-literal": {
|
|
258
|
+
return this._buildRegex(node.value.slice(1, -1), node);
|
|
259
|
+
}
|
|
260
|
+
case "repeat-literal": {
|
|
261
|
+
return this._buildRepeat(name, node);
|
|
262
|
+
}
|
|
263
|
+
case "options-literal": {
|
|
264
|
+
return this._buildOptions(name, node);
|
|
265
|
+
}
|
|
266
|
+
case "sequence-literal": {
|
|
267
|
+
return this._buildSequence(name, node);
|
|
268
|
+
}
|
|
269
|
+
case "complex-anonymous-pattern": {
|
|
270
|
+
return this._buildComplexAnonymousPattern(node);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
throw new Error(`Couldn't build node: ${node.name}.`);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
private _saveSequence(statementNode: Node) {
|
|
278
|
+
const nameNode = statementNode.find(n => n.name === "name") as Node;
|
|
279
|
+
const name = nameNode.value;
|
|
280
|
+
const sequenceNode = statementNode.find(n => n.name === "sequence-literal") as Node;
|
|
281
|
+
const sequence = this._buildSequence(name, sequenceNode);
|
|
282
|
+
|
|
283
|
+
this._parseContext.patternsByName.set(name, sequence);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
private _buildSequence(name: string, node: Node) {
|
|
287
|
+
const patternNodes = node.children.filter(n => n.name !== "and-divider");
|
|
288
|
+
|
|
289
|
+
const patterns = patternNodes.map(n => {
|
|
290
|
+
const patternNode = n.children[0].name === "not" ? n.children[1] : n.children[0];
|
|
291
|
+
const isNot = n.find(n => n.name === "not") != null;
|
|
292
|
+
const isOptional = n.find(n => n.name === "is-optional");
|
|
293
|
+
const pattern = this._buildPattern(patternNode);
|
|
294
|
+
const finalPattern = isOptional ? new Optional(pattern.name, pattern) : pattern;
|
|
295
|
+
|
|
296
|
+
if (isNot) {
|
|
297
|
+
return new Not(`not-${finalPattern.name}`, finalPattern);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return finalPattern;
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
return new Sequence(name, patterns);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
private _saveRepeat(statementNode: Node) {
|
|
307
|
+
const nameNode = statementNode.find(n => n.name === "name") as Node;
|
|
308
|
+
const name = nameNode.value;
|
|
309
|
+
const repeatNode = statementNode.find(n => n.name === "repeat-literal") as Node;
|
|
310
|
+
const repeat = this._buildRepeat(name, repeatNode);
|
|
311
|
+
|
|
312
|
+
this._parseContext.patternsByName.set(name, repeat);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
private _buildRepeat(name: string, repeatNode: Node) {
|
|
316
|
+
let isOptional = false;
|
|
317
|
+
const bounds = repeatNode.find(n => n.name === "bounds");
|
|
318
|
+
const exactCount = repeatNode.find(n => n.name === "exact-count");
|
|
319
|
+
const quantifier = repeatNode.find(n => n.name === "quantifier-shorthand");
|
|
320
|
+
const trimDivider = repeatNode.find(n => n.name === "trim-flag") != null;
|
|
321
|
+
const patterNode = repeatNode.children[1].type === "spaces" ? repeatNode.children[2] : repeatNode.children[1];
|
|
322
|
+
const pattern = this._buildPattern(patterNode);
|
|
323
|
+
const dividerSectionNode = repeatNode.find(n => n.name === "divider-section");
|
|
324
|
+
|
|
325
|
+
const options: RepeatOptions = {
|
|
326
|
+
min: 1,
|
|
327
|
+
max: Infinity
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
if (trimDivider) {
|
|
331
|
+
options.trimDivider = trimDivider;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (dividerSectionNode != null) {
|
|
335
|
+
const dividerNode = dividerSectionNode.children[1];
|
|
336
|
+
options.divider = this._buildPattern(dividerNode);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (bounds != null) {
|
|
340
|
+
const minNode = bounds.find(p => p.name === "min");
|
|
341
|
+
const maxNode = bounds.find(p => p.name === "max");
|
|
342
|
+
|
|
343
|
+
const min = minNode == null ? 0 : Number(minNode.value);
|
|
344
|
+
const max = maxNode == null ? Infinity : Number(maxNode.value);
|
|
345
|
+
|
|
346
|
+
options.min = min;
|
|
347
|
+
options.max = max;
|
|
348
|
+
} else if (exactCount != null) {
|
|
349
|
+
const integerNode = exactCount.find(p => p.name === "integer") as Node;
|
|
350
|
+
const integer = Number(integerNode.value);
|
|
351
|
+
|
|
352
|
+
options.min = integer;
|
|
353
|
+
options.max = integer;
|
|
354
|
+
} else if (quantifier != null) {
|
|
355
|
+
const type = quantifier.value;
|
|
356
|
+
if (type === "+") {
|
|
357
|
+
options.min = 1;
|
|
358
|
+
options.max = Infinity;
|
|
359
|
+
} else {
|
|
360
|
+
isOptional = true;
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return isOptional ? new Optional(name, new Repeat(name, pattern, options)) : new Repeat(name, pattern, options);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
private _saveConfigurableAnonymous(node: Node) {
|
|
368
|
+
const nameNode = node.find(n => n.name === "name") as Node;
|
|
369
|
+
const name = nameNode.value;
|
|
370
|
+
const anonymousNode = node.find(n => n.name === "complex-anonymous-pattern") as Node;
|
|
371
|
+
const isOptional = node.children[1] != null;
|
|
372
|
+
|
|
373
|
+
const anonymous = isOptional ? new Optional(name, this._buildPattern(anonymousNode)) : this._buildPattern(anonymousNode);
|
|
374
|
+
this._parseContext.patternsByName.set(name, anonymous);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
private _buildComplexAnonymousPattern(node: Node) {
|
|
378
|
+
const wrappedNode = node.children[1].name === "line-spaces" ? node.children[2] : node.children[1];
|
|
379
|
+
return this._buildPattern(wrappedNode);
|
|
167
380
|
}
|
|
168
381
|
|
|
169
382
|
private async _resolveImports(ast: Node) {
|
|
@@ -197,7 +410,7 @@ export class Grammar {
|
|
|
197
410
|
throw new Error(`'${importName}' was already used within another import.`);
|
|
198
411
|
}
|
|
199
412
|
|
|
200
|
-
const pattern = patterns
|
|
413
|
+
const pattern = patterns[importName];
|
|
201
414
|
if (pattern == null) {
|
|
202
415
|
throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
|
|
203
416
|
}
|
|
@@ -213,7 +426,7 @@ export class Grammar {
|
|
|
213
426
|
throw new Error(`'${alias}' was already used within another import.`);
|
|
214
427
|
}
|
|
215
428
|
|
|
216
|
-
const pattern = patterns
|
|
429
|
+
const pattern = patterns[importName];
|
|
217
430
|
if (pattern == null) {
|
|
218
431
|
throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
|
|
219
432
|
}
|
|
@@ -244,7 +457,7 @@ export class Grammar {
|
|
|
244
457
|
._parseContext
|
|
245
458
|
.importedPatternsByName
|
|
246
459
|
.values()
|
|
247
|
-
)
|
|
460
|
+
);
|
|
248
461
|
|
|
249
462
|
const grammar = new Grammar({
|
|
250
463
|
params: importedValues,
|
|
@@ -253,59 +466,13 @@ export class Grammar {
|
|
|
253
466
|
});
|
|
254
467
|
|
|
255
468
|
const patterns = grammar.parseString(expression);
|
|
256
|
-
params = Array.from(
|
|
469
|
+
params = Array.from(Object.values(patterns));
|
|
257
470
|
}
|
|
258
471
|
}
|
|
259
472
|
|
|
260
473
|
return params;
|
|
261
474
|
}
|
|
262
475
|
|
|
263
|
-
private _buildLiteral(statementNode: Node) {
|
|
264
|
-
const nameNode = statementNode.find(n => n.name === "name") as Node;
|
|
265
|
-
const literalNode = statementNode.find(n => n.name === "literal") as Node;
|
|
266
|
-
const name = nameNode.value;
|
|
267
|
-
const value = this._resolveStringValue(literalNode.value.slice(1, -1));
|
|
268
|
-
const literal = new Literal(name, value);
|
|
269
|
-
|
|
270
|
-
this._parseContext.patternsByName.set(name, literal)
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
private _resolveStringValue(value: string) {
|
|
274
|
-
return value.replace(/\\n/g, '\n')
|
|
275
|
-
.replace(/\\r/g, '\r')
|
|
276
|
-
.replace(/\\t/g, '\t')
|
|
277
|
-
.replace(/\\b/g, '\b')
|
|
278
|
-
.replace(/\\f/g, '\f')
|
|
279
|
-
.replace(/\\v/g, '\v')
|
|
280
|
-
.replace(/\\0/g, '\0')
|
|
281
|
-
.replace(/\\x([0-9A-Fa-f]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
|
|
282
|
-
.replace(/\\u([0-9A-Fa-f]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
|
|
283
|
-
.replace(/\\(.)/g, '$1');
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
private _buildRegex(statementNode: Node) {
|
|
287
|
-
const nameNode = statementNode.find(n => n.name === "name") as Node;
|
|
288
|
-
const regexNode = statementNode.find(n => n.name === "regex-literal") as Node;
|
|
289
|
-
const value = regexNode.value.slice(1, regexNode.value.length - 1);
|
|
290
|
-
const name = nameNode.value;
|
|
291
|
-
|
|
292
|
-
const regex = new Regex(name, value);
|
|
293
|
-
|
|
294
|
-
this._parseContext.patternsByName.set(name, regex);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
private _buildOr(statementNode: Node) {
|
|
298
|
-
const nameNode = statementNode.find(n => n.name === "name") as Node;
|
|
299
|
-
const orNode = statementNode.find(n => n.name === "or-literal") as Node;
|
|
300
|
-
const patternNodes = orNode.children.filter(n => n.name === "pattern-name");
|
|
301
|
-
|
|
302
|
-
const name = nameNode.value;
|
|
303
|
-
const patterns = patternNodes.map(n => this._getPattern(n.value));
|
|
304
|
-
const or = new Or(name, patterns, false, true);
|
|
305
|
-
|
|
306
|
-
this._parseContext.patternsByName.set(name, or);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
476
|
private _getPattern(name: string) {
|
|
310
477
|
let pattern = this._parseContext.patternsByName.get(name);
|
|
311
478
|
|
|
@@ -324,98 +491,14 @@ export class Grammar {
|
|
|
324
491
|
return pattern;
|
|
325
492
|
}
|
|
326
493
|
|
|
327
|
-
private
|
|
328
|
-
const nameNode = statementNode.find(n => n.name === "name") as Node;
|
|
329
|
-
const andNode = statementNode.find(n => n.name === "and-literal") as Node;
|
|
330
|
-
const patternNodes = andNode.children.filter(n => n.name === "pattern");
|
|
331
|
-
|
|
332
|
-
const name = nameNode.value;
|
|
333
|
-
const patterns = patternNodes.map(n => {
|
|
334
|
-
const nameNode = n.find(n => n.name === "pattern-name") as Node;
|
|
335
|
-
const isNot = n.find(n => n.name === "not") != null;
|
|
336
|
-
const isOptional = n.find(n => n.name === "is-optional") != null;
|
|
337
|
-
const name = nameNode.value;
|
|
338
|
-
const pattern = this._getPattern(name);
|
|
339
|
-
|
|
340
|
-
if (isNot) {
|
|
341
|
-
return new Not(`not-${name}`, pattern.clone(name, isOptional));
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
return pattern.clone(name, isOptional);
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
const and = new And(name, patterns);
|
|
348
|
-
|
|
349
|
-
this._parseContext.patternsByName.set(name, and);
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
private _buildRepeat(statementNode: Node) {
|
|
353
|
-
const nameNode = statementNode.find(n => n.name === "name") as Node;
|
|
354
|
-
const repeatNode = statementNode.find(n => n.name === "repeat-literal") as Node;
|
|
355
|
-
const patternNameNode = statementNode.find(n => n.name === "pattern-name") as Node;
|
|
356
|
-
const dividerNode = repeatNode.find(n => n.name === "divider-pattern");
|
|
357
|
-
const bounds = repeatNode.find(n => n.name === "bounds");
|
|
358
|
-
const exactCount = repeatNode.find(n => n.name === "exact-count");
|
|
359
|
-
const quantifier = repeatNode.find(n => n.name === "quantifier-shorthand");
|
|
360
|
-
const isPatternOptional = repeatNode.find(n => n.name === "is-optional") != null;
|
|
361
|
-
const trimDivider = repeatNode.find(n => n.name === "trim-divider") != null;
|
|
362
|
-
|
|
363
|
-
const name = nameNode.value;
|
|
364
|
-
const pattern = this._getPattern(patternNameNode.value);
|
|
365
|
-
|
|
366
|
-
const options: RepeatOptions = {
|
|
367
|
-
min: 1,
|
|
368
|
-
max: Infinity
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
if (trimDivider) {
|
|
372
|
-
options.trimDivider = trimDivider;
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
if (dividerNode != null) {
|
|
376
|
-
options.divider = this._getPattern(dividerNode.value);
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
if (bounds != null) {
|
|
380
|
-
const minNode = bounds.find(p => p.name === "min");
|
|
381
|
-
const maxNode = bounds.find(p => p.name === "max");
|
|
382
|
-
|
|
383
|
-
const min = minNode == null ? 0 : Number(minNode.value);
|
|
384
|
-
const max = maxNode == null ? Infinity : Number(maxNode.value);
|
|
385
|
-
|
|
386
|
-
options.min = min;
|
|
387
|
-
options.max = max;
|
|
388
|
-
} else if (exactCount != null) {
|
|
389
|
-
const integerNode = exactCount.find(p => p.name === "integer") as Node;
|
|
390
|
-
const integer = Number(integerNode.value);
|
|
391
|
-
|
|
392
|
-
options.min = integer;
|
|
393
|
-
options.max = integer;
|
|
394
|
-
} else if (quantifier != null) {
|
|
395
|
-
const type = quantifier.value;
|
|
396
|
-
if (type === "+") {
|
|
397
|
-
options.min = 1;
|
|
398
|
-
options.max = Infinity;
|
|
399
|
-
} else {
|
|
400
|
-
options.min = 0;
|
|
401
|
-
options.max = Infinity;
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
const repeat = new Repeat(name, pattern.clone(pattern.name, isPatternOptional), options);
|
|
406
|
-
|
|
407
|
-
this._parseContext.patternsByName.set(name, repeat);
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
private _buildAlias(statementNode: Node) {
|
|
494
|
+
private _saveAlias(statementNode: Node) {
|
|
411
495
|
const nameNode = statementNode.find(n => n.name === "name") as Node;
|
|
412
496
|
const aliasNode = statementNode.find(n => n.name === "alias-literal") as Node;
|
|
413
497
|
const aliasName = aliasNode.value;
|
|
414
498
|
const name = nameNode.value;
|
|
415
|
-
const
|
|
416
|
-
const alias = pattern.clone(name);
|
|
499
|
+
const alias = this._getPattern(aliasName).clone(name);
|
|
417
500
|
|
|
418
|
-
this._parseContext.patternsByName.set(name, alias)
|
|
501
|
+
this._parseContext.patternsByName.set(name, alias);
|
|
419
502
|
}
|
|
420
503
|
|
|
421
504
|
static parse(expression: string, options?: GrammarOptions) {
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Literal } from "../../patterns/Literal";
|
|
2
|
+
import { Sequence } from "../../patterns/Sequence";
|
|
3
|
+
import { lineSpaces } from "./spaces";
|
|
4
|
+
import { anonymousLiterals, anonymousWrappedLiterals } from './literals';
|
|
5
|
+
import { Options } from "../../patterns/Options";
|
|
6
|
+
import { Optional } from "../../patterns/Optional";
|
|
7
|
+
|
|
8
|
+
const inlinePatternOpenParen = new Literal("anonymous-pattern-open-paren", "(");
|
|
9
|
+
const inlinePatternCloseParen = new Literal("anonymous-pattern-close-paren", ")");
|
|
10
|
+
const optionalLineSpaces = new Optional("optional-line-spaces", lineSpaces);
|
|
11
|
+
|
|
12
|
+
const complexAnonymousPattern = new Sequence("complex-anonymous-pattern", [
|
|
13
|
+
inlinePatternOpenParen,
|
|
14
|
+
optionalLineSpaces,
|
|
15
|
+
anonymousWrappedLiterals,
|
|
16
|
+
optionalLineSpaces,
|
|
17
|
+
inlinePatternCloseParen,
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
export const anonymousPattern = new Options("anonymous-pattern", [
|
|
21
|
+
anonymousLiterals,
|
|
22
|
+
complexAnonymousPattern
|
|
23
|
+
]);
|
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { Sequence } from "../../patterns/Sequence";
|
|
2
|
+
import { Options } from "../../patterns/Options";
|
|
3
3
|
import { Repeat } from "../../patterns/Repeat";
|
|
4
4
|
import { comment } from "./comment";
|
|
5
5
|
import { lineSpaces, newLine } from "./spaces";
|
|
6
6
|
import { statement } from "./statement";
|
|
7
|
+
import { Optional } from "../../patterns/Optional";
|
|
7
8
|
|
|
8
|
-
const bodyLineContent = new
|
|
9
|
+
const bodyLineContent = new Options("body-line-content", [
|
|
9
10
|
comment,
|
|
10
11
|
statement
|
|
11
12
|
]);
|
|
12
13
|
|
|
13
|
-
const
|
|
14
|
-
|
|
14
|
+
const optionalLineSpaces = new Optional("optional-line-spaces", lineSpaces);
|
|
15
|
+
|
|
16
|
+
const bodyLine = new Sequence("body-line", [
|
|
17
|
+
optionalLineSpaces,
|
|
15
18
|
bodyLineContent,
|
|
16
|
-
|
|
19
|
+
optionalLineSpaces,
|
|
17
20
|
]);
|
|
18
21
|
|
|
19
22
|
export const body = new Repeat("body", bodyLine, {divider: newLine, min: 0});
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Options } from "../../patterns/Options";
|
|
2
2
|
import { Regex } from "../../patterns/Regex";
|
|
3
3
|
import { Repeat } from "../../patterns/Repeat";
|
|
4
4
|
import { comment } from "./comment";
|
|
5
5
|
import { importStatement } from './import';
|
|
6
|
-
import {
|
|
6
|
+
import { Sequence } from "../../patterns/Sequence";
|
|
7
7
|
import { allSpaces } from "./spaces";
|
|
8
8
|
import { body } from "./body";
|
|
9
|
+
import { Optional } from "../../patterns/Optional";
|
|
9
10
|
|
|
10
11
|
const tabs = new Regex("tabs", "\\t+");
|
|
11
12
|
const spaces = new Regex("spaces", "[ ]+");
|
|
@@ -15,25 +16,27 @@ spaces.setTokens([" "]);
|
|
|
15
16
|
tabs.setTokens(["\t"]);
|
|
16
17
|
newLine.setTokens(["\n"]);
|
|
17
18
|
|
|
18
|
-
const lineSpaces = new Repeat("line-spaces", new
|
|
19
|
+
const lineSpaces = new Repeat("line-spaces", new Options("line-space", [tabs, spaces]));
|
|
20
|
+
const optionalLineSpaces = new Optional("optional-line-spaces", lineSpaces);
|
|
19
21
|
|
|
20
|
-
const headLineContent = new
|
|
22
|
+
const headLineContent = new Options("head-line-content", [
|
|
21
23
|
comment,
|
|
22
24
|
importStatement
|
|
23
25
|
]);
|
|
24
26
|
|
|
25
|
-
const headLine = new
|
|
26
|
-
|
|
27
|
+
const headLine = new Sequence("head-line-content", [
|
|
28
|
+
optionalLineSpaces,
|
|
27
29
|
headLineContent,
|
|
28
|
-
|
|
30
|
+
optionalLineSpaces,
|
|
29
31
|
]);
|
|
30
32
|
|
|
31
|
-
const head = new Repeat("head", headLine, { divider: newLine
|
|
33
|
+
const head = new Optional("optional-head", new Repeat("head", headLine, { divider: newLine }));
|
|
34
|
+
const optionalSpaces = new Optional("optional-spaces", allSpaces);
|
|
32
35
|
|
|
33
|
-
export const grammar = new
|
|
34
|
-
|
|
36
|
+
export const grammar = new Sequence("grammar", [
|
|
37
|
+
optionalSpaces,
|
|
35
38
|
head,
|
|
36
|
-
|
|
39
|
+
optionalSpaces,
|
|
37
40
|
body,
|
|
38
|
-
|
|
41
|
+
optionalSpaces
|
|
39
42
|
]);
|