clarity-pattern-parser 8.4.14 → 9.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/TODO.md +4 -1
- package/dist/grammar/Grammar.d.ts +18 -10
- package/dist/grammar/patterns/andLiteral.d.ts +2 -0
- package/dist/grammar/patterns/anonymousPattern.d.ts +2 -0
- package/dist/grammar/patterns/inlinePattern.d.ts +1 -0
- package/dist/grammar/patterns/literals.d.ts +3 -0
- package/dist/grammar/patterns/pattern.d.ts +2 -2
- package/dist/grammar/patterns.d.ts +2 -0
- package/dist/index.browser.js +472 -185
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.esm.js +471 -186
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +472 -185
- package/dist/index.js.map +1 -1
- package/dist/patterns/And.d.ts +4 -1
- package/dist/patterns/Cursor.d.ts +5 -0
- package/dist/patterns/CursorHistory.d.ts +7 -0
- package/dist/patterns/FiniteRepeat.d.ts +4 -1
- package/dist/patterns/InfiniteRepeat.d.ts +5 -4
- package/dist/patterns/Literal.d.ts +6 -5
- package/dist/patterns/Not.d.ts +5 -4
- package/dist/patterns/Or.d.ts +5 -4
- package/dist/patterns/Pattern.d.ts +4 -2
- package/dist/patterns/Reference.d.ts +5 -4
- package/dist/patterns/Regex.d.ts +5 -4
- package/dist/patterns/Repeat.d.ts +3 -0
- package/dist/patterns/arePatternsEqual.d.ts +2 -0
- package/package.json +1 -1
- package/src/grammar/Grammar.test.ts +126 -72
- package/src/grammar/Grammar.ts +241 -158
- package/src/grammar/patterns/anonymousPattern.ts +23 -0
- package/src/grammar/patterns/body.ts +9 -6
- package/src/grammar/patterns/comment.ts +3 -2
- package/src/grammar/patterns/grammar.ts +15 -12
- package/src/grammar/patterns/import.ts +18 -12
- package/src/grammar/patterns/literal.ts +2 -3
- package/src/grammar/patterns/literals.ts +20 -0
- package/src/grammar/patterns/optionsLiteral.ts +19 -0
- package/src/grammar/patterns/pattern.ts +23 -9
- package/src/grammar/patterns/regexLiteral.ts +1 -0
- package/src/grammar/patterns/repeatLiteral.ts +30 -25
- package/src/grammar/patterns/sequenceLiteral.ts +24 -0
- package/src/grammar/patterns/spaces.ts +8 -6
- package/src/grammar/patterns/statement.ts +8 -20
- package/src/grammar/patterns.test.ts +38 -0
- package/src/grammar/patterns.ts +24 -0
- package/src/grammar/spec.md +4 -12
- package/src/index.ts +11 -5
- package/src/intellisense/AutoComplete.test.ts +41 -40
- package/src/intellisense/css/method.ts +2 -2
- package/src/intellisense/css/unit.ts +2 -2
- package/src/intellisense/css/value.ts +1 -1
- package/src/intellisense/javascript/Javascript.test.ts +31 -32
- package/src/intellisense/javascript/arrayLiteral.ts +7 -6
- package/src/intellisense/javascript/assignment.ts +6 -6
- package/src/intellisense/javascript/deleteStatement.ts +2 -2
- package/src/intellisense/javascript/escapedCharacter.ts +6 -6
- package/src/intellisense/javascript/exponent.ts +6 -6
- package/src/intellisense/javascript/expression.ts +18 -17
- package/src/intellisense/javascript/fraction.ts +3 -3
- package/src/intellisense/javascript/infixOperator.ts +10 -10
- package/src/intellisense/javascript/integer.ts +1 -1
- package/src/intellisense/javascript/invocation.ts +8 -7
- package/src/intellisense/javascript/literal.ts +3 -3
- package/src/intellisense/javascript/numberLiteral.ts +5 -4
- package/src/intellisense/javascript/objectAccess.ts +2 -3
- package/src/intellisense/javascript/objectLiteral.ts +8 -7
- package/src/intellisense/javascript/optionalSpaces.ts +2 -1
- package/src/intellisense/javascript/parameters.ts +5 -5
- package/src/intellisense/javascript/prefixOperator.ts +3 -4
- package/src/intellisense/javascript/propertyAccess.ts +9 -8
- package/src/intellisense/javascript/stringLiteral.ts +14 -15
- package/src/patterns/Cursor.ts +42 -4
- package/src/patterns/CursorHistory.ts +20 -4
- package/src/patterns/FiniteRepeat.test.ts +52 -51
- package/src/patterns/FiniteRepeat.ts +60 -38
- package/src/patterns/InfiniteRepeat.test.ts +36 -49
- package/src/patterns/InfiniteRepeat.ts +70 -37
- package/src/patterns/Literal.test.ts +16 -27
- package/src/patterns/Literal.ts +34 -27
- package/src/patterns/Not.test.ts +7 -7
- package/src/patterns/Not.ts +24 -6
- package/src/patterns/Optional.test.ts +164 -0
- package/src/patterns/Optional.ts +143 -0
- package/src/patterns/{Or.test.ts → Options.test.ts} +51 -49
- package/src/patterns/{Or.ts → Options.ts} +32 -23
- package/src/patterns/Pattern.ts +6 -5
- package/src/patterns/Reference.test.ts +21 -22
- package/src/patterns/Reference.ts +26 -15
- package/src/patterns/Regex.test.ts +15 -15
- package/src/patterns/Regex.ts +29 -19
- package/src/patterns/Repeat.test.ts +12 -22
- package/src/patterns/Repeat.ts +22 -21
- package/src/patterns/{And.test.ts → Sequence.test.ts} +78 -78
- package/src/patterns/{And.ts → Sequence.ts} +40 -29
- package/src/patterns/arePatternsEqual.ts +12 -0
- package/src/patterns/clonePatterns.ts +2 -2
- package/src/grammar/patterns/andLiteral.ts +0 -8
- package/src/grammar/patterns/orLiteral.ts +0 -8
|
@@ -3,12 +3,15 @@ import { Cursor } from "./Cursor";
|
|
|
3
3
|
import { Regex } from "./Regex";
|
|
4
4
|
import { Node } from "../ast/Node";
|
|
5
5
|
import { Literal } from "./Literal";
|
|
6
|
-
import {
|
|
6
|
+
import { Sequence } from "./Sequence";
|
|
7
|
+
import { arePatternsEqual } from "./arePatternsEqual";
|
|
8
|
+
import { Optional } from "./Optional";
|
|
7
9
|
|
|
8
10
|
describe("BoundedRepeat", () => {
|
|
9
11
|
test("Bounds Without Divider", () => {
|
|
10
|
-
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"),
|
|
11
|
-
min: 2
|
|
12
|
+
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), {
|
|
13
|
+
min: 2,
|
|
14
|
+
max: 3
|
|
12
15
|
});
|
|
13
16
|
|
|
14
17
|
let cursor = new Cursor("1");
|
|
@@ -62,7 +65,7 @@ describe("BoundedRepeat", () => {
|
|
|
62
65
|
});
|
|
63
66
|
|
|
64
67
|
test("Bounds Are Equal Without Divider", () => {
|
|
65
|
-
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"),
|
|
68
|
+
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), { min: 3, max: 3 });
|
|
66
69
|
|
|
67
70
|
let cursor = new Cursor("1");
|
|
68
71
|
let result = numbers.parse(cursor);
|
|
@@ -104,7 +107,7 @@ describe("BoundedRepeat", () => {
|
|
|
104
107
|
|
|
105
108
|
test("Bounds With Divider", () => {
|
|
106
109
|
const divider = new Literal("comma", ",");
|
|
107
|
-
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"),
|
|
110
|
+
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), { divider, min: 2, max: 3, trimDivider: true });
|
|
108
111
|
|
|
109
112
|
let cursor = new Cursor("1,");
|
|
110
113
|
let result = numbers.parse(cursor);
|
|
@@ -151,9 +154,9 @@ describe("BoundedRepeat", () => {
|
|
|
151
154
|
});
|
|
152
155
|
|
|
153
156
|
test("Optional Repeating Pattern", () => {
|
|
154
|
-
const digit = new Regex("digit", "\\d+"
|
|
157
|
+
const digit = new Optional("optional-digit", new Regex("digit", "\\d+"));
|
|
155
158
|
const divider = new Regex("divider", "\\s");
|
|
156
|
-
const integer = new FiniteRepeat("number", digit,
|
|
159
|
+
const integer = new FiniteRepeat("number", digit, { divider, max: 4 });
|
|
157
160
|
const cursor = new Cursor(
|
|
158
161
|
"\n" +
|
|
159
162
|
"3\n" +
|
|
@@ -169,13 +172,13 @@ describe("BoundedRepeat", () => {
|
|
|
169
172
|
new Node("regex", "divider", 4, 4, [], "\n"),
|
|
170
173
|
]);
|
|
171
174
|
|
|
172
|
-
expect(result).toEqual(expected)
|
|
173
|
-
expect(cursor.hasError).toBeFalsy()
|
|
175
|
+
expect(result).toEqual(expected);
|
|
176
|
+
expect(cursor.hasError).toBeFalsy();
|
|
174
177
|
});
|
|
175
178
|
|
|
176
179
|
test("Bounds Are Equal With Divider", () => {
|
|
177
180
|
const divider = new Literal("comma", ",");
|
|
178
|
-
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"),
|
|
181
|
+
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), { divider, min: 3, max: 3, trimDivider: true });
|
|
179
182
|
|
|
180
183
|
let cursor = new Cursor("1,");
|
|
181
184
|
let result = numbers.parse(cursor);
|
|
@@ -218,14 +221,14 @@ describe("BoundedRepeat", () => {
|
|
|
218
221
|
});
|
|
219
222
|
|
|
220
223
|
test("Test", () => {
|
|
221
|
-
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), 3);
|
|
224
|
+
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), { max: 3 });
|
|
222
225
|
const result = numbers.test("1");
|
|
223
226
|
|
|
224
227
|
expect(result).toBeTruthy();
|
|
225
228
|
});
|
|
226
229
|
|
|
227
230
|
test("Exec", () => {
|
|
228
|
-
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), 3);
|
|
231
|
+
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), { max: 3 });
|
|
229
232
|
const result = numbers.exec("1");
|
|
230
233
|
|
|
231
234
|
expect(result.ast).not.toBeNull();
|
|
@@ -233,7 +236,7 @@ describe("BoundedRepeat", () => {
|
|
|
233
236
|
});
|
|
234
237
|
|
|
235
238
|
test("Fail", () => {
|
|
236
|
-
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), 3);
|
|
239
|
+
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), { max: 3 });
|
|
237
240
|
const result = numbers.exec("f");
|
|
238
241
|
|
|
239
242
|
expect(result.ast).toBeNull();
|
|
@@ -241,7 +244,7 @@ describe("BoundedRepeat", () => {
|
|
|
241
244
|
});
|
|
242
245
|
|
|
243
246
|
test("Optional", () => {
|
|
244
|
-
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"),
|
|
247
|
+
const numbers = new FiniteRepeat("numbers", new Optional("optional-number", new Regex("number", "\\d")), { min: 0, max: 3 });
|
|
245
248
|
const result = numbers.exec("f");
|
|
246
249
|
|
|
247
250
|
expect(result.ast).toBeNull();
|
|
@@ -249,7 +252,7 @@ describe("BoundedRepeat", () => {
|
|
|
249
252
|
});
|
|
250
253
|
|
|
251
254
|
test("Optional With Multiple Matches But Still Below Min", () => {
|
|
252
|
-
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"),
|
|
255
|
+
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), { min: 0, max: 3 });
|
|
253
256
|
const result = numbers.exec("12f");
|
|
254
257
|
|
|
255
258
|
expect(result.ast).toBeNull();
|
|
@@ -257,19 +260,18 @@ describe("BoundedRepeat", () => {
|
|
|
257
260
|
});
|
|
258
261
|
|
|
259
262
|
test("Properties", () => {
|
|
260
|
-
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"),
|
|
263
|
+
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), { min: 1, max: 3 });
|
|
261
264
|
|
|
262
265
|
expect(numbers.type).toBe("finite-repeat");
|
|
263
266
|
expect(numbers.name).toBe("numbers");
|
|
264
267
|
expect(numbers.parent).toBeNull();
|
|
265
268
|
expect(numbers.children.length).toBe(3);
|
|
266
|
-
expect(numbers.min).toBe(
|
|
269
|
+
expect(numbers.min).toBe(1);
|
|
267
270
|
expect(numbers.max).toBe(3);
|
|
268
|
-
expect(numbers.isOptional).toBeTruthy();
|
|
269
271
|
});
|
|
270
272
|
|
|
271
273
|
test("Clone", () => {
|
|
272
|
-
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"),
|
|
274
|
+
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), { min: 0, max: 3 });
|
|
273
275
|
const clone = numbers.clone() as FiniteRepeat;
|
|
274
276
|
|
|
275
277
|
expect(clone.type).toBe(numbers.type);
|
|
@@ -278,40 +280,39 @@ describe("BoundedRepeat", () => {
|
|
|
278
280
|
expect(clone.children.length).toBe(numbers.children.length);
|
|
279
281
|
expect(clone.min).toBe(numbers.min);
|
|
280
282
|
expect(clone.max).toBe(numbers.max);
|
|
281
|
-
expect(clone.isOptional).toBe(numbers.isOptional);
|
|
282
283
|
});
|
|
283
284
|
|
|
284
285
|
test("Clone With Custom Overrides", () => {
|
|
285
|
-
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"),
|
|
286
|
+
const numbers = new FiniteRepeat("numbers", new Regex("number", "\\d"), { min: 0, max: 3 });
|
|
286
287
|
let clone = numbers.clone();
|
|
287
|
-
let expected = new FiniteRepeat("numbers", new Regex("number", "\\d"),
|
|
288
|
+
let expected = new FiniteRepeat("numbers", new Regex("number", "\\d"), { min: 0, max: 3 });
|
|
288
289
|
|
|
289
|
-
expect(clone).
|
|
290
|
+
expect(arePatternsEqual(clone, expected)).toBeTruthy();
|
|
290
291
|
|
|
291
292
|
clone = numbers.clone("cloned-numbers");
|
|
292
|
-
expected = new FiniteRepeat("cloned-numbers", new Regex("number", "\\d"),
|
|
293
|
+
expected = new FiniteRepeat("cloned-numbers", new Regex("number", "\\d"), { min: 0, max: 3 });
|
|
293
294
|
|
|
294
|
-
expect(clone).
|
|
295
|
+
expect(arePatternsEqual(clone, expected)).toBeTruthy();
|
|
295
296
|
|
|
296
|
-
clone = numbers.clone("cloned-numbers"
|
|
297
|
-
expected = new FiniteRepeat("cloned-numbers", new Regex("number", "\\d"),
|
|
297
|
+
clone = numbers.clone("cloned-numbers");
|
|
298
|
+
expected = new FiniteRepeat("cloned-numbers", new Regex("number", "\\d"), { min: 0, max: 3 });
|
|
298
299
|
|
|
299
|
-
expect(clone).
|
|
300
|
+
expect(arePatternsEqual(clone, expected)).toBeTruthy();
|
|
300
301
|
|
|
301
|
-
clone = numbers.clone("cloned-numbers"
|
|
302
|
-
expected = new FiniteRepeat("cloned-numbers", new Regex("number", "\\d"),
|
|
302
|
+
clone = numbers.clone("cloned-numbers");
|
|
303
|
+
expected = new FiniteRepeat("cloned-numbers", new Regex("number", "\\d"), { min: 0, max: 3 });
|
|
303
304
|
|
|
304
|
-
expect(clone).
|
|
305
|
+
expect(arePatternsEqual(clone, expected)).toBeTruthy();
|
|
305
306
|
});
|
|
306
307
|
|
|
307
308
|
test("Get Tokens", () => {
|
|
308
309
|
const numbers = new FiniteRepeat(
|
|
309
310
|
"numbers",
|
|
310
311
|
new Literal("one", "1"),
|
|
311
|
-
3,
|
|
312
312
|
{
|
|
313
313
|
divider: new Literal("comma", ","),
|
|
314
|
-
min: 0
|
|
314
|
+
min: 0,
|
|
315
|
+
max: 3
|
|
315
316
|
});
|
|
316
317
|
|
|
317
318
|
const tokens = numbers.getTokens();
|
|
@@ -323,10 +324,10 @@ describe("BoundedRepeat", () => {
|
|
|
323
324
|
const numbers = new FiniteRepeat(
|
|
324
325
|
"numbers",
|
|
325
326
|
new Literal("one", "1"),
|
|
326
|
-
2,
|
|
327
327
|
{
|
|
328
328
|
divider: new Literal("comma", ","),
|
|
329
329
|
min: 0,
|
|
330
|
+
max: 2,
|
|
330
331
|
trimDivider: true
|
|
331
332
|
});
|
|
332
333
|
|
|
@@ -350,14 +351,14 @@ describe("BoundedRepeat", () => {
|
|
|
350
351
|
const numbers = new FiniteRepeat(
|
|
351
352
|
"numbers",
|
|
352
353
|
new Literal("one", "1"),
|
|
353
|
-
2,
|
|
354
354
|
{
|
|
355
355
|
divider: new Literal("comma", ","),
|
|
356
356
|
trimDivider: true,
|
|
357
|
-
min: 0
|
|
357
|
+
min: 0,
|
|
358
|
+
max: 2
|
|
358
359
|
});
|
|
359
360
|
|
|
360
|
-
const parent = new
|
|
361
|
+
const parent = new Sequence("parent", [numbers, new Literal("b", "B")]);
|
|
361
362
|
const numbersClone = parent.children[0];
|
|
362
363
|
let child = numbersClone.children[0];
|
|
363
364
|
let tokens = numbersClone.getTokensAfter(child);
|
|
@@ -380,14 +381,14 @@ describe("BoundedRepeat", () => {
|
|
|
380
381
|
const numbers = new FiniteRepeat(
|
|
381
382
|
"numbers",
|
|
382
383
|
new Literal("one", "1"),
|
|
383
|
-
2,
|
|
384
384
|
{
|
|
385
385
|
divider: new Literal("comma", ","),
|
|
386
|
-
min: 0
|
|
386
|
+
min: 0,
|
|
387
|
+
max: 2
|
|
387
388
|
}
|
|
388
389
|
);
|
|
389
390
|
|
|
390
|
-
const parent = new
|
|
391
|
+
const parent = new Sequence("parent", [numbers, new Literal("b", "B")]);
|
|
391
392
|
const numbersClone = parent.children[0];
|
|
392
393
|
const tokens = numbersClone.getNextTokens();
|
|
393
394
|
|
|
@@ -399,10 +400,10 @@ describe("BoundedRepeat", () => {
|
|
|
399
400
|
const numbers = new FiniteRepeat(
|
|
400
401
|
"numbers",
|
|
401
402
|
new Literal("one", "1"),
|
|
402
|
-
2,
|
|
403
403
|
{
|
|
404
404
|
divider: new Literal("comma", ","),
|
|
405
|
-
min: 0
|
|
405
|
+
min: 0,
|
|
406
|
+
max: 2
|
|
406
407
|
}
|
|
407
408
|
);
|
|
408
409
|
|
|
@@ -416,10 +417,10 @@ describe("BoundedRepeat", () => {
|
|
|
416
417
|
const numbers = new FiniteRepeat(
|
|
417
418
|
"numbers",
|
|
418
419
|
new Literal("one", "1"),
|
|
419
|
-
2,
|
|
420
420
|
{
|
|
421
421
|
divider: new Literal("comma", ","),
|
|
422
|
-
min: 0
|
|
422
|
+
min: 0,
|
|
423
|
+
max: 2
|
|
423
424
|
}
|
|
424
425
|
);
|
|
425
426
|
|
|
@@ -432,10 +433,10 @@ describe("BoundedRepeat", () => {
|
|
|
432
433
|
const numbers = new FiniteRepeat(
|
|
433
434
|
"numbers",
|
|
434
435
|
new Literal("one", "1"),
|
|
435
|
-
2,
|
|
436
436
|
{
|
|
437
437
|
divider: new Literal("comma", ","),
|
|
438
|
-
min: 0
|
|
438
|
+
min: 0,
|
|
439
|
+
max: 2
|
|
439
440
|
}
|
|
440
441
|
);
|
|
441
442
|
|
|
@@ -448,14 +449,14 @@ describe("BoundedRepeat", () => {
|
|
|
448
449
|
const numbers = new FiniteRepeat(
|
|
449
450
|
"numbers",
|
|
450
451
|
new Literal("one", "1"),
|
|
451
|
-
2,
|
|
452
452
|
{
|
|
453
453
|
divider: new Literal("comma", ","),
|
|
454
|
-
min: 0
|
|
454
|
+
min: 0,
|
|
455
|
+
max: 2
|
|
455
456
|
}
|
|
456
457
|
);
|
|
457
458
|
|
|
458
|
-
const parent = new
|
|
459
|
+
const parent = new Sequence("parent", [numbers, new Literal("b", "B")]);
|
|
459
460
|
const numbersClone = parent.children[0];
|
|
460
461
|
|
|
461
462
|
const patterns = numbersClone.getNextPatterns();
|
|
@@ -467,10 +468,10 @@ describe("BoundedRepeat", () => {
|
|
|
467
468
|
const numbers = new FiniteRepeat(
|
|
468
469
|
"numbers",
|
|
469
470
|
new Literal("one", "1"),
|
|
470
|
-
2,
|
|
471
471
|
{
|
|
472
472
|
divider: new Literal("comma", ","),
|
|
473
|
-
min: 0
|
|
473
|
+
min: 0,
|
|
474
|
+
max: 2
|
|
474
475
|
}
|
|
475
476
|
);
|
|
476
477
|
|
|
@@ -4,13 +4,17 @@ import { findPattern } from "./findPattern";
|
|
|
4
4
|
import { ParseResult } from "./ParseResult";
|
|
5
5
|
import { Pattern } from "./Pattern";
|
|
6
6
|
|
|
7
|
+
let idIndex = 0;
|
|
8
|
+
|
|
7
9
|
export interface FiniteRepeatOptions {
|
|
8
10
|
divider?: Pattern;
|
|
9
11
|
min?: number;
|
|
12
|
+
max?: number;
|
|
10
13
|
trimDivider?: boolean;
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
export class FiniteRepeat implements Pattern {
|
|
17
|
+
private _id: string;
|
|
14
18
|
private _type: string;
|
|
15
19
|
private _name: string;
|
|
16
20
|
private _parent: Pattern | null;
|
|
@@ -20,6 +24,10 @@ export class FiniteRepeat implements Pattern {
|
|
|
20
24
|
private _max: number;
|
|
21
25
|
private _trimDivider: boolean;
|
|
22
26
|
|
|
27
|
+
get id() {
|
|
28
|
+
return this._id;
|
|
29
|
+
}
|
|
30
|
+
|
|
23
31
|
get type() {
|
|
24
32
|
return this._type;
|
|
25
33
|
}
|
|
@@ -40,10 +48,6 @@ export class FiniteRepeat implements Pattern {
|
|
|
40
48
|
return this._children;
|
|
41
49
|
}
|
|
42
50
|
|
|
43
|
-
get isOptional() {
|
|
44
|
-
return this._min === 0;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
51
|
get min() {
|
|
48
52
|
return this._min;
|
|
49
53
|
}
|
|
@@ -52,46 +56,56 @@ export class FiniteRepeat implements Pattern {
|
|
|
52
56
|
return this._max;
|
|
53
57
|
}
|
|
54
58
|
|
|
55
|
-
constructor(name: string, pattern: Pattern,
|
|
59
|
+
constructor(name: string, pattern: Pattern, options: FiniteRepeatOptions = {}) {
|
|
60
|
+
this._id = `finite-repeat-${idIndex++}`;
|
|
56
61
|
this._type = "finite-repeat";
|
|
57
62
|
this._name = name;
|
|
58
63
|
this._parent = null;
|
|
59
64
|
this._children = [];
|
|
60
65
|
this._hasDivider = options.divider != null;
|
|
61
|
-
this._min = options.min != null ? options.min : 1;
|
|
62
|
-
this._max =
|
|
66
|
+
this._min = options.min != null ? Math.max(options.min, 1) : 1;
|
|
67
|
+
this._max = Math.max(this.min, options.max || this.min);
|
|
63
68
|
this._trimDivider = options.trimDivider == null ? false : options.trimDivider;
|
|
64
69
|
|
|
65
|
-
for (let i = 0; i <
|
|
66
|
-
|
|
70
|
+
for (let i = 0; i < this._max; i++) {
|
|
71
|
+
const child = pattern.clone();
|
|
72
|
+
child.parent = this;
|
|
73
|
+
|
|
74
|
+
this._children.push(child);
|
|
67
75
|
|
|
68
|
-
if (options.divider != null && (i <
|
|
69
|
-
|
|
76
|
+
if (options.divider != null && (i < this._max - 1 || !this._trimDivider)) {
|
|
77
|
+
const divider = options.divider.clone();
|
|
78
|
+
divider.parent = this;
|
|
79
|
+
this._children.push(divider);
|
|
70
80
|
}
|
|
71
81
|
}
|
|
82
|
+
|
|
72
83
|
}
|
|
73
84
|
|
|
74
85
|
parse(cursor: Cursor): Node | null {
|
|
86
|
+
cursor.startParseWith(this);
|
|
87
|
+
|
|
75
88
|
const startIndex = cursor.index;
|
|
76
89
|
const nodes: Node[] = [];
|
|
77
90
|
const modulo = this._hasDivider ? 2 : 1;
|
|
78
91
|
let matchCount = 0;
|
|
79
92
|
|
|
80
|
-
|
|
81
93
|
for (let i = 0; i < this._children.length; i++) {
|
|
82
94
|
const childPattern = this._children[i];
|
|
95
|
+
const runningIndex = cursor.index;
|
|
83
96
|
const node = childPattern.parse(cursor);
|
|
84
97
|
|
|
85
|
-
if (i % modulo === 0 && !cursor.hasError) {
|
|
86
|
-
matchCount++
|
|
87
|
-
}
|
|
88
|
-
|
|
89
98
|
if (cursor.hasError) {
|
|
90
|
-
cursor.resolveError();
|
|
91
99
|
break;
|
|
92
100
|
}
|
|
93
101
|
|
|
94
|
-
if (
|
|
102
|
+
if (i % modulo === 0 && !cursor.hasError) {
|
|
103
|
+
matchCount++;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (node == null) {
|
|
107
|
+
cursor.moveTo(runningIndex);
|
|
108
|
+
} else {
|
|
95
109
|
nodes.push(node);
|
|
96
110
|
|
|
97
111
|
if (cursor.hasNext()) {
|
|
@@ -100,13 +114,13 @@ export class FiniteRepeat implements Pattern {
|
|
|
100
114
|
break;
|
|
101
115
|
}
|
|
102
116
|
}
|
|
103
|
-
|
|
104
117
|
}
|
|
105
118
|
|
|
106
119
|
if (this._trimDivider && this._hasDivider) {
|
|
107
|
-
|
|
120
|
+
const isDividerLastMatch = cursor.leafMatch.pattern === this.children[1];
|
|
121
|
+
if (isDividerLastMatch) {
|
|
108
122
|
const node = nodes.pop() as Node;
|
|
109
|
-
cursor.moveTo(node.firstIndex)
|
|
123
|
+
cursor.moveTo(node.firstIndex);
|
|
110
124
|
}
|
|
111
125
|
}
|
|
112
126
|
|
|
@@ -114,17 +128,22 @@ export class FiniteRepeat implements Pattern {
|
|
|
114
128
|
const lastIndex = cursor.index;
|
|
115
129
|
cursor.moveTo(startIndex);
|
|
116
130
|
cursor.recordErrorAt(startIndex, lastIndex, this);
|
|
131
|
+
cursor.endParse();
|
|
117
132
|
return null;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (nodes.length === 0 && !cursor.hasError) {
|
|
136
|
+
cursor.moveTo(startIndex);
|
|
137
|
+
cursor.endParse();
|
|
121
138
|
return null;
|
|
122
139
|
}
|
|
123
140
|
|
|
124
141
|
const firstIndex = nodes[0].firstIndex;
|
|
125
142
|
const lastIndex = nodes[nodes.length - 1].lastIndex;
|
|
126
143
|
|
|
144
|
+
cursor.resolveError();
|
|
127
145
|
cursor.moveTo(lastIndex);
|
|
146
|
+
cursor.endParse();
|
|
128
147
|
|
|
129
148
|
return new Node(this._type, this.name, firstIndex, lastIndex, nodes);
|
|
130
149
|
}
|
|
@@ -136,8 +155,10 @@ export class FiniteRepeat implements Pattern {
|
|
|
136
155
|
return ast?.value === text;
|
|
137
156
|
}
|
|
138
157
|
|
|
139
|
-
exec(text: string): ParseResult {
|
|
158
|
+
exec(text: string, record = false): ParseResult {
|
|
140
159
|
const cursor = new Cursor(text);
|
|
160
|
+
record && cursor.startRecording();
|
|
161
|
+
|
|
141
162
|
const ast = this.parse(cursor);
|
|
142
163
|
|
|
143
164
|
return {
|
|
@@ -146,27 +167,24 @@ export class FiniteRepeat implements Pattern {
|
|
|
146
167
|
};
|
|
147
168
|
}
|
|
148
169
|
|
|
149
|
-
clone(name = this._name
|
|
170
|
+
clone(name = this._name): Pattern {
|
|
150
171
|
let min = this._min;
|
|
172
|
+
let max = this._max;
|
|
151
173
|
|
|
152
|
-
|
|
153
|
-
if (isOptional) {
|
|
154
|
-
min = 0
|
|
155
|
-
} else {
|
|
156
|
-
min = Math.max(this._min, 1);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return new FiniteRepeat(
|
|
174
|
+
const clone = new FiniteRepeat(
|
|
161
175
|
name,
|
|
162
176
|
this._children[0],
|
|
163
|
-
this._max,
|
|
164
177
|
{
|
|
165
178
|
divider: this._hasDivider ? this._children[1] : undefined,
|
|
166
179
|
min,
|
|
180
|
+
max,
|
|
167
181
|
trimDivider: this._trimDivider
|
|
168
182
|
}
|
|
169
183
|
);
|
|
184
|
+
|
|
185
|
+
clone._id = this._id;
|
|
186
|
+
|
|
187
|
+
return clone;
|
|
170
188
|
}
|
|
171
189
|
|
|
172
190
|
getTokens(): string[] {
|
|
@@ -184,7 +202,7 @@ export class FiniteRepeat implements Pattern {
|
|
|
184
202
|
|
|
185
203
|
getNextTokens(): string[] {
|
|
186
204
|
if (this._parent == null) {
|
|
187
|
-
return []
|
|
205
|
+
return [];
|
|
188
206
|
}
|
|
189
207
|
|
|
190
208
|
return this._parent.getTokensAfter(this);
|
|
@@ -214,7 +232,7 @@ export class FiniteRepeat implements Pattern {
|
|
|
214
232
|
// Get the next childs patterns.
|
|
215
233
|
const nextChild = this._children[childIndex + 1];
|
|
216
234
|
|
|
217
|
-
return nextChild.getPatterns()
|
|
235
|
+
return nextChild.getPatterns();
|
|
218
236
|
}
|
|
219
237
|
|
|
220
238
|
getNextPatterns(): Pattern[] {
|
|
@@ -229,4 +247,8 @@ export class FiniteRepeat implements Pattern {
|
|
|
229
247
|
return findPattern(this, predicate);
|
|
230
248
|
}
|
|
231
249
|
|
|
250
|
+
isEqual(pattern: FiniteRepeat): boolean {
|
|
251
|
+
return pattern.type === this.type && this.children.every((c, index) => c.isEqual(pattern.children[index]));
|
|
252
|
+
}
|
|
253
|
+
|
|
232
254
|
}
|