clarity-pattern-parser 6.0.0 → 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 -76
- 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 +1205 -550
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +5 -4
- package/dist/index.esm.js +1203 -549
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1203 -548
- package/dist/index.js.map +1 -1
- package/dist/intellisense/AutoComplete.d.ts +9 -7
- package/dist/intellisense/Suggestion.d.ts +1 -2
- package/dist/patterns/And.d.ts +2 -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 +2 -1
- package/dist/patterns/Not.d.ts +2 -1
- package/dist/patterns/Or.d.ts +2 -1
- package/dist/patterns/Pattern.d.ts +3 -2
- package/dist/patterns/Reference.d.ts +2 -1
- package/dist/patterns/Regex.d.ts +2 -1
- package/dist/patterns/Repeat.d.ts +19 -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 +21 -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 +125 -39
- package/src/intellisense/AutoComplete.ts +52 -36
- package/src/intellisense/Suggestion.ts +1 -2
- 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 +34 -11
- package/src/intellisense/javascript/arrayLiteral.ts +1 -1
- package/src/intellisense/javascript/{expressionStatement.ts → assignment.ts} +7 -8
- package/src/intellisense/javascript/expression.ts +45 -27
- package/src/intellisense/javascript/infixOperator.ts +6 -2
- package/src/intellisense/javascript/invocation.ts +1 -1
- package/src/intellisense/javascript/keywords.ts +3 -0
- package/src/intellisense/javascript/objectAccess.ts +9 -0
- package/src/intellisense/javascript/objectLiteral.ts +3 -3
- package/src/intellisense/javascript/parameters.ts +1 -1
- package/src/intellisense/javascript/propertyAccess.ts +8 -3
- package/src/intellisense/javascript/stringLiteral.ts +14 -8
- package/src/patterns/And.test.ts +16 -3
- package/src/patterns/And.ts +25 -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 +13 -4
- package/src/patterns/Literal.ts +5 -1
- package/src/patterns/Not.test.ts +20 -9
- package/src/patterns/Not.ts +5 -1
- package/src/patterns/Or.test.ts +18 -7
- package/src/patterns/Or.ts +11 -1
- package/src/patterns/Pattern.ts +3 -2
- package/src/patterns/Reference.test.ts +18 -8
- package/src/patterns/Reference.ts +5 -1
- package/src/patterns/Regex.test.ts +13 -4
- package/src/patterns/Regex.ts +5 -1
- package/src/patterns/Repeat.test.ts +162 -158
- package/src/patterns/Repeat.ts +95 -226
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.");
|
|
@@ -455,6 +607,9 @@
|
|
|
455
607
|
}
|
|
456
608
|
return this.parent.getTokensAfter(this);
|
|
457
609
|
}
|
|
610
|
+
getPatterns() {
|
|
611
|
+
return [this];
|
|
612
|
+
}
|
|
458
613
|
getPatternsAfter(_childReference) {
|
|
459
614
|
return [];
|
|
460
615
|
}
|
|
@@ -464,7 +619,7 @@
|
|
|
464
619
|
}
|
|
465
620
|
return this.parent.getPatternsAfter(this);
|
|
466
621
|
}
|
|
467
|
-
|
|
622
|
+
find(_predicate) {
|
|
468
623
|
return null;
|
|
469
624
|
}
|
|
470
625
|
setTokens(tokens) {
|
|
@@ -472,20 +627,6 @@
|
|
|
472
627
|
}
|
|
473
628
|
}
|
|
474
629
|
|
|
475
|
-
function clonePatterns(patterns, isOptional) {
|
|
476
|
-
return patterns.map(p => p.clone(p.name, isOptional));
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
function filterOutNull(nodes) {
|
|
480
|
-
const filteredNodes = [];
|
|
481
|
-
for (const node of nodes) {
|
|
482
|
-
if (node !== null) {
|
|
483
|
-
filteredNodes.push(node);
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
return filteredNodes;
|
|
487
|
-
}
|
|
488
|
-
|
|
489
630
|
function findPattern(pattern, predicate) {
|
|
490
631
|
let children = [];
|
|
491
632
|
if (pattern.type === "reference") {
|
|
@@ -508,7 +649,15 @@
|
|
|
508
649
|
}
|
|
509
650
|
}
|
|
510
651
|
|
|
511
|
-
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
|
+
}
|
|
512
661
|
get type() {
|
|
513
662
|
return this._type;
|
|
514
663
|
}
|
|
@@ -527,25 +676,6 @@
|
|
|
527
676
|
get isOptional() {
|
|
528
677
|
return this._isOptional;
|
|
529
678
|
}
|
|
530
|
-
constructor(name, sequence, isOptional = false) {
|
|
531
|
-
if (sequence.length === 0) {
|
|
532
|
-
throw new Error("Need at least one pattern with an 'and' pattern.");
|
|
533
|
-
}
|
|
534
|
-
const children = clonePatterns(sequence);
|
|
535
|
-
this._assignChildrenToParent(children);
|
|
536
|
-
this._type = "and";
|
|
537
|
-
this._name = name;
|
|
538
|
-
this._isOptional = isOptional;
|
|
539
|
-
this._parent = null;
|
|
540
|
-
this._children = children;
|
|
541
|
-
this._firstIndex = -1;
|
|
542
|
-
this._nodes = [];
|
|
543
|
-
}
|
|
544
|
-
_assignChildrenToParent(children) {
|
|
545
|
-
for (const child of children) {
|
|
546
|
-
child.parent = this;
|
|
547
|
-
}
|
|
548
|
-
}
|
|
549
679
|
test(text) {
|
|
550
680
|
const cursor = new Cursor(text);
|
|
551
681
|
const ast = this.parse(cursor);
|
|
@@ -560,118 +690,48 @@
|
|
|
560
690
|
};
|
|
561
691
|
}
|
|
562
692
|
parse(cursor) {
|
|
563
|
-
this.
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
if (
|
|
567
|
-
const
|
|
568
|
-
if (
|
|
569
|
-
|
|
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.`);
|
|
570
700
|
}
|
|
571
|
-
|
|
701
|
+
const clonedPattern = pattern.clone(this._name, this._isOptional);
|
|
702
|
+
clonedPattern.parent = this;
|
|
703
|
+
this._pattern = clonedPattern;
|
|
704
|
+
this._children = [this._pattern];
|
|
572
705
|
}
|
|
573
|
-
|
|
574
|
-
|
|
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
|
+
}
|
|
575
724
|
}
|
|
576
|
-
return
|
|
577
|
-
}
|
|
578
|
-
tryToParse(cursor) {
|
|
579
|
-
let passed = false;
|
|
580
|
-
for (let i = 0; i < this._children.length; i++) {
|
|
581
|
-
const runningCursorIndex = cursor.index;
|
|
582
|
-
const nextPatternIndex = i + 1;
|
|
583
|
-
const hasMorePatterns = nextPatternIndex < this._children.length;
|
|
584
|
-
const node = this._children[i].parse(cursor);
|
|
585
|
-
const hasNoError = !cursor.hasError;
|
|
586
|
-
const hadMatch = node !== null;
|
|
587
|
-
if (hasNoError) {
|
|
588
|
-
this._nodes.push(node);
|
|
589
|
-
if (hasMorePatterns) {
|
|
590
|
-
if (hadMatch) {
|
|
591
|
-
if (cursor.hasNext()) {
|
|
592
|
-
// We had a match. Increment the cursor and use the next pattern.
|
|
593
|
-
cursor.next();
|
|
594
|
-
continue;
|
|
595
|
-
}
|
|
596
|
-
else {
|
|
597
|
-
// We are at the end of the text, it may still be valid, if all the
|
|
598
|
-
// following patterns are optional.
|
|
599
|
-
if (this.areRemainingPatternsOptional(i)) {
|
|
600
|
-
passed = true;
|
|
601
|
-
break;
|
|
602
|
-
}
|
|
603
|
-
// We didn't finish the parsing sequence.
|
|
604
|
-
cursor.recordErrorAt(cursor.index + 1, this);
|
|
605
|
-
break;
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
else {
|
|
609
|
-
// An optional pattern did not matched, try from the same spot on the next
|
|
610
|
-
// pattern.
|
|
611
|
-
cursor.moveTo(runningCursorIndex);
|
|
612
|
-
continue;
|
|
613
|
-
}
|
|
614
|
-
}
|
|
615
|
-
else {
|
|
616
|
-
// If we don't have any results from what we parsed then record error.
|
|
617
|
-
const lastNode = this.getLastValidNode();
|
|
618
|
-
if (lastNode === null) {
|
|
619
|
-
cursor.recordErrorAt(cursor.index, this);
|
|
620
|
-
break;
|
|
621
|
-
}
|
|
622
|
-
// The sequence was parsed fully.
|
|
623
|
-
passed = true;
|
|
624
|
-
break;
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
else {
|
|
628
|
-
// The pattern failed.
|
|
629
|
-
cursor.moveTo(this._firstIndex);
|
|
630
|
-
break;
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
return passed;
|
|
634
|
-
}
|
|
635
|
-
getLastValidNode() {
|
|
636
|
-
const nodes = filterOutNull(this._nodes);
|
|
637
|
-
if (nodes.length === 0) {
|
|
638
|
-
return null;
|
|
639
|
-
}
|
|
640
|
-
return nodes[nodes.length - 1];
|
|
641
|
-
}
|
|
642
|
-
areRemainingPatternsOptional(fromIndex) {
|
|
643
|
-
const startOnIndex = fromIndex + 1;
|
|
644
|
-
const length = this._children.length;
|
|
645
|
-
for (let i = startOnIndex; i < length; i++) {
|
|
646
|
-
const pattern = this._children[i];
|
|
647
|
-
if (!pattern.isOptional) {
|
|
648
|
-
return false;
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
return true;
|
|
652
|
-
}
|
|
653
|
-
createNode(cursor) {
|
|
654
|
-
const children = filterOutNull(this._nodes);
|
|
655
|
-
const lastIndex = children[children.length - 1].lastIndex;
|
|
656
|
-
cursor.getChars(this._firstIndex, lastIndex);
|
|
657
|
-
cursor.moveTo(lastIndex);
|
|
658
|
-
return new Node("and", this._name, this._firstIndex, lastIndex, children);
|
|
725
|
+
return node;
|
|
659
726
|
}
|
|
660
727
|
getTokens() {
|
|
661
|
-
|
|
662
|
-
for (const child of this._children) {
|
|
663
|
-
tokens.push(...child.getTokens());
|
|
664
|
-
if (!child.isOptional) {
|
|
665
|
-
break;
|
|
666
|
-
}
|
|
667
|
-
}
|
|
668
|
-
return tokens;
|
|
728
|
+
return this._getPatternSafely().getTokens();
|
|
669
729
|
}
|
|
670
|
-
getTokensAfter(
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
return
|
|
730
|
+
getTokensAfter(_lastMatched) {
|
|
731
|
+
if (this._parent == null) {
|
|
732
|
+
return [];
|
|
733
|
+
}
|
|
734
|
+
return this._parent.getTokensAfter(this);
|
|
675
735
|
}
|
|
676
736
|
getNextTokens() {
|
|
677
737
|
if (this.parent == null) {
|
|
@@ -679,47 +739,14 @@
|
|
|
679
739
|
}
|
|
680
740
|
return this.parent.getTokensAfter(this);
|
|
681
741
|
}
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
for (let i = 0; i < this._children.length; i++) {
|
|
688
|
-
if (this._children[i] === childReference) {
|
|
689
|
-
if (i + 1 < this._children.length) {
|
|
690
|
-
nextSibling = this._children[i + 1];
|
|
691
|
-
}
|
|
692
|
-
nextSiblingIndex = i + 1;
|
|
693
|
-
index = i;
|
|
694
|
-
break;
|
|
695
|
-
}
|
|
696
|
-
}
|
|
697
|
-
// The child reference isn't one of the child patterns.
|
|
698
|
-
if (index === -1) {
|
|
742
|
+
getPatterns() {
|
|
743
|
+
return this._getPatternSafely().getPatterns();
|
|
744
|
+
}
|
|
745
|
+
getPatternsAfter(_childReference) {
|
|
746
|
+
if (this._parent == null) {
|
|
699
747
|
return [];
|
|
700
748
|
}
|
|
701
|
-
|
|
702
|
-
if (nextSiblingIndex === this._children.length && this._parent !== null) {
|
|
703
|
-
return this._parent.getPatternsAfter(this);
|
|
704
|
-
}
|
|
705
|
-
// Next pattern isn't optional so send it back as the next patterns.
|
|
706
|
-
if (nextSibling !== null && !nextSibling.isOptional) {
|
|
707
|
-
return [nextSibling];
|
|
708
|
-
}
|
|
709
|
-
// Send back as many optional patterns as possible.
|
|
710
|
-
if (nextSibling !== null && nextSibling.isOptional) {
|
|
711
|
-
for (let i = nextSiblingIndex; i < this._children.length; i++) {
|
|
712
|
-
const child = this._children[i];
|
|
713
|
-
patterns.push(child);
|
|
714
|
-
if (!child.isOptional) {
|
|
715
|
-
break;
|
|
716
|
-
}
|
|
717
|
-
if (i === this._children.length - 1 && this._parent !== null) {
|
|
718
|
-
patterns.push(...this._parent.getPatternsAfter(this));
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
return patterns;
|
|
749
|
+
return this._parent.getPatternsAfter(this);
|
|
723
750
|
}
|
|
724
751
|
getNextPatterns() {
|
|
725
752
|
if (this.parent == null) {
|
|
@@ -727,15 +754,32 @@
|
|
|
727
754
|
}
|
|
728
755
|
return this.parent.getPatternsAfter(this);
|
|
729
756
|
}
|
|
730
|
-
|
|
731
|
-
return
|
|
757
|
+
find(_predicate) {
|
|
758
|
+
return null;
|
|
732
759
|
}
|
|
733
760
|
clone(name = this._name, isOptional = this._isOptional) {
|
|
734
|
-
return new
|
|
761
|
+
return new Reference(name, isOptional);
|
|
735
762
|
}
|
|
736
763
|
}
|
|
737
764
|
|
|
738
|
-
|
|
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
|
+
}
|
|
739
783
|
get type() {
|
|
740
784
|
return this._type;
|
|
741
785
|
}
|
|
@@ -749,23 +793,15 @@
|
|
|
749
793
|
this._parent = pattern;
|
|
750
794
|
}
|
|
751
795
|
get children() {
|
|
752
|
-
return
|
|
796
|
+
return this._children;
|
|
753
797
|
}
|
|
754
798
|
get isOptional() {
|
|
755
799
|
return this._isOptional;
|
|
756
800
|
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
801
|
+
_assignChildrenToParent(children) {
|
|
802
|
+
for (const child of children) {
|
|
803
|
+
child.parent = this;
|
|
760
804
|
}
|
|
761
|
-
this._type = "literal";
|
|
762
|
-
this._name = name;
|
|
763
|
-
this._literal = value;
|
|
764
|
-
this._runes = Array.from(value);
|
|
765
|
-
this._isOptional = isOptional;
|
|
766
|
-
this._parent = null;
|
|
767
|
-
this._firstIndex = 0;
|
|
768
|
-
this._lastIndex = 0;
|
|
769
805
|
}
|
|
770
806
|
test(text) {
|
|
771
807
|
const cursor = new Cursor(text);
|
|
@@ -782,15 +818,13 @@
|
|
|
782
818
|
}
|
|
783
819
|
parse(cursor) {
|
|
784
820
|
this._firstIndex = cursor.index;
|
|
785
|
-
const
|
|
786
|
-
if (
|
|
821
|
+
const node = this._tryToParse(cursor);
|
|
822
|
+
if (node != null) {
|
|
787
823
|
cursor.resolveError();
|
|
788
|
-
const node = this._createNode();
|
|
789
|
-
cursor.recordMatch(this, node);
|
|
790
824
|
return node;
|
|
791
825
|
}
|
|
792
826
|
if (!this._isOptional) {
|
|
793
|
-
cursor.recordErrorAt(
|
|
827
|
+
cursor.recordErrorAt(this._firstIndex, this);
|
|
794
828
|
return null;
|
|
795
829
|
}
|
|
796
830
|
cursor.resolveError();
|
|
@@ -798,60 +832,250 @@
|
|
|
798
832
|
return null;
|
|
799
833
|
}
|
|
800
834
|
_tryToParse(cursor) {
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
if (literalRune !== cursorRune) {
|
|
807
|
-
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;
|
|
808
840
|
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
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));
|
|
813
906
|
}
|
|
814
|
-
|
|
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();
|
|
815
946
|
break;
|
|
816
947
|
}
|
|
817
|
-
|
|
948
|
+
if (node != null) {
|
|
949
|
+
nodes.push(node);
|
|
950
|
+
if (cursor.hasNext()) {
|
|
951
|
+
cursor.next();
|
|
952
|
+
}
|
|
953
|
+
else {
|
|
954
|
+
break;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
818
957
|
}
|
|
819
|
-
|
|
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);
|
|
820
978
|
}
|
|
821
|
-
|
|
822
|
-
|
|
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;
|
|
823
983
|
}
|
|
824
|
-
|
|
825
|
-
const
|
|
826
|
-
|
|
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
|
+
});
|
|
827
1007
|
}
|
|
828
1008
|
getTokens() {
|
|
829
|
-
return
|
|
1009
|
+
return this._children[0].getTokens();
|
|
830
1010
|
}
|
|
831
|
-
getTokensAfter(
|
|
832
|
-
|
|
1011
|
+
getTokensAfter(childReference) {
|
|
1012
|
+
const patterns = this.getPatternsAfter(childReference);
|
|
1013
|
+
const tokens = [];
|
|
1014
|
+
patterns.forEach(p => tokens.push(...p.getTokens()));
|
|
1015
|
+
return tokens;
|
|
833
1016
|
}
|
|
834
1017
|
getNextTokens() {
|
|
835
|
-
if (this.
|
|
1018
|
+
if (this._parent == null) {
|
|
836
1019
|
return [];
|
|
837
1020
|
}
|
|
838
|
-
return this.
|
|
1021
|
+
return this._parent.getTokensAfter(this);
|
|
839
1022
|
}
|
|
840
|
-
|
|
841
|
-
return [];
|
|
1023
|
+
getPatterns() {
|
|
1024
|
+
return this._children[0].getPatterns();
|
|
1025
|
+
}
|
|
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();
|
|
842
1044
|
}
|
|
843
1045
|
getNextPatterns() {
|
|
844
|
-
if (this.
|
|
1046
|
+
if (this._parent == null) {
|
|
845
1047
|
return [];
|
|
846
1048
|
}
|
|
847
|
-
return this.
|
|
1049
|
+
return this._parent.getPatternsAfter(this);
|
|
848
1050
|
}
|
|
849
|
-
|
|
850
|
-
return
|
|
1051
|
+
find(predicate) {
|
|
1052
|
+
return findPattern(this, predicate);
|
|
851
1053
|
}
|
|
852
1054
|
}
|
|
853
1055
|
|
|
854
|
-
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
|
+
}
|
|
855
1079
|
get type() {
|
|
856
1080
|
return this._type;
|
|
857
1081
|
}
|
|
@@ -868,169 +1092,260 @@
|
|
|
868
1092
|
return this._children;
|
|
869
1093
|
}
|
|
870
1094
|
get isOptional() {
|
|
871
|
-
return
|
|
1095
|
+
return this._min === 0;
|
|
872
1096
|
}
|
|
873
|
-
|
|
874
|
-
this.
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
1097
|
+
get min() {
|
|
1098
|
+
return this._min;
|
|
1099
|
+
}
|
|
1100
|
+
_assignChildrenToParent(children) {
|
|
1101
|
+
for (const child of children) {
|
|
1102
|
+
child.parent = this;
|
|
1103
|
+
}
|
|
879
1104
|
}
|
|
880
1105
|
test(text) {
|
|
881
1106
|
const cursor = new Cursor(text);
|
|
882
|
-
this.parse(cursor);
|
|
883
|
-
return
|
|
1107
|
+
const ast = this.parse(cursor);
|
|
1108
|
+
return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
|
|
884
1109
|
}
|
|
885
1110
|
exec(text) {
|
|
886
1111
|
const cursor = new Cursor(text);
|
|
887
1112
|
const ast = this.parse(cursor);
|
|
888
1113
|
return {
|
|
889
|
-
ast,
|
|
1114
|
+
ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
|
|
890
1115
|
cursor
|
|
891
1116
|
};
|
|
892
1117
|
}
|
|
893
1118
|
parse(cursor) {
|
|
894
|
-
|
|
895
|
-
this.
|
|
896
|
-
|
|
1119
|
+
this._firstIndex = cursor.index;
|
|
1120
|
+
this._nodes = [];
|
|
1121
|
+
const passed = this._tryToParse(cursor);
|
|
1122
|
+
if (passed) {
|
|
897
1123
|
cursor.resolveError();
|
|
898
|
-
|
|
1124
|
+
const node = this._createNode(cursor);
|
|
1125
|
+
if (node != null) {
|
|
1126
|
+
cursor.moveTo(node.lastIndex);
|
|
1127
|
+
cursor.recordMatch(this, node);
|
|
1128
|
+
}
|
|
1129
|
+
return node;
|
|
1130
|
+
}
|
|
1131
|
+
if (this._min > 0) {
|
|
1132
|
+
return null;
|
|
1133
|
+
}
|
|
1134
|
+
cursor.resolveError();
|
|
1135
|
+
return null;
|
|
1136
|
+
}
|
|
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;
|
|
899
1194
|
}
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
1195
|
+
return passed;
|
|
1196
|
+
}
|
|
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);
|
|
904
1204
|
}
|
|
905
|
-
|
|
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);
|
|
906
1208
|
}
|
|
907
|
-
|
|
908
|
-
const
|
|
909
|
-
|
|
1209
|
+
_getLastValidNode() {
|
|
1210
|
+
const nodes = this._nodes.filter((node) => node !== null);
|
|
1211
|
+
if (nodes.length === 0) {
|
|
1212
|
+
return null;
|
|
1213
|
+
}
|
|
1214
|
+
return nodes[nodes.length - 1];
|
|
910
1215
|
}
|
|
911
1216
|
getTokens() {
|
|
912
|
-
|
|
913
|
-
if (parent != null) {
|
|
914
|
-
return parent.getTokensAfter(this);
|
|
915
|
-
}
|
|
916
|
-
return [];
|
|
1217
|
+
return this._pattern.getTokens();
|
|
917
1218
|
}
|
|
918
|
-
getTokensAfter(
|
|
919
|
-
const
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
return [];
|
|
1219
|
+
getTokensAfter(childReference) {
|
|
1220
|
+
const patterns = this.getPatternsAfter(childReference);
|
|
1221
|
+
const tokens = [];
|
|
1222
|
+
patterns.forEach(p => tokens.push(...p.getTokens()));
|
|
1223
|
+
return tokens;
|
|
924
1224
|
}
|
|
925
1225
|
getNextTokens() {
|
|
926
|
-
if (this.
|
|
1226
|
+
if (this._parent == null) {
|
|
927
1227
|
return [];
|
|
928
1228
|
}
|
|
929
|
-
return this.
|
|
1229
|
+
return this._parent.getTokensAfter(this);
|
|
930
1230
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
1231
|
+
getPatterns() {
|
|
1232
|
+
return this._pattern.getPatterns();
|
|
1233
|
+
}
|
|
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
|
+
}
|
|
935
1241
|
}
|
|
936
|
-
|
|
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;
|
|
937
1263
|
}
|
|
938
1264
|
getNextPatterns() {
|
|
939
|
-
if (this.
|
|
1265
|
+
if (this._parent == null) {
|
|
940
1266
|
return [];
|
|
941
1267
|
}
|
|
942
|
-
return this.
|
|
1268
|
+
return this._parent.getPatternsAfter(this);
|
|
943
1269
|
}
|
|
944
|
-
|
|
945
|
-
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
|
+
});
|
|
946
1288
|
}
|
|
947
1289
|
}
|
|
948
1290
|
|
|
949
|
-
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
|
+
}
|
|
950
1305
|
get type() {
|
|
951
|
-
return this.
|
|
1306
|
+
return this._repeatPattern.type;
|
|
952
1307
|
}
|
|
953
1308
|
get name() {
|
|
954
|
-
return this.
|
|
1309
|
+
return this._repeatPattern.name;
|
|
955
1310
|
}
|
|
956
1311
|
get parent() {
|
|
957
1312
|
return this._parent;
|
|
958
1313
|
}
|
|
959
|
-
set parent(
|
|
960
|
-
this._parent =
|
|
1314
|
+
set parent(value) {
|
|
1315
|
+
this._parent = value;
|
|
961
1316
|
}
|
|
962
1317
|
get children() {
|
|
963
1318
|
return this._children;
|
|
964
1319
|
}
|
|
965
1320
|
get isOptional() {
|
|
966
|
-
return this.
|
|
1321
|
+
return this._repeatPattern.isOptional;
|
|
967
1322
|
}
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
throw new Error("Need at least one pattern with an 'or' pattern.");
|
|
971
|
-
}
|
|
972
|
-
const children = clonePatterns(options, false);
|
|
973
|
-
this._assignChildrenToParent(children);
|
|
974
|
-
this._type = "or";
|
|
975
|
-
this._name = name;
|
|
976
|
-
this._parent = null;
|
|
977
|
-
this._children = children;
|
|
978
|
-
this._isOptional = isOptional;
|
|
979
|
-
this._firstIndex = 0;
|
|
980
|
-
}
|
|
981
|
-
_assignChildrenToParent(children) {
|
|
982
|
-
for (const child of children) {
|
|
983
|
-
child.parent = this;
|
|
984
|
-
}
|
|
985
|
-
}
|
|
986
|
-
test(text) {
|
|
987
|
-
const cursor = new Cursor(text);
|
|
988
|
-
const ast = this.parse(cursor);
|
|
989
|
-
return (ast === null || ast === void 0 ? void 0 : ast.value) === text;
|
|
1323
|
+
parse(cursor) {
|
|
1324
|
+
return this._repeatPattern.parse(cursor);
|
|
990
1325
|
}
|
|
991
1326
|
exec(text) {
|
|
992
|
-
|
|
993
|
-
const ast = this.parse(cursor);
|
|
994
|
-
return {
|
|
995
|
-
ast: (ast === null || ast === void 0 ? void 0 : ast.value) === text ? ast : null,
|
|
996
|
-
cursor
|
|
997
|
-
};
|
|
1327
|
+
return this._repeatPattern.exec(text);
|
|
998
1328
|
}
|
|
999
|
-
|
|
1000
|
-
this.
|
|
1001
|
-
const node = this._tryToParse(cursor);
|
|
1002
|
-
if (node != null) {
|
|
1003
|
-
cursor.resolveError();
|
|
1004
|
-
return node;
|
|
1005
|
-
}
|
|
1006
|
-
if (!this._isOptional) {
|
|
1007
|
-
cursor.recordErrorAt(this._firstIndex, this);
|
|
1008
|
-
return null;
|
|
1009
|
-
}
|
|
1010
|
-
cursor.resolveError();
|
|
1011
|
-
cursor.moveTo(this._firstIndex);
|
|
1012
|
-
return null;
|
|
1329
|
+
test(text) {
|
|
1330
|
+
return this._repeatPattern.test(text);
|
|
1013
1331
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
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);
|
|
1020
1340
|
}
|
|
1021
|
-
cursor.resolveError();
|
|
1022
1341
|
}
|
|
1023
|
-
return
|
|
1342
|
+
return new Repeat(name, this._pattern, Object.assign(Object.assign({}, this._options), { min }));
|
|
1024
1343
|
}
|
|
1025
1344
|
getTokens() {
|
|
1026
|
-
|
|
1027
|
-
for (const child of this._children) {
|
|
1028
|
-
tokens.push(...child.getTokens());
|
|
1029
|
-
}
|
|
1030
|
-
return tokens;
|
|
1345
|
+
return this._repeatPattern.getTokens();
|
|
1031
1346
|
}
|
|
1032
1347
|
getTokensAfter(_childReference) {
|
|
1033
|
-
if (this._parent
|
|
1348
|
+
if (this._parent == null) {
|
|
1034
1349
|
return [];
|
|
1035
1350
|
}
|
|
1036
1351
|
return this._parent.getTokensAfter(this);
|
|
@@ -1041,28 +1356,53 @@
|
|
|
1041
1356
|
}
|
|
1042
1357
|
return this._parent.getTokensAfter(this);
|
|
1043
1358
|
}
|
|
1359
|
+
getPatterns() {
|
|
1360
|
+
return this._repeatPattern.getPatterns();
|
|
1361
|
+
}
|
|
1044
1362
|
getPatternsAfter(_childReference) {
|
|
1045
|
-
if (this._parent
|
|
1363
|
+
if (this._parent == null) {
|
|
1046
1364
|
return [];
|
|
1047
1365
|
}
|
|
1048
1366
|
return this._parent.getPatternsAfter(this);
|
|
1049
1367
|
}
|
|
1050
1368
|
getNextPatterns() {
|
|
1051
|
-
if (this.
|
|
1369
|
+
if (this._parent == null) {
|
|
1052
1370
|
return [];
|
|
1053
1371
|
}
|
|
1054
|
-
return this.
|
|
1372
|
+
return this._parent.getPatternsAfter(this);
|
|
1055
1373
|
}
|
|
1056
|
-
|
|
1057
|
-
return
|
|
1374
|
+
find(predicate) {
|
|
1375
|
+
return this._repeatPattern.find(predicate);
|
|
1058
1376
|
}
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
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
|
+
}
|
|
1062
1387
|
}
|
|
1388
|
+
return filteredNodes;
|
|
1063
1389
|
}
|
|
1064
1390
|
|
|
1065
|
-
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
|
+
}
|
|
1066
1406
|
get type() {
|
|
1067
1407
|
return this._type;
|
|
1068
1408
|
}
|
|
@@ -1081,20 +1421,6 @@
|
|
|
1081
1421
|
get isOptional() {
|
|
1082
1422
|
return this._isOptional;
|
|
1083
1423
|
}
|
|
1084
|
-
constructor(name, pattern, divider, isOptional = false) {
|
|
1085
|
-
const patterns = divider != null ? [pattern, divider] : [pattern];
|
|
1086
|
-
const children = clonePatterns(patterns, false);
|
|
1087
|
-
this._assignChildrenToParent(children);
|
|
1088
|
-
this._type = "repeat";
|
|
1089
|
-
this._name = name;
|
|
1090
|
-
this._isOptional = isOptional;
|
|
1091
|
-
this._parent = null;
|
|
1092
|
-
this._children = children;
|
|
1093
|
-
this._pattern = children[0];
|
|
1094
|
-
this._divider = children[1];
|
|
1095
|
-
this._firstIndex = -1;
|
|
1096
|
-
this._nodes = [];
|
|
1097
|
-
}
|
|
1098
1424
|
_assignChildrenToParent(children) {
|
|
1099
1425
|
for (const child of children) {
|
|
1100
1426
|
child.parent = this;
|
|
@@ -1118,92 +1444,108 @@
|
|
|
1118
1444
|
this._nodes = [];
|
|
1119
1445
|
const passed = this.tryToParse(cursor);
|
|
1120
1446
|
if (passed) {
|
|
1121
|
-
cursor.resolveError();
|
|
1122
1447
|
const node = this.createNode(cursor);
|
|
1123
|
-
if (node
|
|
1448
|
+
if (node !== null) {
|
|
1124
1449
|
cursor.recordMatch(this, node);
|
|
1125
1450
|
}
|
|
1126
1451
|
return node;
|
|
1127
1452
|
}
|
|
1128
|
-
if (
|
|
1129
|
-
|
|
1453
|
+
if (this._isOptional) {
|
|
1454
|
+
cursor.resolveError();
|
|
1130
1455
|
}
|
|
1131
|
-
cursor.resolveError();
|
|
1132
|
-
cursor.moveTo(this._firstIndex);
|
|
1133
1456
|
return null;
|
|
1134
1457
|
}
|
|
1135
1458
|
tryToParse(cursor) {
|
|
1136
1459
|
let passed = false;
|
|
1137
|
-
|
|
1460
|
+
for (let i = 0; i < this._children.length; i++) {
|
|
1138
1461
|
const runningCursorIndex = cursor.index;
|
|
1139
|
-
const
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
passed = true;
|
|
1163
|
-
break;
|
|
1164
|
-
}
|
|
1165
|
-
else if (dividerNode != null) {
|
|
1166
|
-
this._nodes.push(dividerNode);
|
|
1167
|
-
if (!cursor.hasNext()) {
|
|
1168
|
-
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);
|
|
1169
1485
|
break;
|
|
1170
1486
|
}
|
|
1171
|
-
|
|
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;
|
|
1172
1493
|
}
|
|
1173
1494
|
}
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
const dividerNode = this._nodes[this._nodes.length - 1];
|
|
1186
|
-
cursor.moveTo(dividerNode.firstIndex);
|
|
1187
|
-
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
|
+
}
|
|
1188
1506
|
}
|
|
1189
1507
|
else {
|
|
1190
|
-
|
|
1508
|
+
// The pattern failed.
|
|
1509
|
+
cursor.moveTo(this._firstIndex);
|
|
1510
|
+
break;
|
|
1191
1511
|
}
|
|
1192
1512
|
}
|
|
1193
|
-
|
|
1194
|
-
cursor.getChars(this._firstIndex, lastIndex);
|
|
1195
|
-
cursor.moveTo(lastIndex);
|
|
1196
|
-
return new Node("repeat", this._name, this._firstIndex, lastIndex, children, undefined);
|
|
1513
|
+
return passed;
|
|
1197
1514
|
}
|
|
1198
1515
|
getLastValidNode() {
|
|
1199
|
-
const nodes = this._nodes
|
|
1516
|
+
const nodes = filterOutNull(this._nodes);
|
|
1200
1517
|
if (nodes.length === 0) {
|
|
1201
1518
|
return null;
|
|
1202
1519
|
}
|
|
1203
1520
|
return nodes[nodes.length - 1];
|
|
1204
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
|
+
}
|
|
1205
1540
|
getTokens() {
|
|
1206
|
-
|
|
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;
|
|
1207
1549
|
}
|
|
1208
1550
|
getTokensAfter(childReference) {
|
|
1209
1551
|
const patterns = this.getPatternsAfter(childReference);
|
|
@@ -1217,33 +1559,50 @@
|
|
|
1217
1559
|
}
|
|
1218
1560
|
return this.parent.getTokensAfter(this);
|
|
1219
1561
|
}
|
|
1562
|
+
getPatterns() {
|
|
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;
|
|
1571
|
+
}
|
|
1220
1572
|
getPatternsAfter(childReference) {
|
|
1221
|
-
let index = -1;
|
|
1222
1573
|
const patterns = [];
|
|
1574
|
+
let nextSiblingIndex = -1;
|
|
1575
|
+
let index = -1;
|
|
1223
1576
|
for (let i = 0; i < this._children.length; i++) {
|
|
1224
1577
|
if (this._children[i] === childReference) {
|
|
1578
|
+
if (i + 1 < this._children.length) {
|
|
1579
|
+
this._children[i + 1];
|
|
1580
|
+
}
|
|
1581
|
+
nextSiblingIndex = i + 1;
|
|
1225
1582
|
index = i;
|
|
1583
|
+
break;
|
|
1226
1584
|
}
|
|
1227
1585
|
}
|
|
1228
|
-
//
|
|
1586
|
+
// The child reference isn't one of the child patterns.
|
|
1229
1587
|
if (index === -1) {
|
|
1230
1588
|
return [];
|
|
1231
1589
|
}
|
|
1232
|
-
//
|
|
1233
|
-
if (
|
|
1234
|
-
|
|
1235
|
-
|
|
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) {
|
|
1236
1603
|
patterns.push(...this._parent.getPatternsAfter(this));
|
|
1237
1604
|
}
|
|
1238
1605
|
}
|
|
1239
|
-
// Suggest the pattern because the divider was the last match.
|
|
1240
|
-
if (index === 1) {
|
|
1241
|
-
patterns.push(this._children[0]);
|
|
1242
|
-
}
|
|
1243
|
-
if (index === 0 && !this._divider && this._parent) {
|
|
1244
|
-
patterns.push(this._children[0]);
|
|
1245
|
-
patterns.push(...this._parent.getPatternsAfter(this));
|
|
1246
|
-
}
|
|
1247
1606
|
return patterns;
|
|
1248
1607
|
}
|
|
1249
1608
|
getNextPatterns() {
|
|
@@ -1252,15 +1611,138 @@
|
|
|
1252
1611
|
}
|
|
1253
1612
|
return this.parent.getPatternsAfter(this);
|
|
1254
1613
|
}
|
|
1255
|
-
|
|
1614
|
+
find(predicate) {
|
|
1256
1615
|
return findPattern(this, predicate);
|
|
1257
1616
|
}
|
|
1258
1617
|
clone(name = this._name, isOptional = this._isOptional) {
|
|
1259
|
-
return new
|
|
1618
|
+
return new And(name, this._children, isOptional);
|
|
1260
1619
|
}
|
|
1261
1620
|
}
|
|
1262
1621
|
|
|
1263
|
-
|
|
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
|
+
}
|
|
1264
1746
|
get type() {
|
|
1265
1747
|
return this._type;
|
|
1266
1748
|
}
|
|
@@ -1277,72 +1759,52 @@
|
|
|
1277
1759
|
return this._children;
|
|
1278
1760
|
}
|
|
1279
1761
|
get isOptional() {
|
|
1280
|
-
return
|
|
1281
|
-
}
|
|
1282
|
-
constructor(name, isOptional = false) {
|
|
1283
|
-
this._type = "reference";
|
|
1284
|
-
this._name = name;
|
|
1285
|
-
this._parent = null;
|
|
1286
|
-
this._isOptional = isOptional;
|
|
1287
|
-
this._pattern = null;
|
|
1288
|
-
this._children = [];
|
|
1762
|
+
return false;
|
|
1289
1763
|
}
|
|
1290
1764
|
test(text) {
|
|
1291
1765
|
const cursor = new Cursor(text);
|
|
1292
|
-
|
|
1293
|
-
return
|
|
1766
|
+
this.parse(cursor);
|
|
1767
|
+
return !cursor.hasError;
|
|
1294
1768
|
}
|
|
1295
1769
|
exec(text) {
|
|
1296
1770
|
const cursor = new Cursor(text);
|
|
1297
1771
|
const ast = this.parse(cursor);
|
|
1298
1772
|
return {
|
|
1299
|
-
ast
|
|
1773
|
+
ast,
|
|
1300
1774
|
cursor
|
|
1301
1775
|
};
|
|
1302
1776
|
}
|
|
1303
1777
|
parse(cursor) {
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
if (pattern === null) {
|
|
1310
|
-
throw new Error(`Couldn't find '${this._name}' pattern within tree.`);
|
|
1311
|
-
}
|
|
1312
|
-
const clonedPattern = pattern.clone(this._name, this._isOptional);
|
|
1313
|
-
clonedPattern.parent = this;
|
|
1314
|
-
this._pattern = clonedPattern;
|
|
1315
|
-
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);
|
|
1316
1783
|
}
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
return findPattern(root, (pattern) => {
|
|
1322
|
-
return pattern.name === this._name && pattern.type !== "reference";
|
|
1323
|
-
});
|
|
1324
|
-
}
|
|
1325
|
-
_getRoot() {
|
|
1326
|
-
let node = this;
|
|
1327
|
-
while (true) {
|
|
1328
|
-
const parent = node.parent;
|
|
1329
|
-
if (parent == null) {
|
|
1330
|
-
break;
|
|
1331
|
-
}
|
|
1332
|
-
else {
|
|
1333
|
-
node = parent;
|
|
1334
|
-
}
|
|
1784
|
+
else {
|
|
1785
|
+
cursor.moveTo(firstIndex);
|
|
1786
|
+
cursor.resolveError();
|
|
1787
|
+
cursor.recordErrorAt(firstIndex, this);
|
|
1335
1788
|
}
|
|
1336
|
-
return
|
|
1789
|
+
return null;
|
|
1790
|
+
}
|
|
1791
|
+
clone(name = this._name) {
|
|
1792
|
+
const not = new Not(name, this._children[0]);
|
|
1793
|
+
return not;
|
|
1337
1794
|
}
|
|
1338
1795
|
getTokens() {
|
|
1339
|
-
|
|
1796
|
+
const parent = this._parent;
|
|
1797
|
+
if (parent != null) {
|
|
1798
|
+
return parent.getTokensAfter(this);
|
|
1799
|
+
}
|
|
1800
|
+
return [];
|
|
1340
1801
|
}
|
|
1341
|
-
getTokensAfter(
|
|
1342
|
-
|
|
1343
|
-
|
|
1802
|
+
getTokensAfter(_childReference) {
|
|
1803
|
+
const parent = this._parent;
|
|
1804
|
+
if (parent != null) {
|
|
1805
|
+
return parent.getTokensAfter(this);
|
|
1344
1806
|
}
|
|
1345
|
-
return
|
|
1807
|
+
return [];
|
|
1346
1808
|
}
|
|
1347
1809
|
getNextTokens() {
|
|
1348
1810
|
if (this.parent == null) {
|
|
@@ -1350,11 +1812,15 @@
|
|
|
1350
1812
|
}
|
|
1351
1813
|
return this.parent.getTokensAfter(this);
|
|
1352
1814
|
}
|
|
1815
|
+
getPatterns() {
|
|
1816
|
+
return [...this.getNextPatterns().map(p => p.getPatterns()).flat()];
|
|
1817
|
+
}
|
|
1353
1818
|
getPatternsAfter(_childReference) {
|
|
1354
|
-
|
|
1355
|
-
|
|
1819
|
+
const parent = this._parent;
|
|
1820
|
+
if (parent != null) {
|
|
1821
|
+
return parent.getPatternsAfter(this);
|
|
1356
1822
|
}
|
|
1357
|
-
return
|
|
1823
|
+
return [];
|
|
1358
1824
|
}
|
|
1359
1825
|
getNextPatterns() {
|
|
1360
1826
|
if (this.parent == null) {
|
|
@@ -1362,11 +1828,8 @@
|
|
|
1362
1828
|
}
|
|
1363
1829
|
return this.parent.getPatternsAfter(this);
|
|
1364
1830
|
}
|
|
1365
|
-
|
|
1366
|
-
return null;
|
|
1367
|
-
}
|
|
1368
|
-
clone(name = this._name, isOptional = this._isOptional) {
|
|
1369
|
-
return new Reference(name, isOptional);
|
|
1831
|
+
find(predicate) {
|
|
1832
|
+
return predicate(this._children[0]) ? this._children[0] : null;
|
|
1370
1833
|
}
|
|
1371
1834
|
}
|
|
1372
1835
|
|
|
@@ -1377,72 +1840,73 @@
|
|
|
1377
1840
|
this._options = options;
|
|
1378
1841
|
this._text = "";
|
|
1379
1842
|
}
|
|
1380
|
-
|
|
1843
|
+
suggestFor(text) {
|
|
1381
1844
|
if (text.length === 0) {
|
|
1382
1845
|
return {
|
|
1383
1846
|
isComplete: false,
|
|
1384
|
-
options: this.
|
|
1385
|
-
|
|
1847
|
+
options: this._createSuggestionsFromRoot(),
|
|
1848
|
+
errorAtIndex: 0,
|
|
1386
1849
|
cursor: null,
|
|
1387
1850
|
ast: null
|
|
1388
1851
|
};
|
|
1389
1852
|
}
|
|
1390
1853
|
this._text = text;
|
|
1391
1854
|
this._cursor = new Cursor(text);
|
|
1855
|
+
let errorAtIndex = null;
|
|
1392
1856
|
const ast = this._pattern.parse(this._cursor);
|
|
1393
|
-
const leafPattern = this._cursor.leafMatch.pattern;
|
|
1394
1857
|
const isComplete = (ast === null || ast === void 0 ? void 0 : ast.value) === text;
|
|
1395
|
-
const options = this.
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1858
|
+
const options = this._getAllOptions();
|
|
1859
|
+
if (this._cursor.hasError && this._cursor.furthestError != null) {
|
|
1860
|
+
errorAtIndex = this._cursor.furthestError.index;
|
|
1861
|
+
errorAtIndex = options.reduce((errorAtIndex, option) => Math.max(errorAtIndex, option.startIndex), errorAtIndex);
|
|
1399
1862
|
}
|
|
1400
1863
|
return {
|
|
1401
1864
|
isComplete: isComplete,
|
|
1402
1865
|
options: options,
|
|
1403
|
-
|
|
1866
|
+
errorAtIndex,
|
|
1404
1867
|
cursor: this._cursor,
|
|
1405
1868
|
ast,
|
|
1406
1869
|
};
|
|
1407
1870
|
}
|
|
1408
|
-
|
|
1871
|
+
_getAllOptions() {
|
|
1872
|
+
return this._cursor.leafMatches.map((m) => this._createSuggestionsFromMatch(m)).flat();
|
|
1873
|
+
}
|
|
1874
|
+
_createSuggestionsFromRoot() {
|
|
1409
1875
|
const suggestions = [];
|
|
1410
1876
|
const tokens = this._pattern.getTokens();
|
|
1411
1877
|
for (const token of tokens) {
|
|
1412
|
-
suggestions.push(this.
|
|
1878
|
+
suggestions.push(this._createSuggestion("", token));
|
|
1413
1879
|
}
|
|
1414
1880
|
return suggestions;
|
|
1415
1881
|
}
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
return this.createSuggestions(-1, this._getTokensForPattern(this._pattern));
|
|
1882
|
+
_createSuggestionsFromMatch(match) {
|
|
1883
|
+
if (!match.pattern) {
|
|
1884
|
+
return this._createSuggestions(-1, this._getTokensForPattern(this._pattern));
|
|
1420
1885
|
}
|
|
1421
|
-
const leafPattern =
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
if (parent !== null && leafMatch.node != null) {
|
|
1886
|
+
const leafPattern = match.pattern;
|
|
1887
|
+
const parent = match.pattern.parent;
|
|
1888
|
+
if (parent !== null && match.node != null) {
|
|
1425
1889
|
const patterns = leafPattern.getNextPatterns();
|
|
1426
1890
|
const tokens = patterns.reduce((acc, pattern) => {
|
|
1427
1891
|
acc.push(...this._getTokensForPattern(pattern));
|
|
1428
1892
|
return acc;
|
|
1429
1893
|
}, []);
|
|
1430
|
-
return this.
|
|
1894
|
+
return this._createSuggestions(match.node.lastIndex, tokens);
|
|
1431
1895
|
}
|
|
1432
1896
|
else {
|
|
1433
1897
|
return [];
|
|
1434
1898
|
}
|
|
1435
1899
|
}
|
|
1436
1900
|
_getTokensForPattern(pattern) {
|
|
1437
|
-
|
|
1438
|
-
|
|
1901
|
+
const augmentedTokens = this._getAugmentedTokens(pattern);
|
|
1902
|
+
if (this._options.greedyPatternNames != null && this._options.greedyPatternNames.includes(pattern.name)) {
|
|
1439
1903
|
const nextPatterns = pattern.getNextPatterns();
|
|
1440
1904
|
const tokens = [];
|
|
1441
1905
|
const nextPatternTokens = nextPatterns.reduce((acc, pattern) => {
|
|
1442
1906
|
acc.push(...this._getTokensForPattern(pattern));
|
|
1443
1907
|
return acc;
|
|
1444
1908
|
}, []);
|
|
1445
|
-
for (let token of
|
|
1909
|
+
for (let token of augmentedTokens) {
|
|
1446
1910
|
for (let nextPatternToken of nextPatternTokens) {
|
|
1447
1911
|
tokens.push(token + nextPatternToken);
|
|
1448
1912
|
}
|
|
@@ -1450,13 +1914,20 @@
|
|
|
1450
1914
|
return tokens;
|
|
1451
1915
|
}
|
|
1452
1916
|
else {
|
|
1453
|
-
|
|
1454
|
-
const customTokens = this._options.customTokens[pattern.name] || [];
|
|
1455
|
-
tokens.push(...customTokens);
|
|
1456
|
-
return tokens;
|
|
1917
|
+
return augmentedTokens;
|
|
1457
1918
|
}
|
|
1458
1919
|
}
|
|
1459
|
-
|
|
1920
|
+
_getAugmentedTokens(pattern) {
|
|
1921
|
+
const customTokensMap = this._options.customTokens || {};
|
|
1922
|
+
const leafPatterns = pattern.getPatterns();
|
|
1923
|
+
const tokens = customTokensMap[pattern.name] || [];
|
|
1924
|
+
leafPatterns.forEach(p => {
|
|
1925
|
+
const augmentedTokens = customTokensMap[p.name] || [];
|
|
1926
|
+
tokens.push(...p.getTokens(), ...augmentedTokens);
|
|
1927
|
+
});
|
|
1928
|
+
return tokens;
|
|
1929
|
+
}
|
|
1930
|
+
_createSuggestions(lastIndex, tokens) {
|
|
1460
1931
|
let substring = lastIndex === -1 ? "" : this._cursor.getChars(0, lastIndex);
|
|
1461
1932
|
const suggestionStrings = [];
|
|
1462
1933
|
const options = [];
|
|
@@ -1467,14 +1938,14 @@
|
|
|
1467
1938
|
const isSameAsText = suggestion === this._text;
|
|
1468
1939
|
if (startsWith && !alreadyExist && !isSameAsText) {
|
|
1469
1940
|
suggestionStrings.push(suggestion);
|
|
1470
|
-
options.push(this.
|
|
1941
|
+
options.push(this._createSuggestion(this._cursor.text, suggestion));
|
|
1471
1942
|
}
|
|
1472
1943
|
}
|
|
1473
1944
|
const reducedOptions = getFurthestOptions(options);
|
|
1474
1945
|
reducedOptions.sort((a, b) => a.text.localeCompare(b.text));
|
|
1475
1946
|
return reducedOptions;
|
|
1476
1947
|
}
|
|
1477
|
-
|
|
1948
|
+
_createSuggestion(fullText, suggestion) {
|
|
1478
1949
|
const furthestMatch = findMatchIndex(suggestion, fullText);
|
|
1479
1950
|
const text = suggestion.slice(furthestMatch);
|
|
1480
1951
|
return {
|
|
@@ -1514,10 +1985,194 @@
|
|
|
1514
1985
|
return furthestOptions;
|
|
1515
1986
|
}
|
|
1516
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
|
+
|
|
1517
2171
|
exports.And = And;
|
|
1518
2172
|
exports.AutoComplete = AutoComplete;
|
|
1519
2173
|
exports.Cursor = Cursor;
|
|
1520
2174
|
exports.CursorHistory = CursorHistory;
|
|
2175
|
+
exports.Grammar = Grammar;
|
|
1521
2176
|
exports.Literal = Literal;
|
|
1522
2177
|
exports.Node = Node;
|
|
1523
2178
|
exports.Not = Not;
|
|
@@ -1529,5 +2184,5 @@
|
|
|
1529
2184
|
|
|
1530
2185
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
1531
2186
|
|
|
1532
|
-
}));
|
|
2187
|
+
})));
|
|
1533
2188
|
//# sourceMappingURL=index.browser.js.map
|