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