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