clarity-pattern-parser 6.0.2 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/TODO.md +1 -78
- package/dist/ast/Node.d.ts +1 -0
- package/dist/grammar/Grammar.d.ts +17 -0
- package/dist/grammar/patterns/andLiteral.d.ts +2 -0
- package/dist/grammar/patterns/comment.d.ts +2 -0
- package/dist/grammar/patterns/grammar.d.ts +2 -0
- package/dist/grammar/patterns/literal.d.ts +2 -0
- package/dist/grammar/patterns/name.d.ts +2 -0
- package/dist/grammar/patterns/orLiteral.d.ts +2 -0
- package/dist/grammar/patterns/pattern.d.ts +2 -0
- package/dist/grammar/patterns/regexLiteral.d.ts +2 -0
- package/dist/grammar/patterns/repeatLiteral.d.ts +3 -0
- package/dist/grammar/patterns/spaces.d.ts +2 -0
- package/dist/grammar/patterns/statement.d.ts +2 -0
- package/dist/index.browser.js +1161 -556
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.esm.js +1159 -555
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1159 -554
- package/dist/index.js.map +1 -1
- package/dist/intellisense/AutoComplete.d.ts +2 -6
- package/dist/patterns/And.d.ts +1 -1
- package/dist/patterns/Cursor.d.ts +1 -0
- package/dist/patterns/CursorHistory.d.ts +2 -1
- package/dist/patterns/FiniteRepeat.d.ts +39 -0
- package/dist/patterns/InfiniteRepeat.d.ts +47 -0
- package/dist/patterns/Literal.d.ts +1 -1
- package/dist/patterns/Not.d.ts +1 -1
- package/dist/patterns/Or.d.ts +1 -1
- package/dist/patterns/Pattern.d.ts +1 -1
- package/dist/patterns/Reference.d.ts +1 -1
- package/dist/patterns/Regex.d.ts +1 -1
- package/dist/patterns/Repeat.d.ts +18 -22
- package/jest.config.js +0 -1
- package/jest.coverage.config.js +13 -0
- package/package.json +3 -3
- package/src/ast/Node.test.ts +15 -0
- package/src/ast/Node.ts +12 -6
- package/src/grammar/Grammar.test.ts +306 -0
- package/src/grammar/Grammar.ts +249 -0
- package/src/grammar/patterns/andLiteral.ts +8 -0
- package/src/grammar/patterns/comment.ts +3 -0
- package/src/grammar/patterns/grammar.ts +19 -0
- package/src/grammar/patterns/literal.ts +5 -0
- package/src/grammar/patterns/name.ts +3 -0
- package/src/grammar/patterns/orLiteral.ts +8 -0
- package/src/grammar/patterns/pattern.ts +13 -0
- package/src/grammar/patterns/regexLiteral.ts +4 -0
- package/src/grammar/patterns/repeatLiteral.ts +72 -0
- package/src/grammar/patterns/spaces.ts +4 -0
- package/src/grammar/patterns/statement.ts +36 -0
- package/src/grammar/spec.md +142 -0
- package/src/index.ts +6 -3
- package/src/intellisense/AutoComplete.test.ts +21 -2
- package/src/intellisense/AutoComplete.ts +14 -25
- package/src/intellisense/Suggestion.ts +0 -1
- package/src/intellisense/css/cssValue.ts +1 -1
- package/src/intellisense/css/method.ts +1 -1
- package/src/intellisense/css/values.ts +1 -1
- package/src/intellisense/javascript/Javascript.test.ts +0 -1
- package/src/intellisense/javascript/arrayLiteral.ts +1 -1
- package/src/intellisense/javascript/expression.ts +1 -1
- package/src/intellisense/javascript/invocation.ts +1 -1
- package/src/intellisense/javascript/objectLiteral.ts +1 -1
- package/src/intellisense/javascript/parameters.ts +1 -1
- package/src/intellisense/javascript/stringLiteral.ts +2 -4
- package/src/patterns/And.test.ts +5 -5
- package/src/patterns/And.ts +11 -17
- package/src/patterns/Cursor.ts +4 -0
- package/src/patterns/CursorHistory.ts +34 -5
- package/src/patterns/FiniteRepeat.test.ts +481 -0
- package/src/patterns/FiniteRepeat.ts +231 -0
- package/src/patterns/InfiniteRepeat.test.ts +296 -0
- package/src/patterns/InfiniteRepeat.ts +329 -0
- package/src/patterns/Literal.test.ts +4 -4
- package/src/patterns/Literal.ts +1 -1
- package/src/patterns/Not.test.ts +11 -11
- package/src/patterns/Not.ts +1 -1
- package/src/patterns/Or.test.ts +9 -9
- package/src/patterns/Or.ts +1 -1
- package/src/patterns/Pattern.ts +1 -1
- package/src/patterns/Reference.test.ts +8 -8
- package/src/patterns/Reference.ts +1 -1
- package/src/patterns/Regex.test.ts +4 -4
- package/src/patterns/Regex.ts +1 -1
- package/src/patterns/Repeat.test.ts +160 -165
- package/src/patterns/Repeat.ts +95 -230
package/dist/index.js
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
class Node {
|
|
6
|
+
constructor(type, name, firstIndex, lastIndex, children = [], value = "") {
|
|
7
|
+
this._type = type;
|
|
8
|
+
this._name = name;
|
|
9
|
+
this._firstIndex = firstIndex;
|
|
10
|
+
this._lastIndex = lastIndex;
|
|
11
|
+
this._parent = null;
|
|
12
|
+
this._children = children;
|
|
13
|
+
this._value = value;
|
|
14
|
+
this._children.forEach(c => c._parent = this);
|
|
15
|
+
}
|
|
6
16
|
get type() {
|
|
7
17
|
return this._type;
|
|
8
18
|
}
|
|
@@ -33,16 +43,6 @@ class Node {
|
|
|
33
43
|
get value() {
|
|
34
44
|
return this.toString();
|
|
35
45
|
}
|
|
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
46
|
removeChild(node) {
|
|
47
47
|
const index = this._children.indexOf(node);
|
|
48
48
|
if (index > -1) {
|
|
@@ -149,6 +149,11 @@ class Node {
|
|
|
149
149
|
this.removeAllChildren();
|
|
150
150
|
this._value = value;
|
|
151
151
|
}
|
|
152
|
+
remove() {
|
|
153
|
+
if (this._parent != null) {
|
|
154
|
+
this._parent.removeChild(this);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
152
157
|
clone() {
|
|
153
158
|
return new Node(this._type, this._name, this._firstIndex, this._lastIndex, this._children.map((c) => c.clone()), this._value);
|
|
154
159
|
}
|
|
@@ -185,7 +190,7 @@ class ParseError {
|
|
|
185
190
|
class CursorHistory {
|
|
186
191
|
constructor() {
|
|
187
192
|
this._isRecording = false;
|
|
188
|
-
this.
|
|
193
|
+
this._leafMatches = [{ pattern: null, node: null }];
|
|
189
194
|
this._furthestError = null;
|
|
190
195
|
this._currentError = null;
|
|
191
196
|
this._rootMatch = { pattern: null, node: null };
|
|
@@ -200,7 +205,10 @@ class CursorHistory {
|
|
|
200
205
|
return this._rootMatch;
|
|
201
206
|
}
|
|
202
207
|
get leafMatch() {
|
|
203
|
-
return this.
|
|
208
|
+
return this._leafMatches[this._leafMatches.length - 1];
|
|
209
|
+
}
|
|
210
|
+
get leafMatches() {
|
|
211
|
+
return this._leafMatches;
|
|
204
212
|
}
|
|
205
213
|
get furthestError() {
|
|
206
214
|
return this._furthestError;
|
|
@@ -224,10 +232,32 @@ class CursorHistory {
|
|
|
224
232
|
}
|
|
225
233
|
this._rootMatch.pattern = pattern;
|
|
226
234
|
this._rootMatch.node = node;
|
|
227
|
-
const
|
|
235
|
+
const leafMatch = this._leafMatches[this._leafMatches.length - 1];
|
|
236
|
+
const isFurthestMatch = leafMatch.node === null || node.lastIndex > leafMatch.node.lastIndex;
|
|
237
|
+
const isSameIndexMatch = leafMatch.node === null || node.lastIndex === leafMatch.node.lastIndex;
|
|
228
238
|
if (isFurthestMatch) {
|
|
229
|
-
|
|
230
|
-
this.
|
|
239
|
+
// This is to save on GC churn.
|
|
240
|
+
const match = this._leafMatches.pop();
|
|
241
|
+
match.pattern = pattern;
|
|
242
|
+
match.node = node;
|
|
243
|
+
this._leafMatches.length = 0;
|
|
244
|
+
this._leafMatches.push(match);
|
|
245
|
+
}
|
|
246
|
+
else if (isSameIndexMatch) {
|
|
247
|
+
const isAncestor = this._leafMatches.some((m) => {
|
|
248
|
+
var _a;
|
|
249
|
+
let parent = (_a = m.pattern) === null || _a === void 0 ? void 0 : _a.parent;
|
|
250
|
+
while (parent != null) {
|
|
251
|
+
if (parent == pattern.parent) {
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
parent = parent.parent;
|
|
255
|
+
}
|
|
256
|
+
return false;
|
|
257
|
+
});
|
|
258
|
+
if (!isAncestor) {
|
|
259
|
+
this._leafMatches.unshift({ pattern, node });
|
|
260
|
+
}
|
|
231
261
|
}
|
|
232
262
|
}
|
|
233
263
|
recordErrorAt(index, pattern) {
|
|
@@ -252,6 +282,15 @@ class CursorHistory {
|
|
|
252
282
|
}
|
|
253
283
|
|
|
254
284
|
class Cursor {
|
|
285
|
+
constructor(text) {
|
|
286
|
+
if (text.length === 0) {
|
|
287
|
+
throw new Error("Cannot have a empty string.");
|
|
288
|
+
}
|
|
289
|
+
this._text = text;
|
|
290
|
+
this._index = 0;
|
|
291
|
+
this._length = text.length;
|
|
292
|
+
this._history = new CursorHistory();
|
|
293
|
+
}
|
|
255
294
|
get text() {
|
|
256
295
|
return this._text;
|
|
257
296
|
}
|
|
@@ -270,6 +309,9 @@ class Cursor {
|
|
|
270
309
|
get leafMatch() {
|
|
271
310
|
return this._history.leafMatch;
|
|
272
311
|
}
|
|
312
|
+
get leafMatches() {
|
|
313
|
+
return this._history.leafMatches;
|
|
314
|
+
}
|
|
273
315
|
get furthestError() {
|
|
274
316
|
return this._history.furthestError;
|
|
275
317
|
}
|
|
@@ -288,15 +330,6 @@ class Cursor {
|
|
|
288
330
|
get currentChar() {
|
|
289
331
|
return this._text[this._index];
|
|
290
332
|
}
|
|
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
333
|
hasNext() {
|
|
301
334
|
return this._index + 1 < this._length;
|
|
302
335
|
}
|
|
@@ -347,7 +380,20 @@ class Cursor {
|
|
|
347
380
|
}
|
|
348
381
|
}
|
|
349
382
|
|
|
350
|
-
class
|
|
383
|
+
class Literal {
|
|
384
|
+
constructor(name, value, isOptional = false) {
|
|
385
|
+
if (value.length === 0) {
|
|
386
|
+
throw new Error("Value Cannot be empty.");
|
|
387
|
+
}
|
|
388
|
+
this._type = "literal";
|
|
389
|
+
this._name = name;
|
|
390
|
+
this._literal = value;
|
|
391
|
+
this._runes = Array.from(value);
|
|
392
|
+
this._isOptional = isOptional;
|
|
393
|
+
this._parent = null;
|
|
394
|
+
this._firstIndex = 0;
|
|
395
|
+
this._lastIndex = 0;
|
|
396
|
+
}
|
|
351
397
|
get type() {
|
|
352
398
|
return this._type;
|
|
353
399
|
}
|
|
@@ -366,6 +412,94 @@ class Regex {
|
|
|
366
412
|
get isOptional() {
|
|
367
413
|
return this._isOptional;
|
|
368
414
|
}
|
|
415
|
+
test(text) {
|
|
416
|
+
const cursor = new Cursor(text);
|
|
417
|
+
const ast = this.parse(cursor);
|
|
418
|
+
return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
|
|
419
|
+
}
|
|
420
|
+
exec(text) {
|
|
421
|
+
const cursor = new Cursor(text);
|
|
422
|
+
const ast = this.parse(cursor);
|
|
423
|
+
return {
|
|
424
|
+
ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
|
|
425
|
+
cursor
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
parse(cursor) {
|
|
429
|
+
this._firstIndex = cursor.index;
|
|
430
|
+
const passed = this._tryToParse(cursor);
|
|
431
|
+
if (passed) {
|
|
432
|
+
cursor.resolveError();
|
|
433
|
+
const node = this._createNode();
|
|
434
|
+
cursor.recordMatch(this, node);
|
|
435
|
+
return node;
|
|
436
|
+
}
|
|
437
|
+
if (!this._isOptional) {
|
|
438
|
+
cursor.recordErrorAt(cursor.index, this);
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
441
|
+
cursor.resolveError();
|
|
442
|
+
cursor.moveTo(this._firstIndex);
|
|
443
|
+
return null;
|
|
444
|
+
}
|
|
445
|
+
_tryToParse(cursor) {
|
|
446
|
+
let passed = false;
|
|
447
|
+
const literalRuneLength = this._runes.length;
|
|
448
|
+
for (let i = 0; i < literalRuneLength; i++) {
|
|
449
|
+
const literalRune = this._runes[i];
|
|
450
|
+
const cursorRune = cursor.currentChar;
|
|
451
|
+
if (literalRune !== cursorRune) {
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
if (i + 1 === literalRuneLength) {
|
|
455
|
+
this._lastIndex = this._firstIndex + this._literal.length - 1;
|
|
456
|
+
passed = true;
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
if (!cursor.hasNext()) {
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
cursor.next();
|
|
463
|
+
}
|
|
464
|
+
return passed;
|
|
465
|
+
}
|
|
466
|
+
_createNode() {
|
|
467
|
+
return new Node("literal", this._name, this._firstIndex, this._lastIndex, undefined, this._literal);
|
|
468
|
+
}
|
|
469
|
+
clone(name = this._name, isOptional = this._isOptional) {
|
|
470
|
+
const clone = new Literal(name, this._literal, isOptional);
|
|
471
|
+
return clone;
|
|
472
|
+
}
|
|
473
|
+
getTokens() {
|
|
474
|
+
return [this._literal];
|
|
475
|
+
}
|
|
476
|
+
getTokensAfter(_lastMatched) {
|
|
477
|
+
return [];
|
|
478
|
+
}
|
|
479
|
+
getNextTokens() {
|
|
480
|
+
if (this.parent == null) {
|
|
481
|
+
return [];
|
|
482
|
+
}
|
|
483
|
+
return this.parent.getTokensAfter(this);
|
|
484
|
+
}
|
|
485
|
+
getPatterns() {
|
|
486
|
+
return [this];
|
|
487
|
+
}
|
|
488
|
+
getPatternsAfter() {
|
|
489
|
+
return [];
|
|
490
|
+
}
|
|
491
|
+
getNextPatterns() {
|
|
492
|
+
if (this.parent == null) {
|
|
493
|
+
return [];
|
|
494
|
+
}
|
|
495
|
+
return this.parent.getPatternsAfter(this);
|
|
496
|
+
}
|
|
497
|
+
find(_predicate) {
|
|
498
|
+
return null;
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
class Regex {
|
|
369
503
|
constructor(name, regex, isOptional = false) {
|
|
370
504
|
this._node = null;
|
|
371
505
|
this._cursor = null;
|
|
@@ -379,6 +513,24 @@ class Regex {
|
|
|
379
513
|
this._regex = new RegExp(`^${regex}`, "g");
|
|
380
514
|
this.assertArguments();
|
|
381
515
|
}
|
|
516
|
+
get type() {
|
|
517
|
+
return this._type;
|
|
518
|
+
}
|
|
519
|
+
get name() {
|
|
520
|
+
return this._name;
|
|
521
|
+
}
|
|
522
|
+
get parent() {
|
|
523
|
+
return this._parent;
|
|
524
|
+
}
|
|
525
|
+
set parent(pattern) {
|
|
526
|
+
this._parent = pattern;
|
|
527
|
+
}
|
|
528
|
+
get children() {
|
|
529
|
+
return [];
|
|
530
|
+
}
|
|
531
|
+
get isOptional() {
|
|
532
|
+
return this._isOptional;
|
|
533
|
+
}
|
|
382
534
|
assertArguments() {
|
|
383
535
|
if (this._originalRegexString.length < 1) {
|
|
384
536
|
throw new Error("Invalid Arguments: The regex string argument needs to be at least one character long.");
|
|
@@ -465,7 +617,7 @@ class Regex {
|
|
|
465
617
|
}
|
|
466
618
|
return this.parent.getPatternsAfter(this);
|
|
467
619
|
}
|
|
468
|
-
|
|
620
|
+
find(_predicate) {
|
|
469
621
|
return null;
|
|
470
622
|
}
|
|
471
623
|
setTokens(tokens) {
|
|
@@ -473,20 +625,6 @@ class Regex {
|
|
|
473
625
|
}
|
|
474
626
|
}
|
|
475
627
|
|
|
476
|
-
function clonePatterns(patterns, isOptional) {
|
|
477
|
-
return patterns.map(p => p.clone(p.name, isOptional));
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
function filterOutNull(nodes) {
|
|
481
|
-
const filteredNodes = [];
|
|
482
|
-
for (const node of nodes) {
|
|
483
|
-
if (node !== null) {
|
|
484
|
-
filteredNodes.push(node);
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
return filteredNodes;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
628
|
function findPattern(pattern, predicate) {
|
|
491
629
|
let children = [];
|
|
492
630
|
if (pattern.type === "reference") {
|
|
@@ -509,7 +647,15 @@ function findPattern(pattern, predicate) {
|
|
|
509
647
|
}
|
|
510
648
|
}
|
|
511
649
|
|
|
512
|
-
class
|
|
650
|
+
class Reference {
|
|
651
|
+
constructor(name, isOptional = false) {
|
|
652
|
+
this._type = "reference";
|
|
653
|
+
this._name = name;
|
|
654
|
+
this._parent = null;
|
|
655
|
+
this._isOptional = isOptional;
|
|
656
|
+
this._pattern = null;
|
|
657
|
+
this._children = [];
|
|
658
|
+
}
|
|
513
659
|
get type() {
|
|
514
660
|
return this._type;
|
|
515
661
|
}
|
|
@@ -528,25 +674,6 @@ class And {
|
|
|
528
674
|
get isOptional() {
|
|
529
675
|
return this._isOptional;
|
|
530
676
|
}
|
|
531
|
-
constructor(name, sequence, isOptional = false) {
|
|
532
|
-
if (sequence.length === 0) {
|
|
533
|
-
throw new Error("Need at least one pattern with an 'and' pattern.");
|
|
534
|
-
}
|
|
535
|
-
const children = clonePatterns(sequence);
|
|
536
|
-
this._assignChildrenToParent(children);
|
|
537
|
-
this._type = "and";
|
|
538
|
-
this._name = name;
|
|
539
|
-
this._isOptional = isOptional;
|
|
540
|
-
this._parent = null;
|
|
541
|
-
this._children = children;
|
|
542
|
-
this._firstIndex = -1;
|
|
543
|
-
this._nodes = [];
|
|
544
|
-
}
|
|
545
|
-
_assignChildrenToParent(children) {
|
|
546
|
-
for (const child of children) {
|
|
547
|
-
child.parent = this;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
677
|
test(text) {
|
|
551
678
|
const cursor = new Cursor(text);
|
|
552
679
|
const ast = this.parse(cursor);
|
|
@@ -561,118 +688,48 @@ class And {
|
|
|
561
688
|
};
|
|
562
689
|
}
|
|
563
690
|
parse(cursor) {
|
|
564
|
-
this.
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
if (
|
|
568
|
-
const
|
|
569
|
-
if (
|
|
570
|
-
|
|
691
|
+
return this._getPatternSafely().parse(cursor);
|
|
692
|
+
}
|
|
693
|
+
_getPatternSafely() {
|
|
694
|
+
if (this._pattern === null) {
|
|
695
|
+
const pattern = this._findPattern();
|
|
696
|
+
if (pattern === null) {
|
|
697
|
+
throw new Error(`Couldn't find '${this._name}' pattern within tree.`);
|
|
571
698
|
}
|
|
572
|
-
|
|
699
|
+
const clonedPattern = pattern.clone(this._name, this._isOptional);
|
|
700
|
+
clonedPattern.parent = this;
|
|
701
|
+
this._pattern = clonedPattern;
|
|
702
|
+
this._children = [this._pattern];
|
|
573
703
|
}
|
|
574
|
-
|
|
575
|
-
|
|
704
|
+
return this._pattern;
|
|
705
|
+
}
|
|
706
|
+
_findPattern() {
|
|
707
|
+
const root = this._getRoot();
|
|
708
|
+
return findPattern(root, (pattern) => {
|
|
709
|
+
return pattern.name === this._name && pattern.type !== "reference";
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
_getRoot() {
|
|
713
|
+
let node = this;
|
|
714
|
+
while (true) {
|
|
715
|
+
const parent = node.parent;
|
|
716
|
+
if (parent == null) {
|
|
717
|
+
break;
|
|
718
|
+
}
|
|
719
|
+
else {
|
|
720
|
+
node = parent;
|
|
721
|
+
}
|
|
576
722
|
}
|
|
577
|
-
return
|
|
578
|
-
}
|
|
579
|
-
tryToParse(cursor) {
|
|
580
|
-
let passed = false;
|
|
581
|
-
for (let i = 0; i < this._children.length; i++) {
|
|
582
|
-
const runningCursorIndex = cursor.index;
|
|
583
|
-
const nextPatternIndex = i + 1;
|
|
584
|
-
const hasMorePatterns = nextPatternIndex < this._children.length;
|
|
585
|
-
const node = this._children[i].parse(cursor);
|
|
586
|
-
const hasNoError = !cursor.hasError;
|
|
587
|
-
const hadMatch = node !== null;
|
|
588
|
-
if (hasNoError) {
|
|
589
|
-
this._nodes.push(node);
|
|
590
|
-
if (hasMorePatterns) {
|
|
591
|
-
if (hadMatch) {
|
|
592
|
-
if (cursor.hasNext()) {
|
|
593
|
-
// We had a match. Increment the cursor and use the next pattern.
|
|
594
|
-
cursor.next();
|
|
595
|
-
continue;
|
|
596
|
-
}
|
|
597
|
-
else {
|
|
598
|
-
// We are at the end of the text, it may still be valid, if all the
|
|
599
|
-
// following patterns are optional.
|
|
600
|
-
if (this.areRemainingPatternsOptional(i)) {
|
|
601
|
-
passed = true;
|
|
602
|
-
break;
|
|
603
|
-
}
|
|
604
|
-
// We didn't finish the parsing sequence.
|
|
605
|
-
cursor.recordErrorAt(cursor.index + 1, this);
|
|
606
|
-
break;
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
else {
|
|
610
|
-
// An optional pattern did not matched, try from the same spot on the next
|
|
611
|
-
// pattern.
|
|
612
|
-
cursor.moveTo(runningCursorIndex);
|
|
613
|
-
continue;
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
else {
|
|
617
|
-
// If we don't have any results from what we parsed then record error.
|
|
618
|
-
const lastNode = this.getLastValidNode();
|
|
619
|
-
if (lastNode === null) {
|
|
620
|
-
cursor.recordErrorAt(cursor.index, this);
|
|
621
|
-
break;
|
|
622
|
-
}
|
|
623
|
-
// The sequence was parsed fully.
|
|
624
|
-
passed = true;
|
|
625
|
-
break;
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
else {
|
|
629
|
-
// The pattern failed.
|
|
630
|
-
cursor.moveTo(this._firstIndex);
|
|
631
|
-
break;
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
return passed;
|
|
635
|
-
}
|
|
636
|
-
getLastValidNode() {
|
|
637
|
-
const nodes = filterOutNull(this._nodes);
|
|
638
|
-
if (nodes.length === 0) {
|
|
639
|
-
return null;
|
|
640
|
-
}
|
|
641
|
-
return nodes[nodes.length - 1];
|
|
642
|
-
}
|
|
643
|
-
areRemainingPatternsOptional(fromIndex) {
|
|
644
|
-
const startOnIndex = fromIndex + 1;
|
|
645
|
-
const length = this._children.length;
|
|
646
|
-
for (let i = startOnIndex; i < length; i++) {
|
|
647
|
-
const pattern = this._children[i];
|
|
648
|
-
if (!pattern.isOptional) {
|
|
649
|
-
return false;
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
return true;
|
|
653
|
-
}
|
|
654
|
-
createNode(cursor) {
|
|
655
|
-
const children = filterOutNull(this._nodes);
|
|
656
|
-
const lastIndex = children[children.length - 1].lastIndex;
|
|
657
|
-
cursor.getChars(this._firstIndex, lastIndex);
|
|
658
|
-
cursor.moveTo(lastIndex);
|
|
659
|
-
return new Node("and", this._name, this._firstIndex, lastIndex, children);
|
|
723
|
+
return node;
|
|
660
724
|
}
|
|
661
725
|
getTokens() {
|
|
662
|
-
|
|
663
|
-
for (const child of this._children) {
|
|
664
|
-
tokens.push(...child.getTokens());
|
|
665
|
-
if (!child.isOptional) {
|
|
666
|
-
break;
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
return tokens;
|
|
726
|
+
return this._getPatternSafely().getTokens();
|
|
670
727
|
}
|
|
671
|
-
getTokensAfter(
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
return
|
|
728
|
+
getTokensAfter(_lastMatched) {
|
|
729
|
+
if (this._parent == null) {
|
|
730
|
+
return [];
|
|
731
|
+
}
|
|
732
|
+
return this._parent.getTokensAfter(this);
|
|
676
733
|
}
|
|
677
734
|
getNextTokens() {
|
|
678
735
|
if (this.parent == null) {
|
|
@@ -681,56 +738,13 @@ class And {
|
|
|
681
738
|
return this.parent.getTokensAfter(this);
|
|
682
739
|
}
|
|
683
740
|
getPatterns() {
|
|
684
|
-
|
|
685
|
-
for (const pattern of this._children) {
|
|
686
|
-
patterns.push(...pattern.getPatterns());
|
|
687
|
-
if (!pattern.isOptional) {
|
|
688
|
-
break;
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
return patterns;
|
|
741
|
+
return this._getPatternSafely().getPatterns();
|
|
692
742
|
}
|
|
693
|
-
getPatternsAfter(
|
|
694
|
-
|
|
695
|
-
let nextSiblingIndex = -1;
|
|
696
|
-
let index = -1;
|
|
697
|
-
const patterns = [];
|
|
698
|
-
for (let i = 0; i < this._children.length; i++) {
|
|
699
|
-
if (this._children[i] === childReference) {
|
|
700
|
-
if (i + 1 < this._children.length) {
|
|
701
|
-
nextSibling = this._children[i + 1];
|
|
702
|
-
}
|
|
703
|
-
nextSiblingIndex = i + 1;
|
|
704
|
-
index = i;
|
|
705
|
-
break;
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
// The child reference isn't one of the child patterns.
|
|
709
|
-
if (index === -1) {
|
|
743
|
+
getPatternsAfter(_childReference) {
|
|
744
|
+
if (this._parent == null) {
|
|
710
745
|
return [];
|
|
711
746
|
}
|
|
712
|
-
|
|
713
|
-
if (nextSiblingIndex === this._children.length && this._parent !== null) {
|
|
714
|
-
return this._parent.getPatternsAfter(this);
|
|
715
|
-
}
|
|
716
|
-
// Next pattern isn't optional so send it back as the next patterns.
|
|
717
|
-
if (nextSibling !== null && !nextSibling.isOptional) {
|
|
718
|
-
return [nextSibling];
|
|
719
|
-
}
|
|
720
|
-
// Send back as many optional patterns as possible.
|
|
721
|
-
if (nextSibling !== null && nextSibling.isOptional) {
|
|
722
|
-
for (let i = nextSiblingIndex; i < this._children.length; i++) {
|
|
723
|
-
const child = this._children[i];
|
|
724
|
-
patterns.push(child);
|
|
725
|
-
if (!child.isOptional) {
|
|
726
|
-
break;
|
|
727
|
-
}
|
|
728
|
-
if (i === this._children.length - 1 && this._parent !== null) {
|
|
729
|
-
patterns.push(...this._parent.getPatternsAfter(this));
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
return patterns;
|
|
747
|
+
return this._parent.getPatternsAfter(this);
|
|
734
748
|
}
|
|
735
749
|
getNextPatterns() {
|
|
736
750
|
if (this.parent == null) {
|
|
@@ -738,15 +752,32 @@ class And {
|
|
|
738
752
|
}
|
|
739
753
|
return this.parent.getPatternsAfter(this);
|
|
740
754
|
}
|
|
741
|
-
|
|
742
|
-
return
|
|
755
|
+
find(_predicate) {
|
|
756
|
+
return null;
|
|
743
757
|
}
|
|
744
758
|
clone(name = this._name, isOptional = this._isOptional) {
|
|
745
|
-
return new
|
|
759
|
+
return new Reference(name, isOptional);
|
|
746
760
|
}
|
|
747
761
|
}
|
|
748
762
|
|
|
749
|
-
|
|
763
|
+
function clonePatterns(patterns, isOptional) {
|
|
764
|
+
return patterns.map(p => p.clone(p.name, isOptional));
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
class Or {
|
|
768
|
+
constructor(name, options, isOptional = false) {
|
|
769
|
+
if (options.length === 0) {
|
|
770
|
+
throw new Error("Need at least one pattern with an 'or' pattern.");
|
|
771
|
+
}
|
|
772
|
+
const children = clonePatterns(options, false);
|
|
773
|
+
this._assignChildrenToParent(children);
|
|
774
|
+
this._type = "or";
|
|
775
|
+
this._name = name;
|
|
776
|
+
this._parent = null;
|
|
777
|
+
this._children = children;
|
|
778
|
+
this._isOptional = isOptional;
|
|
779
|
+
this._firstIndex = 0;
|
|
780
|
+
}
|
|
750
781
|
get type() {
|
|
751
782
|
return this._type;
|
|
752
783
|
}
|
|
@@ -760,23 +791,15 @@ class Literal {
|
|
|
760
791
|
this._parent = pattern;
|
|
761
792
|
}
|
|
762
793
|
get children() {
|
|
763
|
-
return
|
|
794
|
+
return this._children;
|
|
764
795
|
}
|
|
765
796
|
get isOptional() {
|
|
766
797
|
return this._isOptional;
|
|
767
798
|
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
799
|
+
_assignChildrenToParent(children) {
|
|
800
|
+
for (const child of children) {
|
|
801
|
+
child.parent = this;
|
|
771
802
|
}
|
|
772
|
-
this._type = "literal";
|
|
773
|
-
this._name = name;
|
|
774
|
-
this._literal = value;
|
|
775
|
-
this._runes = Array.from(value);
|
|
776
|
-
this._isOptional = isOptional;
|
|
777
|
-
this._parent = null;
|
|
778
|
-
this._firstIndex = 0;
|
|
779
|
-
this._lastIndex = 0;
|
|
780
803
|
}
|
|
781
804
|
test(text) {
|
|
782
805
|
const cursor = new Cursor(text);
|
|
@@ -793,15 +816,13 @@ class Literal {
|
|
|
793
816
|
}
|
|
794
817
|
parse(cursor) {
|
|
795
818
|
this._firstIndex = cursor.index;
|
|
796
|
-
const
|
|
797
|
-
if (
|
|
819
|
+
const node = this._tryToParse(cursor);
|
|
820
|
+
if (node != null) {
|
|
798
821
|
cursor.resolveError();
|
|
799
|
-
const node = this._createNode();
|
|
800
|
-
cursor.recordMatch(this, node);
|
|
801
822
|
return node;
|
|
802
823
|
}
|
|
803
824
|
if (!this._isOptional) {
|
|
804
|
-
cursor.recordErrorAt(
|
|
825
|
+
cursor.recordErrorAt(this._firstIndex, this);
|
|
805
826
|
return null;
|
|
806
827
|
}
|
|
807
828
|
cursor.resolveError();
|
|
@@ -809,63 +830,250 @@ class Literal {
|
|
|
809
830
|
return null;
|
|
810
831
|
}
|
|
811
832
|
_tryToParse(cursor) {
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
if (literalRune !== cursorRune) {
|
|
818
|
-
break;
|
|
833
|
+
for (const pattern of this._children) {
|
|
834
|
+
cursor.moveTo(this._firstIndex);
|
|
835
|
+
const result = pattern.parse(cursor);
|
|
836
|
+
if (!cursor.hasError) {
|
|
837
|
+
return result;
|
|
819
838
|
}
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
839
|
+
cursor.resolveError();
|
|
840
|
+
}
|
|
841
|
+
return null;
|
|
842
|
+
}
|
|
843
|
+
getTokens() {
|
|
844
|
+
const tokens = [];
|
|
845
|
+
for (const child of this._children) {
|
|
846
|
+
tokens.push(...child.getTokens());
|
|
847
|
+
}
|
|
848
|
+
return tokens;
|
|
849
|
+
}
|
|
850
|
+
getTokensAfter(_childReference) {
|
|
851
|
+
if (this._parent === null) {
|
|
852
|
+
return [];
|
|
853
|
+
}
|
|
854
|
+
return this._parent.getTokensAfter(this);
|
|
855
|
+
}
|
|
856
|
+
getNextTokens() {
|
|
857
|
+
if (this._parent == null) {
|
|
858
|
+
return [];
|
|
859
|
+
}
|
|
860
|
+
return this._parent.getTokensAfter(this);
|
|
861
|
+
}
|
|
862
|
+
getPatterns() {
|
|
863
|
+
const patterns = [];
|
|
864
|
+
for (const pattern of this._children) {
|
|
865
|
+
patterns.push(...pattern.getPatterns());
|
|
866
|
+
}
|
|
867
|
+
return patterns;
|
|
868
|
+
}
|
|
869
|
+
getPatternsAfter(_childReference) {
|
|
870
|
+
if (this._parent === null) {
|
|
871
|
+
return [];
|
|
872
|
+
}
|
|
873
|
+
return this._parent.getPatternsAfter(this);
|
|
874
|
+
}
|
|
875
|
+
getNextPatterns() {
|
|
876
|
+
if (this.parent == null) {
|
|
877
|
+
return [];
|
|
878
|
+
}
|
|
879
|
+
return this.parent.getPatternsAfter(this);
|
|
880
|
+
}
|
|
881
|
+
find(predicate) {
|
|
882
|
+
return findPattern(this, predicate);
|
|
883
|
+
}
|
|
884
|
+
clone(name = this._name, isOptional = this._isOptional) {
|
|
885
|
+
const or = new Or(name, this._children, isOptional);
|
|
886
|
+
return or;
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
class FiniteRepeat {
|
|
891
|
+
constructor(name, pattern, repeatAmount, options = {}) {
|
|
892
|
+
this._type = "finite-repeat";
|
|
893
|
+
this._name = name;
|
|
894
|
+
this._parent = null;
|
|
895
|
+
this._children = [];
|
|
896
|
+
this._hasDivider = options.divider != null;
|
|
897
|
+
this._min = options.min != null ? options.min : 1;
|
|
898
|
+
this._max = repeatAmount;
|
|
899
|
+
this._trimDivider = options.trimDivider == null ? false : options.trimDivider;
|
|
900
|
+
for (let i = 0; i < repeatAmount; i++) {
|
|
901
|
+
this._children.push(pattern.clone(pattern.name));
|
|
902
|
+
if (options.divider != null && (i < repeatAmount - 1 || !this._trimDivider)) {
|
|
903
|
+
this._children.push(options.divider.clone(options.divider.name, false));
|
|
824
904
|
}
|
|
825
|
-
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
get type() {
|
|
908
|
+
return this._type;
|
|
909
|
+
}
|
|
910
|
+
get name() {
|
|
911
|
+
return this._name;
|
|
912
|
+
}
|
|
913
|
+
get parent() {
|
|
914
|
+
return this._parent;
|
|
915
|
+
}
|
|
916
|
+
set parent(value) {
|
|
917
|
+
this._parent = value;
|
|
918
|
+
}
|
|
919
|
+
get children() {
|
|
920
|
+
return this._children;
|
|
921
|
+
}
|
|
922
|
+
get isOptional() {
|
|
923
|
+
return this._min === 0;
|
|
924
|
+
}
|
|
925
|
+
get min() {
|
|
926
|
+
return this._min;
|
|
927
|
+
}
|
|
928
|
+
get max() {
|
|
929
|
+
return this._max;
|
|
930
|
+
}
|
|
931
|
+
parse(cursor) {
|
|
932
|
+
const startIndex = cursor.index;
|
|
933
|
+
const nodes = [];
|
|
934
|
+
const modulo = this._hasDivider ? 2 : 1;
|
|
935
|
+
let matchCount = 0;
|
|
936
|
+
for (let i = 0; i < this._children.length; i++) {
|
|
937
|
+
const childPattern = this._children[i];
|
|
938
|
+
const node = childPattern.parse(cursor);
|
|
939
|
+
if (i % modulo === 0 && !cursor.hasError) {
|
|
940
|
+
matchCount++;
|
|
941
|
+
}
|
|
942
|
+
if (cursor.hasError) {
|
|
943
|
+
cursor.resolveError();
|
|
826
944
|
break;
|
|
827
945
|
}
|
|
828
|
-
|
|
946
|
+
if (node != null) {
|
|
947
|
+
nodes.push(node);
|
|
948
|
+
if (cursor.hasNext()) {
|
|
949
|
+
cursor.next();
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
break;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
829
955
|
}
|
|
830
|
-
|
|
956
|
+
if (this._trimDivider && this._hasDivider) {
|
|
957
|
+
if (cursor.leafMatch.pattern === this.children[1]) {
|
|
958
|
+
const node = nodes.pop();
|
|
959
|
+
cursor.moveTo(node.firstIndex);
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
if (matchCount < this._min) {
|
|
963
|
+
cursor.moveTo(startIndex);
|
|
964
|
+
cursor.recordErrorAt(startIndex, this);
|
|
965
|
+
return null;
|
|
966
|
+
}
|
|
967
|
+
else if (nodes.length === 0) {
|
|
968
|
+
cursor.resolveError();
|
|
969
|
+
cursor.moveTo(startIndex);
|
|
970
|
+
return null;
|
|
971
|
+
}
|
|
972
|
+
const firstIndex = nodes[0].firstIndex;
|
|
973
|
+
const lastIndex = nodes[nodes.length - 1].lastIndex;
|
|
974
|
+
cursor.moveTo(lastIndex);
|
|
975
|
+
return new Node(this._type, this.name, firstIndex, lastIndex, nodes);
|
|
831
976
|
}
|
|
832
|
-
|
|
833
|
-
|
|
977
|
+
test(text) {
|
|
978
|
+
const cursor = new Cursor(text);
|
|
979
|
+
const ast = this.parse(cursor);
|
|
980
|
+
return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
|
|
834
981
|
}
|
|
835
|
-
|
|
836
|
-
const
|
|
837
|
-
|
|
982
|
+
exec(text) {
|
|
983
|
+
const cursor = new Cursor(text);
|
|
984
|
+
const ast = this.parse(cursor);
|
|
985
|
+
return {
|
|
986
|
+
ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
|
|
987
|
+
cursor
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
clone(name = this._name, isOptional) {
|
|
991
|
+
let min = this._min;
|
|
992
|
+
if (isOptional != null) {
|
|
993
|
+
if (isOptional) {
|
|
994
|
+
min = 0;
|
|
995
|
+
}
|
|
996
|
+
else {
|
|
997
|
+
min = Math.max(this._min, 1);
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
return new FiniteRepeat(name, this._children[0], this._max, {
|
|
1001
|
+
divider: this._hasDivider ? this._children[1] : undefined,
|
|
1002
|
+
min,
|
|
1003
|
+
trimDivider: this._trimDivider
|
|
1004
|
+
});
|
|
838
1005
|
}
|
|
839
1006
|
getTokens() {
|
|
840
|
-
return
|
|
1007
|
+
return this._children[0].getTokens();
|
|
841
1008
|
}
|
|
842
|
-
getTokensAfter(
|
|
843
|
-
|
|
1009
|
+
getTokensAfter(childReference) {
|
|
1010
|
+
const patterns = this.getPatternsAfter(childReference);
|
|
1011
|
+
const tokens = [];
|
|
1012
|
+
patterns.forEach(p => tokens.push(...p.getTokens()));
|
|
1013
|
+
return tokens;
|
|
844
1014
|
}
|
|
845
1015
|
getNextTokens() {
|
|
846
|
-
if (this.
|
|
1016
|
+
if (this._parent == null) {
|
|
847
1017
|
return [];
|
|
848
1018
|
}
|
|
849
|
-
return this.
|
|
1019
|
+
return this._parent.getTokensAfter(this);
|
|
850
1020
|
}
|
|
851
1021
|
getPatterns() {
|
|
852
|
-
return [
|
|
1022
|
+
return this._children[0].getPatterns();
|
|
853
1023
|
}
|
|
854
|
-
getPatternsAfter() {
|
|
855
|
-
|
|
1024
|
+
getPatternsAfter(childReference) {
|
|
1025
|
+
const childIndex = this._children.indexOf(childReference);
|
|
1026
|
+
// If Reference Pattern isn't a child.
|
|
1027
|
+
if (childIndex == -1) {
|
|
1028
|
+
return [];
|
|
1029
|
+
}
|
|
1030
|
+
// If Reference Pattern is the last pattern. Ask for the parents next patterns
|
|
1031
|
+
if (childIndex === this._children.length - 1) {
|
|
1032
|
+
if (this._parent == null) {
|
|
1033
|
+
return [];
|
|
1034
|
+
}
|
|
1035
|
+
else {
|
|
1036
|
+
return this._parent.getPatternsAfter(this);
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
// Get the next childs patterns.
|
|
1040
|
+
const nextChild = this._children[childIndex + 1];
|
|
1041
|
+
return nextChild.getPatterns();
|
|
856
1042
|
}
|
|
857
1043
|
getNextPatterns() {
|
|
858
|
-
if (this.
|
|
1044
|
+
if (this._parent == null) {
|
|
859
1045
|
return [];
|
|
860
1046
|
}
|
|
861
|
-
return this.
|
|
1047
|
+
return this._parent.getPatternsAfter(this);
|
|
862
1048
|
}
|
|
863
|
-
|
|
864
|
-
return
|
|
1049
|
+
find(predicate) {
|
|
1050
|
+
return findPattern(this, predicate);
|
|
865
1051
|
}
|
|
866
1052
|
}
|
|
867
1053
|
|
|
868
|
-
class
|
|
1054
|
+
class InfiniteRepeat {
|
|
1055
|
+
constructor(name, pattern, options = {}) {
|
|
1056
|
+
const min = options.min != null ? options.min : 1;
|
|
1057
|
+
const divider = options.divider;
|
|
1058
|
+
let children;
|
|
1059
|
+
if (divider != null) {
|
|
1060
|
+
children = [pattern.clone(), divider.clone(divider.name, false)];
|
|
1061
|
+
}
|
|
1062
|
+
else {
|
|
1063
|
+
children = [pattern.clone()];
|
|
1064
|
+
}
|
|
1065
|
+
this._assignChildrenToParent(children);
|
|
1066
|
+
this._type = "infinite-repeat";
|
|
1067
|
+
this._name = name;
|
|
1068
|
+
this._min = min;
|
|
1069
|
+
this._parent = null;
|
|
1070
|
+
this._children = children;
|
|
1071
|
+
this._pattern = children[0];
|
|
1072
|
+
this._divider = children[1];
|
|
1073
|
+
this._firstIndex = -1;
|
|
1074
|
+
this._nodes = [];
|
|
1075
|
+
this._trimDivider = options.trimDivider == null ? false : options.trimDivider;
|
|
1076
|
+
}
|
|
869
1077
|
get type() {
|
|
870
1078
|
return this._type;
|
|
871
1079
|
}
|
|
@@ -882,172 +1090,260 @@ class Not {
|
|
|
882
1090
|
return this._children;
|
|
883
1091
|
}
|
|
884
1092
|
get isOptional() {
|
|
885
|
-
return
|
|
1093
|
+
return this._min === 0;
|
|
886
1094
|
}
|
|
887
|
-
|
|
888
|
-
this.
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
1095
|
+
get min() {
|
|
1096
|
+
return this._min;
|
|
1097
|
+
}
|
|
1098
|
+
_assignChildrenToParent(children) {
|
|
1099
|
+
for (const child of children) {
|
|
1100
|
+
child.parent = this;
|
|
1101
|
+
}
|
|
893
1102
|
}
|
|
894
1103
|
test(text) {
|
|
895
1104
|
const cursor = new Cursor(text);
|
|
896
|
-
this.parse(cursor);
|
|
897
|
-
return
|
|
1105
|
+
const ast = this.parse(cursor);
|
|
1106
|
+
return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
|
|
898
1107
|
}
|
|
899
1108
|
exec(text) {
|
|
900
1109
|
const cursor = new Cursor(text);
|
|
901
1110
|
const ast = this.parse(cursor);
|
|
902
1111
|
return {
|
|
903
|
-
ast,
|
|
1112
|
+
ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
|
|
904
1113
|
cursor
|
|
905
1114
|
};
|
|
906
1115
|
}
|
|
907
1116
|
parse(cursor) {
|
|
908
|
-
|
|
909
|
-
this.
|
|
910
|
-
|
|
1117
|
+
this._firstIndex = cursor.index;
|
|
1118
|
+
this._nodes = [];
|
|
1119
|
+
const passed = this._tryToParse(cursor);
|
|
1120
|
+
if (passed) {
|
|
911
1121
|
cursor.resolveError();
|
|
912
|
-
|
|
1122
|
+
const node = this._createNode(cursor);
|
|
1123
|
+
if (node != null) {
|
|
1124
|
+
cursor.moveTo(node.lastIndex);
|
|
1125
|
+
cursor.recordMatch(this, node);
|
|
1126
|
+
}
|
|
1127
|
+
return node;
|
|
913
1128
|
}
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
cursor.resolveError();
|
|
917
|
-
cursor.recordErrorAt(firstIndex, this);
|
|
1129
|
+
if (this._min > 0) {
|
|
1130
|
+
return null;
|
|
918
1131
|
}
|
|
1132
|
+
cursor.resolveError();
|
|
919
1133
|
return null;
|
|
920
1134
|
}
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1135
|
+
_meetsMin() {
|
|
1136
|
+
if (this._divider != null) {
|
|
1137
|
+
return Math.ceil(this._nodes.length / 2) >= this._min;
|
|
1138
|
+
}
|
|
1139
|
+
return this._nodes.length >= this._min;
|
|
1140
|
+
}
|
|
1141
|
+
_tryToParse(cursor) {
|
|
1142
|
+
let passed = false;
|
|
1143
|
+
while (true) {
|
|
1144
|
+
const runningCursorIndex = cursor.index;
|
|
1145
|
+
const repeatedNode = this._pattern.parse(cursor);
|
|
1146
|
+
if (cursor.hasError) {
|
|
1147
|
+
const lastValidNode = this._getLastValidNode();
|
|
1148
|
+
if (lastValidNode != null) {
|
|
1149
|
+
passed = true;
|
|
1150
|
+
}
|
|
1151
|
+
else {
|
|
1152
|
+
cursor.moveTo(runningCursorIndex);
|
|
1153
|
+
cursor.recordErrorAt(runningCursorIndex, this._pattern);
|
|
1154
|
+
passed = false;
|
|
1155
|
+
}
|
|
1156
|
+
break;
|
|
1157
|
+
}
|
|
1158
|
+
else {
|
|
1159
|
+
if (repeatedNode != null) {
|
|
1160
|
+
this._nodes.push(repeatedNode);
|
|
1161
|
+
if (!cursor.hasNext()) {
|
|
1162
|
+
passed = true;
|
|
1163
|
+
break;
|
|
1164
|
+
}
|
|
1165
|
+
cursor.next();
|
|
1166
|
+
}
|
|
1167
|
+
if (this._divider != null) {
|
|
1168
|
+
const dividerNode = this._divider.parse(cursor);
|
|
1169
|
+
if (cursor.hasError) {
|
|
1170
|
+
passed = true;
|
|
1171
|
+
break;
|
|
1172
|
+
}
|
|
1173
|
+
else if (dividerNode != null) {
|
|
1174
|
+
this._nodes.push(dividerNode);
|
|
1175
|
+
if (!cursor.hasNext()) {
|
|
1176
|
+
passed = true;
|
|
1177
|
+
break;
|
|
1178
|
+
}
|
|
1179
|
+
cursor.next();
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
const hasMinimum = this._meetsMin();
|
|
1185
|
+
if (hasMinimum) {
|
|
1186
|
+
return passed;
|
|
1187
|
+
}
|
|
1188
|
+
else if (!hasMinimum && passed) {
|
|
1189
|
+
cursor.recordErrorAt(cursor.index, this);
|
|
1190
|
+
cursor.moveTo(this._firstIndex);
|
|
1191
|
+
return false;
|
|
1192
|
+
}
|
|
1193
|
+
return passed;
|
|
924
1194
|
}
|
|
925
|
-
|
|
926
|
-
const
|
|
927
|
-
if (
|
|
928
|
-
|
|
1195
|
+
_createNode(cursor) {
|
|
1196
|
+
const hasDivider = this._divider != null;
|
|
1197
|
+
if (hasDivider &&
|
|
1198
|
+
this._trimDivider &&
|
|
1199
|
+
cursor.leafMatch.pattern === this._divider) {
|
|
1200
|
+
const dividerNode = this._nodes.pop();
|
|
1201
|
+
cursor.moveTo(dividerNode.firstIndex);
|
|
929
1202
|
}
|
|
930
|
-
|
|
1203
|
+
const lastIndex = this._nodes[this._nodes.length - 1].lastIndex;
|
|
1204
|
+
cursor.moveTo(lastIndex);
|
|
1205
|
+
return new Node(this._type, this._name, this._firstIndex, lastIndex, this._nodes);
|
|
931
1206
|
}
|
|
932
|
-
|
|
933
|
-
const
|
|
934
|
-
if (
|
|
935
|
-
return
|
|
1207
|
+
_getLastValidNode() {
|
|
1208
|
+
const nodes = this._nodes.filter((node) => node !== null);
|
|
1209
|
+
if (nodes.length === 0) {
|
|
1210
|
+
return null;
|
|
936
1211
|
}
|
|
937
|
-
return [];
|
|
1212
|
+
return nodes[nodes.length - 1];
|
|
1213
|
+
}
|
|
1214
|
+
getTokens() {
|
|
1215
|
+
return this._pattern.getTokens();
|
|
1216
|
+
}
|
|
1217
|
+
getTokensAfter(childReference) {
|
|
1218
|
+
const patterns = this.getPatternsAfter(childReference);
|
|
1219
|
+
const tokens = [];
|
|
1220
|
+
patterns.forEach(p => tokens.push(...p.getTokens()));
|
|
1221
|
+
return tokens;
|
|
938
1222
|
}
|
|
939
1223
|
getNextTokens() {
|
|
940
|
-
if (this.
|
|
1224
|
+
if (this._parent == null) {
|
|
941
1225
|
return [];
|
|
942
1226
|
}
|
|
943
|
-
return this.
|
|
1227
|
+
return this._parent.getTokensAfter(this);
|
|
944
1228
|
}
|
|
945
1229
|
getPatterns() {
|
|
946
|
-
return
|
|
1230
|
+
return this._pattern.getPatterns();
|
|
947
1231
|
}
|
|
948
|
-
getPatternsAfter(
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
1232
|
+
getPatternsAfter(childReference) {
|
|
1233
|
+
let index = -1;
|
|
1234
|
+
const patterns = [];
|
|
1235
|
+
for (let i = 0; i < this._children.length; i++) {
|
|
1236
|
+
if (this._children[i] === childReference) {
|
|
1237
|
+
index = i;
|
|
1238
|
+
}
|
|
952
1239
|
}
|
|
953
|
-
|
|
1240
|
+
// If the last match isn't a child of this pattern.
|
|
1241
|
+
if (index === -1) {
|
|
1242
|
+
return [];
|
|
1243
|
+
}
|
|
1244
|
+
// If the last match was the repeated patterns, then suggest the divider.
|
|
1245
|
+
if (index === 0 && this._divider) {
|
|
1246
|
+
patterns.push(this._children[1]);
|
|
1247
|
+
if (this._parent) {
|
|
1248
|
+
patterns.push(...this._parent.getPatternsAfter(this));
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
// Suggest the pattern because the divider was the last match.
|
|
1252
|
+
if (index === 1) {
|
|
1253
|
+
patterns.push(this._children[0]);
|
|
1254
|
+
}
|
|
1255
|
+
// If there is no divider then suggest the repeating pattern and the next pattern after.
|
|
1256
|
+
if (index === 0 && !this._divider && this._parent) {
|
|
1257
|
+
patterns.push(this._children[0]);
|
|
1258
|
+
patterns.push(...this._parent.getPatternsAfter(this));
|
|
1259
|
+
}
|
|
1260
|
+
return patterns;
|
|
954
1261
|
}
|
|
955
1262
|
getNextPatterns() {
|
|
956
|
-
if (this.
|
|
1263
|
+
if (this._parent == null) {
|
|
957
1264
|
return [];
|
|
958
1265
|
}
|
|
959
|
-
return this.
|
|
1266
|
+
return this._parent.getPatternsAfter(this);
|
|
960
1267
|
}
|
|
961
|
-
|
|
962
|
-
return
|
|
1268
|
+
find(predicate) {
|
|
1269
|
+
return findPattern(this, predicate);
|
|
1270
|
+
}
|
|
1271
|
+
clone(name = this._name, isOptional) {
|
|
1272
|
+
let min = this._min;
|
|
1273
|
+
if (isOptional != null) {
|
|
1274
|
+
if (isOptional) {
|
|
1275
|
+
min = 0;
|
|
1276
|
+
}
|
|
1277
|
+
else {
|
|
1278
|
+
min = Math.max(this._min, 1);
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
return new InfiniteRepeat(name, this._pattern, {
|
|
1282
|
+
divider: this._divider == null ? undefined : this._divider,
|
|
1283
|
+
min: min,
|
|
1284
|
+
trimDivider: this._trimDivider
|
|
1285
|
+
});
|
|
963
1286
|
}
|
|
964
1287
|
}
|
|
965
1288
|
|
|
966
|
-
class
|
|
1289
|
+
class Repeat {
|
|
1290
|
+
constructor(name, pattern, options = {}) {
|
|
1291
|
+
this._pattern = pattern;
|
|
1292
|
+
this._parent = null;
|
|
1293
|
+
this._options = Object.assign(Object.assign({}, options), { min: options.min == null ? 1 : options.min, max: options.max == null ? Infinity : options.max });
|
|
1294
|
+
if (this._options.max != Infinity) {
|
|
1295
|
+
this._repeatPattern = new FiniteRepeat(name, pattern, this._options.max, this._options);
|
|
1296
|
+
}
|
|
1297
|
+
else {
|
|
1298
|
+
this._repeatPattern = new InfiniteRepeat(name, pattern, this._options);
|
|
1299
|
+
}
|
|
1300
|
+
this._children = [this._repeatPattern];
|
|
1301
|
+
this._repeatPattern.parent = this;
|
|
1302
|
+
}
|
|
967
1303
|
get type() {
|
|
968
|
-
return this.
|
|
1304
|
+
return this._repeatPattern.type;
|
|
969
1305
|
}
|
|
970
1306
|
get name() {
|
|
971
|
-
return this.
|
|
1307
|
+
return this._repeatPattern.name;
|
|
972
1308
|
}
|
|
973
1309
|
get parent() {
|
|
974
1310
|
return this._parent;
|
|
975
1311
|
}
|
|
976
|
-
set parent(
|
|
977
|
-
this._parent =
|
|
1312
|
+
set parent(value) {
|
|
1313
|
+
this._parent = value;
|
|
978
1314
|
}
|
|
979
1315
|
get children() {
|
|
980
1316
|
return this._children;
|
|
981
1317
|
}
|
|
982
1318
|
get isOptional() {
|
|
983
|
-
return this.
|
|
984
|
-
}
|
|
985
|
-
constructor(name, options, isOptional = false) {
|
|
986
|
-
if (options.length === 0) {
|
|
987
|
-
throw new Error("Need at least one pattern with an 'or' pattern.");
|
|
988
|
-
}
|
|
989
|
-
const children = clonePatterns(options, false);
|
|
990
|
-
this._assignChildrenToParent(children);
|
|
991
|
-
this._type = "or";
|
|
992
|
-
this._name = name;
|
|
993
|
-
this._parent = null;
|
|
994
|
-
this._children = children;
|
|
995
|
-
this._isOptional = isOptional;
|
|
996
|
-
this._firstIndex = 0;
|
|
997
|
-
}
|
|
998
|
-
_assignChildrenToParent(children) {
|
|
999
|
-
for (const child of children) {
|
|
1000
|
-
child.parent = this;
|
|
1001
|
-
}
|
|
1319
|
+
return this._repeatPattern.isOptional;
|
|
1002
1320
|
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
const ast = this.parse(cursor);
|
|
1006
|
-
return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
|
|
1321
|
+
parse(cursor) {
|
|
1322
|
+
return this._repeatPattern.parse(cursor);
|
|
1007
1323
|
}
|
|
1008
1324
|
exec(text) {
|
|
1009
|
-
|
|
1010
|
-
const ast = this.parse(cursor);
|
|
1011
|
-
return {
|
|
1012
|
-
ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
|
|
1013
|
-
cursor
|
|
1014
|
-
};
|
|
1325
|
+
return this._repeatPattern.exec(text);
|
|
1015
1326
|
}
|
|
1016
|
-
|
|
1017
|
-
this.
|
|
1018
|
-
const node = this._tryToParse(cursor);
|
|
1019
|
-
if (node != null) {
|
|
1020
|
-
cursor.resolveError();
|
|
1021
|
-
return node;
|
|
1022
|
-
}
|
|
1023
|
-
if (!this._isOptional) {
|
|
1024
|
-
cursor.recordErrorAt(this._firstIndex, this);
|
|
1025
|
-
return null;
|
|
1026
|
-
}
|
|
1027
|
-
cursor.resolveError();
|
|
1028
|
-
cursor.moveTo(this._firstIndex);
|
|
1029
|
-
return null;
|
|
1327
|
+
test(text) {
|
|
1328
|
+
return this._repeatPattern.test(text);
|
|
1030
1329
|
}
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1330
|
+
clone(name = this.name, isOptional) {
|
|
1331
|
+
let min = this._options.min;
|
|
1332
|
+
if (isOptional != null) {
|
|
1333
|
+
if (isOptional) {
|
|
1334
|
+
min = 0;
|
|
1335
|
+
}
|
|
1336
|
+
else {
|
|
1337
|
+
min = Math.max(this._options.min, 1);
|
|
1037
1338
|
}
|
|
1038
|
-
cursor.resolveError();
|
|
1039
1339
|
}
|
|
1040
|
-
return
|
|
1340
|
+
return new Repeat(name, this._pattern, Object.assign(Object.assign({}, this._options), { min }));
|
|
1041
1341
|
}
|
|
1042
1342
|
getTokens() {
|
|
1043
|
-
|
|
1044
|
-
for (const child of this._children) {
|
|
1045
|
-
tokens.push(...child.getTokens());
|
|
1046
|
-
}
|
|
1047
|
-
return tokens;
|
|
1343
|
+
return this._repeatPattern.getTokens();
|
|
1048
1344
|
}
|
|
1049
1345
|
getTokensAfter(_childReference) {
|
|
1050
|
-
if (this._parent
|
|
1346
|
+
if (this._parent == null) {
|
|
1051
1347
|
return [];
|
|
1052
1348
|
}
|
|
1053
1349
|
return this._parent.getTokensAfter(this);
|
|
@@ -1059,34 +1355,52 @@ class Or {
|
|
|
1059
1355
|
return this._parent.getTokensAfter(this);
|
|
1060
1356
|
}
|
|
1061
1357
|
getPatterns() {
|
|
1062
|
-
|
|
1063
|
-
for (const pattern of this._children) {
|
|
1064
|
-
patterns.push(...pattern.getPatterns());
|
|
1065
|
-
}
|
|
1066
|
-
return patterns;
|
|
1358
|
+
return this._repeatPattern.getPatterns();
|
|
1067
1359
|
}
|
|
1068
1360
|
getPatternsAfter(_childReference) {
|
|
1069
|
-
if (this._parent
|
|
1361
|
+
if (this._parent == null) {
|
|
1070
1362
|
return [];
|
|
1071
1363
|
}
|
|
1072
1364
|
return this._parent.getPatternsAfter(this);
|
|
1073
1365
|
}
|
|
1074
1366
|
getNextPatterns() {
|
|
1075
|
-
if (this.
|
|
1367
|
+
if (this._parent == null) {
|
|
1076
1368
|
return [];
|
|
1077
1369
|
}
|
|
1078
|
-
return this.
|
|
1370
|
+
return this._parent.getPatternsAfter(this);
|
|
1079
1371
|
}
|
|
1080
|
-
|
|
1081
|
-
return
|
|
1372
|
+
find(predicate) {
|
|
1373
|
+
return this._repeatPattern.find(predicate);
|
|
1082
1374
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
const comment = new Regex("comment", "#[^\r\n]+");
|
|
1378
|
+
|
|
1379
|
+
function filterOutNull(nodes) {
|
|
1380
|
+
const filteredNodes = [];
|
|
1381
|
+
for (const node of nodes) {
|
|
1382
|
+
if (node !== null) {
|
|
1383
|
+
filteredNodes.push(node);
|
|
1384
|
+
}
|
|
1086
1385
|
}
|
|
1386
|
+
return filteredNodes;
|
|
1087
1387
|
}
|
|
1088
1388
|
|
|
1089
|
-
class
|
|
1389
|
+
class And {
|
|
1390
|
+
constructor(name, sequence, isOptional = false) {
|
|
1391
|
+
if (sequence.length === 0) {
|
|
1392
|
+
throw new Error("Need at least one pattern with an 'and' pattern.");
|
|
1393
|
+
}
|
|
1394
|
+
const children = clonePatterns(sequence);
|
|
1395
|
+
this._assignChildrenToParent(children);
|
|
1396
|
+
this._type = "and";
|
|
1397
|
+
this._name = name;
|
|
1398
|
+
this._isOptional = isOptional;
|
|
1399
|
+
this._parent = null;
|
|
1400
|
+
this._children = children;
|
|
1401
|
+
this._firstIndex = -1;
|
|
1402
|
+
this._nodes = [];
|
|
1403
|
+
}
|
|
1090
1404
|
get type() {
|
|
1091
1405
|
return this._type;
|
|
1092
1406
|
}
|
|
@@ -1105,20 +1419,6 @@ class Repeat {
|
|
|
1105
1419
|
get isOptional() {
|
|
1106
1420
|
return this._isOptional;
|
|
1107
1421
|
}
|
|
1108
|
-
constructor(name, pattern, divider, isOptional = false) {
|
|
1109
|
-
const patterns = divider != null ? [pattern, divider] : [pattern];
|
|
1110
|
-
const children = clonePatterns(patterns, false);
|
|
1111
|
-
this._assignChildrenToParent(children);
|
|
1112
|
-
this._type = "repeat";
|
|
1113
|
-
this._name = name;
|
|
1114
|
-
this._isOptional = isOptional;
|
|
1115
|
-
this._parent = null;
|
|
1116
|
-
this._children = children;
|
|
1117
|
-
this._pattern = children[0];
|
|
1118
|
-
this._divider = children[1];
|
|
1119
|
-
this._firstIndex = -1;
|
|
1120
|
-
this._nodes = [];
|
|
1121
|
-
}
|
|
1122
1422
|
_assignChildrenToParent(children) {
|
|
1123
1423
|
for (const child of children) {
|
|
1124
1424
|
child.parent = this;
|
|
@@ -1142,92 +1442,108 @@ class Repeat {
|
|
|
1142
1442
|
this._nodes = [];
|
|
1143
1443
|
const passed = this.tryToParse(cursor);
|
|
1144
1444
|
if (passed) {
|
|
1145
|
-
cursor.resolveError();
|
|
1146
1445
|
const node = this.createNode(cursor);
|
|
1147
|
-
if (node
|
|
1446
|
+
if (node !== null) {
|
|
1148
1447
|
cursor.recordMatch(this, node);
|
|
1149
1448
|
}
|
|
1150
1449
|
return node;
|
|
1151
1450
|
}
|
|
1152
|
-
if (
|
|
1153
|
-
|
|
1451
|
+
if (this._isOptional) {
|
|
1452
|
+
cursor.resolveError();
|
|
1154
1453
|
}
|
|
1155
|
-
cursor.resolveError();
|
|
1156
|
-
cursor.moveTo(this._firstIndex);
|
|
1157
1454
|
return null;
|
|
1158
1455
|
}
|
|
1159
1456
|
tryToParse(cursor) {
|
|
1160
1457
|
let passed = false;
|
|
1161
|
-
|
|
1458
|
+
for (let i = 0; i < this._children.length; i++) {
|
|
1162
1459
|
const runningCursorIndex = cursor.index;
|
|
1163
|
-
const
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
passed = true;
|
|
1187
|
-
break;
|
|
1188
|
-
}
|
|
1189
|
-
else if (dividerNode != null) {
|
|
1190
|
-
this._nodes.push(dividerNode);
|
|
1191
|
-
if (!cursor.hasNext()) {
|
|
1192
|
-
passed = true;
|
|
1460
|
+
const nextPatternIndex = i + 1;
|
|
1461
|
+
const hasMorePatterns = nextPatternIndex < this._children.length;
|
|
1462
|
+
const node = this._children[i].parse(cursor);
|
|
1463
|
+
const hasNoError = !cursor.hasError;
|
|
1464
|
+
const hadMatch = node !== null;
|
|
1465
|
+
if (hasNoError) {
|
|
1466
|
+
this._nodes.push(node);
|
|
1467
|
+
if (hasMorePatterns) {
|
|
1468
|
+
if (hadMatch) {
|
|
1469
|
+
if (cursor.hasNext()) {
|
|
1470
|
+
// We had a match. Increment the cursor and use the next pattern.
|
|
1471
|
+
cursor.next();
|
|
1472
|
+
continue;
|
|
1473
|
+
}
|
|
1474
|
+
else {
|
|
1475
|
+
// We are at the end of the text, it may still be valid, if all the
|
|
1476
|
+
// following patterns are optional.
|
|
1477
|
+
if (this.areRemainingPatternsOptional(i)) {
|
|
1478
|
+
passed = true;
|
|
1479
|
+
break;
|
|
1480
|
+
}
|
|
1481
|
+
// We didn't finish the parsing sequence.
|
|
1482
|
+
cursor.recordErrorAt(cursor.index + 1, this);
|
|
1193
1483
|
break;
|
|
1194
1484
|
}
|
|
1195
|
-
|
|
1485
|
+
}
|
|
1486
|
+
else {
|
|
1487
|
+
// An optional pattern did not matched, try from the same spot on the next
|
|
1488
|
+
// pattern.
|
|
1489
|
+
cursor.moveTo(runningCursorIndex);
|
|
1490
|
+
continue;
|
|
1196
1491
|
}
|
|
1197
1492
|
}
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
const dividerNode = this._nodes[this._nodes.length - 1];
|
|
1210
|
-
cursor.moveTo(dividerNode.firstIndex);
|
|
1211
|
-
children = this._nodes.slice(0, this._nodes.length - 1);
|
|
1493
|
+
else {
|
|
1494
|
+
// If we don't have any results from what we parsed then record error.
|
|
1495
|
+
const lastNode = this.getLastValidNode();
|
|
1496
|
+
if (lastNode === null) {
|
|
1497
|
+
cursor.recordErrorAt(cursor.index, this);
|
|
1498
|
+
break;
|
|
1499
|
+
}
|
|
1500
|
+
// The sequence was parsed fully.
|
|
1501
|
+
passed = true;
|
|
1502
|
+
break;
|
|
1503
|
+
}
|
|
1212
1504
|
}
|
|
1213
1505
|
else {
|
|
1214
|
-
|
|
1506
|
+
// The pattern failed.
|
|
1507
|
+
cursor.moveTo(this._firstIndex);
|
|
1508
|
+
break;
|
|
1215
1509
|
}
|
|
1216
1510
|
}
|
|
1217
|
-
|
|
1218
|
-
cursor.getChars(this._firstIndex, lastIndex);
|
|
1219
|
-
cursor.moveTo(lastIndex);
|
|
1220
|
-
return new Node("repeat", this._name, this._firstIndex, lastIndex, children, undefined);
|
|
1511
|
+
return passed;
|
|
1221
1512
|
}
|
|
1222
1513
|
getLastValidNode() {
|
|
1223
|
-
const nodes = this._nodes
|
|
1514
|
+
const nodes = filterOutNull(this._nodes);
|
|
1224
1515
|
if (nodes.length === 0) {
|
|
1225
1516
|
return null;
|
|
1226
1517
|
}
|
|
1227
1518
|
return nodes[nodes.length - 1];
|
|
1228
1519
|
}
|
|
1520
|
+
areRemainingPatternsOptional(fromIndex) {
|
|
1521
|
+
const startOnIndex = fromIndex + 1;
|
|
1522
|
+
const length = this._children.length;
|
|
1523
|
+
for (let i = startOnIndex; i < length; i++) {
|
|
1524
|
+
const pattern = this._children[i];
|
|
1525
|
+
if (!pattern.isOptional) {
|
|
1526
|
+
return false;
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
return true;
|
|
1530
|
+
}
|
|
1531
|
+
createNode(cursor) {
|
|
1532
|
+
const children = filterOutNull(this._nodes);
|
|
1533
|
+
const lastIndex = children[children.length - 1].lastIndex;
|
|
1534
|
+
cursor.getChars(this._firstIndex, lastIndex);
|
|
1535
|
+
cursor.moveTo(lastIndex);
|
|
1536
|
+
return new Node("and", this._name, this._firstIndex, lastIndex, children);
|
|
1537
|
+
}
|
|
1229
1538
|
getTokens() {
|
|
1230
|
-
|
|
1539
|
+
const tokens = [];
|
|
1540
|
+
for (const child of this._children) {
|
|
1541
|
+
tokens.push(...child.getTokens());
|
|
1542
|
+
if (!child.isOptional) {
|
|
1543
|
+
break;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
return tokens;
|
|
1231
1547
|
}
|
|
1232
1548
|
getTokensAfter(childReference) {
|
|
1233
1549
|
const patterns = this.getPatternsAfter(childReference);
|
|
@@ -1242,35 +1558,49 @@ class Repeat {
|
|
|
1242
1558
|
return this.parent.getTokensAfter(this);
|
|
1243
1559
|
}
|
|
1244
1560
|
getPatterns() {
|
|
1245
|
-
|
|
1561
|
+
const patterns = [];
|
|
1562
|
+
for (const pattern of this._children) {
|
|
1563
|
+
patterns.push(...pattern.getPatterns());
|
|
1564
|
+
if (!pattern.isOptional) {
|
|
1565
|
+
break;
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
return patterns;
|
|
1246
1569
|
}
|
|
1247
1570
|
getPatternsAfter(childReference) {
|
|
1248
|
-
let index = -1;
|
|
1249
1571
|
const patterns = [];
|
|
1572
|
+
let nextSiblingIndex = -1;
|
|
1573
|
+
let index = -1;
|
|
1250
1574
|
for (let i = 0; i < this._children.length; i++) {
|
|
1251
1575
|
if (this._children[i] === childReference) {
|
|
1576
|
+
if (i + 1 < this._children.length) {
|
|
1577
|
+
this._children[i + 1];
|
|
1578
|
+
}
|
|
1579
|
+
nextSiblingIndex = i + 1;
|
|
1252
1580
|
index = i;
|
|
1581
|
+
break;
|
|
1253
1582
|
}
|
|
1254
1583
|
}
|
|
1255
|
-
//
|
|
1584
|
+
// The child reference isn't one of the child patterns.
|
|
1256
1585
|
if (index === -1) {
|
|
1257
1586
|
return [];
|
|
1258
1587
|
}
|
|
1259
|
-
//
|
|
1260
|
-
if (
|
|
1261
|
-
|
|
1262
|
-
|
|
1588
|
+
// The reference pattern is the last child. So ask the parent for the next pattern.
|
|
1589
|
+
if (nextSiblingIndex === this._children.length && this._parent !== null) {
|
|
1590
|
+
return this._parent.getPatternsAfter(this);
|
|
1591
|
+
}
|
|
1592
|
+
// Send back as many optional patterns as possible.
|
|
1593
|
+
for (let i = nextSiblingIndex; i < this._children.length; i++) {
|
|
1594
|
+
const child = this._children[i];
|
|
1595
|
+
patterns.push(child);
|
|
1596
|
+
if (!child.isOptional) {
|
|
1597
|
+
break;
|
|
1598
|
+
}
|
|
1599
|
+
// If we are on the last child and its options then ask for the next pattern from the parent.
|
|
1600
|
+
if (i === this._children.length - 1 && this._parent !== null) {
|
|
1263
1601
|
patterns.push(...this._parent.getPatternsAfter(this));
|
|
1264
1602
|
}
|
|
1265
1603
|
}
|
|
1266
|
-
// Suggest the pattern because the divider was the last match.
|
|
1267
|
-
if (index === 1) {
|
|
1268
|
-
patterns.push(this._children[0]);
|
|
1269
|
-
}
|
|
1270
|
-
if (index === 0 && !this._divider && this._parent) {
|
|
1271
|
-
patterns.push(this._children[0]);
|
|
1272
|
-
patterns.push(...this._parent.getPatternsAfter(this));
|
|
1273
|
-
}
|
|
1274
1604
|
return patterns;
|
|
1275
1605
|
}
|
|
1276
1606
|
getNextPatterns() {
|
|
@@ -1279,15 +1609,138 @@ class Repeat {
|
|
|
1279
1609
|
}
|
|
1280
1610
|
return this.parent.getPatternsAfter(this);
|
|
1281
1611
|
}
|
|
1282
|
-
|
|
1612
|
+
find(predicate) {
|
|
1283
1613
|
return findPattern(this, predicate);
|
|
1284
1614
|
}
|
|
1285
1615
|
clone(name = this._name, isOptional = this._isOptional) {
|
|
1286
|
-
return new
|
|
1616
|
+
return new And(name, this._children, isOptional);
|
|
1287
1617
|
}
|
|
1288
1618
|
}
|
|
1289
1619
|
|
|
1290
|
-
|
|
1620
|
+
const name = new Regex("name", "[a-zA-Z_-]+[a-zA-Z0-9_-]*");
|
|
1621
|
+
|
|
1622
|
+
const optionalNot = new Literal("not", "!", true);
|
|
1623
|
+
const optionalIsOptional$1 = new Literal("is-optional", "?", true);
|
|
1624
|
+
const patternName$1 = name.clone("pattern-name");
|
|
1625
|
+
const pattern$1 = new And("pattern", [
|
|
1626
|
+
optionalNot,
|
|
1627
|
+
patternName$1,
|
|
1628
|
+
optionalIsOptional$1,
|
|
1629
|
+
]);
|
|
1630
|
+
|
|
1631
|
+
const divider$1 = new Regex("and-divider", "\\s*[&]\\s*");
|
|
1632
|
+
divider$1.setTokens([" & "]);
|
|
1633
|
+
const andLiteral = new Repeat("and-literal", pattern$1, { divider: divider$1, min: 2 });
|
|
1634
|
+
|
|
1635
|
+
const divider = new Regex("or-divider", "\\s*[|]\\s*");
|
|
1636
|
+
divider.setTokens([" | "]);
|
|
1637
|
+
const orLiteral = new Repeat("or-literal", name.clone("pattern-name"), { divider, min: 2 });
|
|
1638
|
+
|
|
1639
|
+
const regexLiteral = new Regex("regex-literal", "/(\\\\/|[^/\\n\\r])*/");
|
|
1640
|
+
|
|
1641
|
+
const spaces = new Regex("spaces", "[ \\t]+");
|
|
1642
|
+
spaces.setTokens([" "]);
|
|
1643
|
+
|
|
1644
|
+
const optionalIsOptional = new Literal("is-optional", "?", true);
|
|
1645
|
+
const patternName = name.clone("pattern-name");
|
|
1646
|
+
const pattern = new And("pattern", [
|
|
1647
|
+
patternName,
|
|
1648
|
+
optionalIsOptional,
|
|
1649
|
+
]);
|
|
1650
|
+
const optionalSpaces$1 = spaces.clone("optional-spaces", true);
|
|
1651
|
+
const dividerPattern = name.clone("divider-pattern");
|
|
1652
|
+
const openBracket = new Literal("open-bracket", "{");
|
|
1653
|
+
const closeBracket = new Literal("close-bracket", "}");
|
|
1654
|
+
const comma = new Literal("comma", ",");
|
|
1655
|
+
const integer = new Regex("integer", "([1-9][0-9]*)|0");
|
|
1656
|
+
integer.setTokens(["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]);
|
|
1657
|
+
const optionalInteger = integer.clone("integer", true);
|
|
1658
|
+
const bounds = new And("bounds", [
|
|
1659
|
+
openBracket,
|
|
1660
|
+
optionalSpaces$1,
|
|
1661
|
+
optionalInteger.clone("min"),
|
|
1662
|
+
optionalSpaces$1,
|
|
1663
|
+
comma,
|
|
1664
|
+
optionalSpaces$1,
|
|
1665
|
+
optionalInteger.clone("max"),
|
|
1666
|
+
optionalSpaces$1,
|
|
1667
|
+
closeBracket
|
|
1668
|
+
]);
|
|
1669
|
+
const exactCount = new And("exact-count", [
|
|
1670
|
+
openBracket,
|
|
1671
|
+
optionalSpaces$1,
|
|
1672
|
+
integer,
|
|
1673
|
+
optionalSpaces$1,
|
|
1674
|
+
closeBracket,
|
|
1675
|
+
]);
|
|
1676
|
+
const quantifierShorthand = new Regex("quantifier-shorthand", "\\*|\\+");
|
|
1677
|
+
quantifierShorthand.setTokens(["*", "+"]);
|
|
1678
|
+
const quantifier = new Or("quantifier", [
|
|
1679
|
+
quantifierShorthand,
|
|
1680
|
+
exactCount,
|
|
1681
|
+
bounds
|
|
1682
|
+
]);
|
|
1683
|
+
const optional = new Literal("is-optional", "?", true);
|
|
1684
|
+
const trimDivider = new Literal("trim-divider", "-t");
|
|
1685
|
+
const openParen = new Literal("open-paren", "(");
|
|
1686
|
+
const closeParen = new Literal("close-paren", ")");
|
|
1687
|
+
const dividerComma = new Regex("divider-comma", "\\s*,\\s*");
|
|
1688
|
+
dividerComma.setTokens([", "]);
|
|
1689
|
+
const repeatLiteral = new And("repeat-literal", [
|
|
1690
|
+
openParen,
|
|
1691
|
+
optionalSpaces$1,
|
|
1692
|
+
pattern,
|
|
1693
|
+
optional,
|
|
1694
|
+
new And("optional-divider-section", [dividerComma, dividerPattern], true),
|
|
1695
|
+
optionalSpaces$1,
|
|
1696
|
+
closeParen,
|
|
1697
|
+
new And("quantifier-section", [optionalSpaces$1, quantifier]),
|
|
1698
|
+
new And("optional-trim-divider-section", [spaces, trimDivider], true)
|
|
1699
|
+
]);
|
|
1700
|
+
|
|
1701
|
+
const literal = new Regex("literal", "\"(?:\\\\[\"\\\\]|[^\n\"\\\\])*\"");
|
|
1702
|
+
|
|
1703
|
+
const optionalSpaces = spaces.clone("optional-spaces", true);
|
|
1704
|
+
const assignOperator = new Literal("assign-operator", "=");
|
|
1705
|
+
const optionalComment = comment.clone("inline-comment", true);
|
|
1706
|
+
const statements = new Or("statements", [
|
|
1707
|
+
literal,
|
|
1708
|
+
regexLiteral,
|
|
1709
|
+
orLiteral,
|
|
1710
|
+
andLiteral,
|
|
1711
|
+
repeatLiteral,
|
|
1712
|
+
]);
|
|
1713
|
+
const statement = new And("statement", [
|
|
1714
|
+
optionalSpaces,
|
|
1715
|
+
name,
|
|
1716
|
+
optionalSpaces,
|
|
1717
|
+
assignOperator,
|
|
1718
|
+
optionalSpaces,
|
|
1719
|
+
statements,
|
|
1720
|
+
optionalSpaces,
|
|
1721
|
+
optionalComment,
|
|
1722
|
+
optionalSpaces,
|
|
1723
|
+
]);
|
|
1724
|
+
|
|
1725
|
+
const whitespace = new Regex("whitespace", "[ \\t]+");
|
|
1726
|
+
const newLine = new Regex("new-line", "(\\r?\\n)+");
|
|
1727
|
+
whitespace.setTokens([" "]);
|
|
1728
|
+
newLine.setTokens(["\n"]);
|
|
1729
|
+
const line = new Or("line", [
|
|
1730
|
+
comment,
|
|
1731
|
+
statement,
|
|
1732
|
+
whitespace
|
|
1733
|
+
], true);
|
|
1734
|
+
const grammar = new Repeat("grammar", line, { divider: newLine });
|
|
1735
|
+
|
|
1736
|
+
class Not {
|
|
1737
|
+
constructor(name, pattern) {
|
|
1738
|
+
this._type = "not";
|
|
1739
|
+
this._name = name;
|
|
1740
|
+
this._parent = null;
|
|
1741
|
+
this._children = [pattern.clone(pattern.name, false)];
|
|
1742
|
+
this._children[0].parent = this;
|
|
1743
|
+
}
|
|
1291
1744
|
get type() {
|
|
1292
1745
|
return this._type;
|
|
1293
1746
|
}
|
|
@@ -1304,72 +1757,52 @@ class Reference {
|
|
|
1304
1757
|
return this._children;
|
|
1305
1758
|
}
|
|
1306
1759
|
get isOptional() {
|
|
1307
|
-
return
|
|
1308
|
-
}
|
|
1309
|
-
constructor(name, isOptional = false) {
|
|
1310
|
-
this._type = "reference";
|
|
1311
|
-
this._name = name;
|
|
1312
|
-
this._parent = null;
|
|
1313
|
-
this._isOptional = isOptional;
|
|
1314
|
-
this._pattern = null;
|
|
1315
|
-
this._children = [];
|
|
1760
|
+
return false;
|
|
1316
1761
|
}
|
|
1317
1762
|
test(text) {
|
|
1318
1763
|
const cursor = new Cursor(text);
|
|
1319
|
-
|
|
1320
|
-
return
|
|
1764
|
+
this.parse(cursor);
|
|
1765
|
+
return !cursor.hasError;
|
|
1321
1766
|
}
|
|
1322
1767
|
exec(text) {
|
|
1323
1768
|
const cursor = new Cursor(text);
|
|
1324
1769
|
const ast = this.parse(cursor);
|
|
1325
1770
|
return {
|
|
1326
|
-
ast
|
|
1771
|
+
ast,
|
|
1327
1772
|
cursor
|
|
1328
1773
|
};
|
|
1329
1774
|
}
|
|
1330
1775
|
parse(cursor) {
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
if (pattern === null) {
|
|
1337
|
-
throw new Error(`Couldn't find '${this._name}' pattern within tree.`);
|
|
1338
|
-
}
|
|
1339
|
-
const clonedPattern = pattern.clone(this._name, this._isOptional);
|
|
1340
|
-
clonedPattern.parent = this;
|
|
1341
|
-
this._pattern = clonedPattern;
|
|
1342
|
-
this._children = [this._pattern];
|
|
1776
|
+
const firstIndex = cursor.index;
|
|
1777
|
+
this._children[0].parse(cursor);
|
|
1778
|
+
if (cursor.hasError) {
|
|
1779
|
+
cursor.resolveError();
|
|
1780
|
+
cursor.moveTo(firstIndex);
|
|
1343
1781
|
}
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
return findPattern(root, (pattern) => {
|
|
1349
|
-
return pattern.name === this._name && pattern.type !== "reference";
|
|
1350
|
-
});
|
|
1351
|
-
}
|
|
1352
|
-
_getRoot() {
|
|
1353
|
-
let node = this;
|
|
1354
|
-
while (true) {
|
|
1355
|
-
const parent = node.parent;
|
|
1356
|
-
if (parent == null) {
|
|
1357
|
-
break;
|
|
1358
|
-
}
|
|
1359
|
-
else {
|
|
1360
|
-
node = parent;
|
|
1361
|
-
}
|
|
1782
|
+
else {
|
|
1783
|
+
cursor.moveTo(firstIndex);
|
|
1784
|
+
cursor.resolveError();
|
|
1785
|
+
cursor.recordErrorAt(firstIndex, this);
|
|
1362
1786
|
}
|
|
1363
|
-
return
|
|
1787
|
+
return null;
|
|
1788
|
+
}
|
|
1789
|
+
clone(name = this._name) {
|
|
1790
|
+
const not = new Not(name, this._children[0]);
|
|
1791
|
+
return not;
|
|
1364
1792
|
}
|
|
1365
1793
|
getTokens() {
|
|
1366
|
-
|
|
1794
|
+
const parent = this._parent;
|
|
1795
|
+
if (parent != null) {
|
|
1796
|
+
return parent.getTokensAfter(this);
|
|
1797
|
+
}
|
|
1798
|
+
return [];
|
|
1367
1799
|
}
|
|
1368
|
-
getTokensAfter(
|
|
1369
|
-
|
|
1370
|
-
|
|
1800
|
+
getTokensAfter(_childReference) {
|
|
1801
|
+
const parent = this._parent;
|
|
1802
|
+
if (parent != null) {
|
|
1803
|
+
return parent.getTokensAfter(this);
|
|
1371
1804
|
}
|
|
1372
|
-
return
|
|
1805
|
+
return [];
|
|
1373
1806
|
}
|
|
1374
1807
|
getNextTokens() {
|
|
1375
1808
|
if (this.parent == null) {
|
|
@@ -1378,13 +1811,14 @@ class Reference {
|
|
|
1378
1811
|
return this.parent.getTokensAfter(this);
|
|
1379
1812
|
}
|
|
1380
1813
|
getPatterns() {
|
|
1381
|
-
return this.
|
|
1814
|
+
return [...this.getNextPatterns().map(p => p.getPatterns()).flat()];
|
|
1382
1815
|
}
|
|
1383
1816
|
getPatternsAfter(_childReference) {
|
|
1384
|
-
|
|
1385
|
-
|
|
1817
|
+
const parent = this._parent;
|
|
1818
|
+
if (parent != null) {
|
|
1819
|
+
return parent.getPatternsAfter(this);
|
|
1386
1820
|
}
|
|
1387
|
-
return
|
|
1821
|
+
return [];
|
|
1388
1822
|
}
|
|
1389
1823
|
getNextPatterns() {
|
|
1390
1824
|
if (this.parent == null) {
|
|
@@ -1392,11 +1826,8 @@ class Reference {
|
|
|
1392
1826
|
}
|
|
1393
1827
|
return this.parent.getPatternsAfter(this);
|
|
1394
1828
|
}
|
|
1395
|
-
|
|
1396
|
-
return null;
|
|
1397
|
-
}
|
|
1398
|
-
clone(name = this._name, isOptional = this._isOptional) {
|
|
1399
|
-
return new Reference(name, isOptional);
|
|
1829
|
+
find(predicate) {
|
|
1830
|
+
return predicate(this._children[0]) ? this._children[0] : null;
|
|
1400
1831
|
}
|
|
1401
1832
|
}
|
|
1402
1833
|
|
|
@@ -1407,13 +1838,6 @@ class AutoComplete {
|
|
|
1407
1838
|
this._options = options;
|
|
1408
1839
|
this._text = "";
|
|
1409
1840
|
}
|
|
1410
|
-
/**
|
|
1411
|
-
* @deprecated Use suggestFor instead.
|
|
1412
|
-
* @param text The text to suggest for.
|
|
1413
|
-
*/
|
|
1414
|
-
suggest(text) {
|
|
1415
|
-
return this.suggestFor(text);
|
|
1416
|
-
}
|
|
1417
1841
|
suggestFor(text) {
|
|
1418
1842
|
if (text.length === 0) {
|
|
1419
1843
|
return {
|
|
@@ -1426,15 +1850,10 @@ class AutoComplete {
|
|
|
1426
1850
|
}
|
|
1427
1851
|
this._text = text;
|
|
1428
1852
|
this._cursor = new Cursor(text);
|
|
1853
|
+
let errorAtIndex = null;
|
|
1429
1854
|
const ast = this._pattern.parse(this._cursor);
|
|
1430
|
-
const leafPattern = this._cursor.leafMatch.pattern;
|
|
1431
1855
|
const isComplete = (ast === null || ast === void 0 ? void 0 : ast.value) === text;
|
|
1432
|
-
const options = this.
|
|
1433
|
-
[this._pattern];
|
|
1434
|
-
let errorAtIndex = null;
|
|
1435
|
-
if (leafPattern != null) {
|
|
1436
|
-
leafPattern.getNextPatterns();
|
|
1437
|
-
}
|
|
1856
|
+
const options = this._getAllOptions();
|
|
1438
1857
|
if (this._cursor.hasError && this._cursor.furthestError != null) {
|
|
1439
1858
|
errorAtIndex = this._cursor.furthestError.index;
|
|
1440
1859
|
errorAtIndex = options.reduce((errorAtIndex, option) => Math.max(errorAtIndex, option.startIndex), errorAtIndex);
|
|
@@ -1447,6 +1866,9 @@ class AutoComplete {
|
|
|
1447
1866
|
ast,
|
|
1448
1867
|
};
|
|
1449
1868
|
}
|
|
1869
|
+
_getAllOptions() {
|
|
1870
|
+
return this._cursor.leafMatches.map((m) => this._createSuggestionsFromMatch(m)).flat();
|
|
1871
|
+
}
|
|
1450
1872
|
_createSuggestionsFromRoot() {
|
|
1451
1873
|
const suggestions = [];
|
|
1452
1874
|
const tokens = this._pattern.getTokens();
|
|
@@ -1455,20 +1877,19 @@ class AutoComplete {
|
|
|
1455
1877
|
}
|
|
1456
1878
|
return suggestions;
|
|
1457
1879
|
}
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
if (!leafMatch.pattern) {
|
|
1880
|
+
_createSuggestionsFromMatch(match) {
|
|
1881
|
+
if (!match.pattern) {
|
|
1461
1882
|
return this._createSuggestions(-1, this._getTokensForPattern(this._pattern));
|
|
1462
1883
|
}
|
|
1463
|
-
const leafPattern =
|
|
1464
|
-
const parent =
|
|
1465
|
-
if (parent !== null &&
|
|
1884
|
+
const leafPattern = match.pattern;
|
|
1885
|
+
const parent = match.pattern.parent;
|
|
1886
|
+
if (parent !== null && match.node != null) {
|
|
1466
1887
|
const patterns = leafPattern.getNextPatterns();
|
|
1467
1888
|
const tokens = patterns.reduce((acc, pattern) => {
|
|
1468
1889
|
acc.push(...this._getTokensForPattern(pattern));
|
|
1469
1890
|
return acc;
|
|
1470
1891
|
}, []);
|
|
1471
|
-
return this._createSuggestions(
|
|
1892
|
+
return this._createSuggestions(match.node.lastIndex, tokens);
|
|
1472
1893
|
}
|
|
1473
1894
|
else {
|
|
1474
1895
|
return [];
|
|
@@ -1562,10 +1983,194 @@ function getFurthestOptions(options) {
|
|
|
1562
1983
|
return furthestOptions;
|
|
1563
1984
|
}
|
|
1564
1985
|
|
|
1986
|
+
class ParseContext {
|
|
1987
|
+
constructor() {
|
|
1988
|
+
this.patternsByName = new Map();
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
class Grammar {
|
|
1992
|
+
constructor() {
|
|
1993
|
+
this._parseContext = new ParseContext();
|
|
1994
|
+
this._autoComplete = new AutoComplete(grammar, {
|
|
1995
|
+
greedyPatternNames: ["spaces", "optional-spaces", "whitespace", "new-line"],
|
|
1996
|
+
customTokens: {
|
|
1997
|
+
"regex-literal": ["[Regular Expression]"],
|
|
1998
|
+
"literal": ["[String]"],
|
|
1999
|
+
"name": ["[Pattern Name]"],
|
|
2000
|
+
"pattern-name": ["[Pattern Name]"]
|
|
2001
|
+
}
|
|
2002
|
+
});
|
|
2003
|
+
}
|
|
2004
|
+
parse(expression) {
|
|
2005
|
+
this._parseContext = new ParseContext();
|
|
2006
|
+
this._tryToParse(expression);
|
|
2007
|
+
return this._parseContext.patternsByName;
|
|
2008
|
+
}
|
|
2009
|
+
_tryToParse(expression) {
|
|
2010
|
+
const { ast, cursor, options, isComplete } = this._autoComplete.suggestFor(expression);
|
|
2011
|
+
if (!isComplete) {
|
|
2012
|
+
const text = (cursor === null || cursor === void 0 ? void 0 : cursor.text) || "";
|
|
2013
|
+
const index = options.reduce((num, o) => Math.max(o.startIndex, num), 0);
|
|
2014
|
+
const foundText = text.slice(Math.max(index - 10, 0), index + 10);
|
|
2015
|
+
const expectedTexts = "'" + options.map(o => {
|
|
2016
|
+
const startText = text.slice(Math.max(o.startIndex - 10), o.startIndex);
|
|
2017
|
+
return startText + o.text;
|
|
2018
|
+
}).join("' or '") + "'";
|
|
2019
|
+
const message = `[Parse Error] Found: '${foundText}', expected: ${expectedTexts}.`;
|
|
2020
|
+
throw new Error(message);
|
|
2021
|
+
}
|
|
2022
|
+
// If it is complete it will always have a node. So we have to cast it.
|
|
2023
|
+
this._cleanAst(ast);
|
|
2024
|
+
this._buildPatterns(ast);
|
|
2025
|
+
}
|
|
2026
|
+
_cleanAst(ast) {
|
|
2027
|
+
ast.findAll(n => n.name === "spaces" ||
|
|
2028
|
+
n.name === "optional-spaces" ||
|
|
2029
|
+
n.name === "new-line" ||
|
|
2030
|
+
n.name.includes("whitespace") ||
|
|
2031
|
+
n.name.includes("comment")).forEach(n => n.remove());
|
|
2032
|
+
}
|
|
2033
|
+
_buildPatterns(ast) {
|
|
2034
|
+
ast.children.forEach((n) => {
|
|
2035
|
+
const typeNode = n.find(n => n.name.includes("literal"));
|
|
2036
|
+
const type = (typeNode === null || typeNode === void 0 ? void 0 : typeNode.name) || "unknown";
|
|
2037
|
+
switch (type) {
|
|
2038
|
+
case "literal": {
|
|
2039
|
+
this._buildLiteral(n);
|
|
2040
|
+
break;
|
|
2041
|
+
}
|
|
2042
|
+
case "regex-literal": {
|
|
2043
|
+
this._buildRegex(n);
|
|
2044
|
+
break;
|
|
2045
|
+
}
|
|
2046
|
+
case "or-literal": {
|
|
2047
|
+
this._buildOr(n);
|
|
2048
|
+
break;
|
|
2049
|
+
}
|
|
2050
|
+
case "and-literal": {
|
|
2051
|
+
this._buildAnd(n);
|
|
2052
|
+
break;
|
|
2053
|
+
}
|
|
2054
|
+
case "repeat-literal": {
|
|
2055
|
+
this._buildRepeat(n);
|
|
2056
|
+
break;
|
|
2057
|
+
}
|
|
2058
|
+
}
|
|
2059
|
+
});
|
|
2060
|
+
}
|
|
2061
|
+
_buildLiteral(statementNode) {
|
|
2062
|
+
const nameNode = statementNode.find(n => n.name === "name");
|
|
2063
|
+
const literalNode = statementNode.find(n => n.name === "literal");
|
|
2064
|
+
const value = literalNode.value.slice(1, literalNode.value.length - 1);
|
|
2065
|
+
const name = nameNode.value;
|
|
2066
|
+
const literal = new Literal(name, value);
|
|
2067
|
+
this._parseContext.patternsByName.set(name, literal);
|
|
2068
|
+
}
|
|
2069
|
+
_buildRegex(statementNode) {
|
|
2070
|
+
const nameNode = statementNode.find(n => n.name === "name");
|
|
2071
|
+
const regexNode = statementNode.find(n => n.name === "regex-literal");
|
|
2072
|
+
const value = regexNode.value.slice(1, regexNode.value.length - 1);
|
|
2073
|
+
const name = nameNode.value;
|
|
2074
|
+
const regex = new Regex(name, value);
|
|
2075
|
+
this._parseContext.patternsByName.set(name, regex);
|
|
2076
|
+
}
|
|
2077
|
+
_buildOr(statementNode) {
|
|
2078
|
+
const nameNode = statementNode.find(n => n.name === "name");
|
|
2079
|
+
const orNode = statementNode.find(n => n.name === "or-literal");
|
|
2080
|
+
const patternNodes = orNode.children.filter(n => n.name == "pattern-name");
|
|
2081
|
+
const name = nameNode.value;
|
|
2082
|
+
const patterns = patternNodes.map(n => this._getPattern(n.value));
|
|
2083
|
+
const or = new Or(name, patterns);
|
|
2084
|
+
this._parseContext.patternsByName.set(name, or);
|
|
2085
|
+
}
|
|
2086
|
+
_getPattern(name) {
|
|
2087
|
+
const pattern = this._parseContext.patternsByName.get(name);
|
|
2088
|
+
if (pattern == null) {
|
|
2089
|
+
return new Reference(name);
|
|
2090
|
+
}
|
|
2091
|
+
return pattern;
|
|
2092
|
+
}
|
|
2093
|
+
_buildAnd(statementNode) {
|
|
2094
|
+
const nameNode = statementNode.find(n => n.name === "name");
|
|
2095
|
+
const andNode = statementNode.find(n => n.name === "and-literal");
|
|
2096
|
+
const patternNodes = andNode.children.filter(n => n.name == "pattern");
|
|
2097
|
+
const name = nameNode.value;
|
|
2098
|
+
const patterns = patternNodes.map(n => {
|
|
2099
|
+
const nameNode = n.find(n => n.name === "pattern-name");
|
|
2100
|
+
const isNot = n.find(n => n.name === "not") != null;
|
|
2101
|
+
const isOptional = n.find(n => n.name === "is-optional") != null;
|
|
2102
|
+
const name = nameNode.value;
|
|
2103
|
+
const pattern = this._getPattern(name);
|
|
2104
|
+
if (isNot) {
|
|
2105
|
+
return new Not(`not-${name}`, pattern.clone(name, isOptional));
|
|
2106
|
+
}
|
|
2107
|
+
return pattern.clone(name, isOptional);
|
|
2108
|
+
});
|
|
2109
|
+
const and = new And(name, patterns);
|
|
2110
|
+
this._parseContext.patternsByName.set(name, and);
|
|
2111
|
+
}
|
|
2112
|
+
_buildRepeat(statementNode) {
|
|
2113
|
+
const nameNode = statementNode.find(n => n.name === "name");
|
|
2114
|
+
const repeatNode = statementNode.find(n => n.name === "repeat-literal");
|
|
2115
|
+
const patternNode = repeatNode.find(n => n.name == "pattern");
|
|
2116
|
+
const patternNameNode = patternNode.find(n => n.name === "pattern-name");
|
|
2117
|
+
const dividerNode = repeatNode.find(n => n.name === "divider-pattern");
|
|
2118
|
+
const bounds = repeatNode.find(n => n.name === "bounds");
|
|
2119
|
+
const exactCount = repeatNode.find(n => n.name === "exact-count");
|
|
2120
|
+
const quantifier = repeatNode.find(n => n.name === "quantifier-shorthand");
|
|
2121
|
+
const isPatternOptional = repeatNode.find(n => n.name === "is-optional") != null;
|
|
2122
|
+
const trimDivider = repeatNode.find(n => n.name === "trim-divider") != null;
|
|
2123
|
+
const name = nameNode.value;
|
|
2124
|
+
const pattern = this._getPattern(patternNameNode.value);
|
|
2125
|
+
const options = {
|
|
2126
|
+
min: 1,
|
|
2127
|
+
max: Infinity
|
|
2128
|
+
};
|
|
2129
|
+
if (trimDivider) {
|
|
2130
|
+
options.trimDivider = trimDivider;
|
|
2131
|
+
}
|
|
2132
|
+
if (dividerNode != null) {
|
|
2133
|
+
options.divider = this._getPattern(dividerNode.value);
|
|
2134
|
+
}
|
|
2135
|
+
if (bounds != null) {
|
|
2136
|
+
const minNode = bounds.find(p => p.name === "min");
|
|
2137
|
+
const maxNode = bounds.find(p => p.name === "max");
|
|
2138
|
+
const min = minNode == null ? 0 : Number(minNode.value);
|
|
2139
|
+
const max = maxNode == null ? Infinity : Number(maxNode.value);
|
|
2140
|
+
options.min = min;
|
|
2141
|
+
options.max = max;
|
|
2142
|
+
}
|
|
2143
|
+
else if (exactCount != null) {
|
|
2144
|
+
const integerNode = exactCount.find(p => p.name === "integer");
|
|
2145
|
+
const integer = Number(integerNode.value);
|
|
2146
|
+
options.min = integer;
|
|
2147
|
+
options.max = integer;
|
|
2148
|
+
}
|
|
2149
|
+
else if (quantifier != null) {
|
|
2150
|
+
const type = quantifier.value;
|
|
2151
|
+
if (type === "+") {
|
|
2152
|
+
options.min = 1;
|
|
2153
|
+
options.max = Infinity;
|
|
2154
|
+
}
|
|
2155
|
+
else {
|
|
2156
|
+
options.min = 0;
|
|
2157
|
+
options.max = Infinity;
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
const repeat = new Repeat(name, pattern.clone(pattern.name, isPatternOptional), options);
|
|
2161
|
+
this._parseContext.patternsByName.set(name, repeat);
|
|
2162
|
+
}
|
|
2163
|
+
static parse(expression) {
|
|
2164
|
+
const grammar = new Grammar();
|
|
2165
|
+
return grammar.parse(expression);
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
|
|
1565
2169
|
exports.And = And;
|
|
1566
2170
|
exports.AutoComplete = AutoComplete;
|
|
1567
2171
|
exports.Cursor = Cursor;
|
|
1568
2172
|
exports.CursorHistory = CursorHistory;
|
|
2173
|
+
exports.Grammar = Grammar;
|
|
1569
2174
|
exports.Literal = Literal;
|
|
1570
2175
|
exports.Node = Node;
|
|
1571
2176
|
exports.Not = Not;
|