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.
Files changed (100) hide show
  1. package/TODO.md +4 -1
  2. package/dist/grammar/Grammar.d.ts +18 -10
  3. package/dist/grammar/patterns/andLiteral.d.ts +2 -0
  4. package/dist/grammar/patterns/anonymousPattern.d.ts +2 -0
  5. package/dist/grammar/patterns/inlinePattern.d.ts +1 -0
  6. package/dist/grammar/patterns/literals.d.ts +3 -0
  7. package/dist/grammar/patterns/pattern.d.ts +2 -2
  8. package/dist/grammar/patterns.d.ts +2 -0
  9. package/dist/index.browser.js +472 -185
  10. package/dist/index.browser.js.map +1 -1
  11. package/dist/index.d.ts +3 -1
  12. package/dist/index.esm.js +471 -186
  13. package/dist/index.esm.js.map +1 -1
  14. package/dist/index.js +472 -185
  15. package/dist/index.js.map +1 -1
  16. package/dist/patterns/And.d.ts +4 -1
  17. package/dist/patterns/Cursor.d.ts +5 -0
  18. package/dist/patterns/CursorHistory.d.ts +7 -0
  19. package/dist/patterns/FiniteRepeat.d.ts +4 -1
  20. package/dist/patterns/InfiniteRepeat.d.ts +5 -4
  21. package/dist/patterns/Literal.d.ts +6 -5
  22. package/dist/patterns/Not.d.ts +5 -4
  23. package/dist/patterns/Or.d.ts +5 -4
  24. package/dist/patterns/Pattern.d.ts +4 -2
  25. package/dist/patterns/Reference.d.ts +5 -4
  26. package/dist/patterns/Regex.d.ts +5 -4
  27. package/dist/patterns/Repeat.d.ts +3 -0
  28. package/dist/patterns/arePatternsEqual.d.ts +2 -0
  29. package/package.json +1 -1
  30. package/src/grammar/Grammar.test.ts +126 -72
  31. package/src/grammar/Grammar.ts +241 -158
  32. package/src/grammar/patterns/anonymousPattern.ts +23 -0
  33. package/src/grammar/patterns/body.ts +9 -6
  34. package/src/grammar/patterns/comment.ts +3 -2
  35. package/src/grammar/patterns/grammar.ts +15 -12
  36. package/src/grammar/patterns/import.ts +18 -12
  37. package/src/grammar/patterns/literal.ts +2 -3
  38. package/src/grammar/patterns/literals.ts +20 -0
  39. package/src/grammar/patterns/optionsLiteral.ts +19 -0
  40. package/src/grammar/patterns/pattern.ts +23 -9
  41. package/src/grammar/patterns/regexLiteral.ts +1 -0
  42. package/src/grammar/patterns/repeatLiteral.ts +30 -25
  43. package/src/grammar/patterns/sequenceLiteral.ts +24 -0
  44. package/src/grammar/patterns/spaces.ts +8 -6
  45. package/src/grammar/patterns/statement.ts +8 -20
  46. package/src/grammar/patterns.test.ts +38 -0
  47. package/src/grammar/patterns.ts +24 -0
  48. package/src/grammar/spec.md +4 -12
  49. package/src/index.ts +11 -5
  50. package/src/intellisense/AutoComplete.test.ts +41 -40
  51. package/src/intellisense/css/method.ts +2 -2
  52. package/src/intellisense/css/unit.ts +2 -2
  53. package/src/intellisense/css/value.ts +1 -1
  54. package/src/intellisense/javascript/Javascript.test.ts +31 -32
  55. package/src/intellisense/javascript/arrayLiteral.ts +7 -6
  56. package/src/intellisense/javascript/assignment.ts +6 -6
  57. package/src/intellisense/javascript/deleteStatement.ts +2 -2
  58. package/src/intellisense/javascript/escapedCharacter.ts +6 -6
  59. package/src/intellisense/javascript/exponent.ts +6 -6
  60. package/src/intellisense/javascript/expression.ts +18 -17
  61. package/src/intellisense/javascript/fraction.ts +3 -3
  62. package/src/intellisense/javascript/infixOperator.ts +10 -10
  63. package/src/intellisense/javascript/integer.ts +1 -1
  64. package/src/intellisense/javascript/invocation.ts +8 -7
  65. package/src/intellisense/javascript/literal.ts +3 -3
  66. package/src/intellisense/javascript/numberLiteral.ts +5 -4
  67. package/src/intellisense/javascript/objectAccess.ts +2 -3
  68. package/src/intellisense/javascript/objectLiteral.ts +8 -7
  69. package/src/intellisense/javascript/optionalSpaces.ts +2 -1
  70. package/src/intellisense/javascript/parameters.ts +5 -5
  71. package/src/intellisense/javascript/prefixOperator.ts +3 -4
  72. package/src/intellisense/javascript/propertyAccess.ts +9 -8
  73. package/src/intellisense/javascript/stringLiteral.ts +14 -15
  74. package/src/patterns/Cursor.ts +42 -4
  75. package/src/patterns/CursorHistory.ts +20 -4
  76. package/src/patterns/FiniteRepeat.test.ts +52 -51
  77. package/src/patterns/FiniteRepeat.ts +60 -38
  78. package/src/patterns/InfiniteRepeat.test.ts +36 -49
  79. package/src/patterns/InfiniteRepeat.ts +70 -37
  80. package/src/patterns/Literal.test.ts +16 -27
  81. package/src/patterns/Literal.ts +34 -27
  82. package/src/patterns/Not.test.ts +7 -7
  83. package/src/patterns/Not.ts +24 -6
  84. package/src/patterns/Optional.test.ts +164 -0
  85. package/src/patterns/Optional.ts +143 -0
  86. package/src/patterns/{Or.test.ts → Options.test.ts} +51 -49
  87. package/src/patterns/{Or.ts → Options.ts} +32 -23
  88. package/src/patterns/Pattern.ts +6 -5
  89. package/src/patterns/Reference.test.ts +21 -22
  90. package/src/patterns/Reference.ts +26 -15
  91. package/src/patterns/Regex.test.ts +15 -15
  92. package/src/patterns/Regex.ts +29 -19
  93. package/src/patterns/Repeat.test.ts +12 -22
  94. package/src/patterns/Repeat.ts +22 -21
  95. package/src/patterns/{And.test.ts → Sequence.test.ts} +78 -78
  96. package/src/patterns/{And.ts → Sequence.ts} +40 -29
  97. package/src/patterns/arePatternsEqual.ts +12 -0
  98. package/src/patterns/clonePatterns.ts +2 -2
  99. package/src/grammar/patterns/andLiteral.ts +0 -8
  100. package/src/grammar/patterns/orLiteral.ts +0 -8
@@ -4,11 +4,24 @@ import { Pattern } from "../patterns/Pattern";
4
4
  import { Regex } from "../patterns/Regex";
5
5
  import { Reference } from "../patterns/Reference";
6
6
  import { grammar } from "./patterns/grammar";
7
- import { Or } from "../patterns/Or";
7
+ import { Options } from "../patterns/Options";
8
8
  import { Not } from "../patterns/Not";
9
- import { And } from "../patterns/And";
9
+ import { Sequence } from "../patterns/Sequence";
10
10
  import { Repeat, RepeatOptions } from "../patterns/Repeat";
11
11
  import { AutoComplete } from "../intellisense/AutoComplete";
12
+ import { Optional } from "../patterns/Optional";
13
+
14
+ let anonymousIndexId = 0;
15
+
16
+ const patternNodes: Record<string, boolean> = {
17
+ "literal": true,
18
+ "regex-literal": true,
19
+ "options-literal": true,
20
+ "sequence-literal": true,
21
+ "repeat-literal": true,
22
+ "alias-literal": true,
23
+ "configurable-anonymous-pattern": true
24
+ };
12
25
 
13
26
  class ParseContext {
14
27
  constructor(params: Pattern[]) {
@@ -75,7 +88,7 @@ export class Grammar {
75
88
  await this._resolveImports(ast);
76
89
  this._buildPatterns(ast);
77
90
 
78
- return this._parseContext.patternsByName;
91
+ return Object.fromEntries(this._parseContext.patternsByName) as Record<string, Pattern>;
79
92
  }
80
93
 
81
94
  parseString(expression: string) {
@@ -85,9 +98,8 @@ export class Grammar {
85
98
  if (this._hasImports(ast)) {
86
99
  throw new Error("Cannot use imports on parseString, use parse instead.");
87
100
  }
88
-
89
101
  this._buildPatterns(ast);
90
- return this._parseContext.patternsByName;
102
+ return Object.fromEntries(this._parseContext.patternsByName) as Record<string, Pattern>;
91
103
  }
92
104
 
93
105
  private _tryToParse(expression: string): Node {
@@ -101,7 +113,7 @@ export class Grammar {
101
113
  const startText = text.slice(Math.max(o.startIndex - 10), o.startIndex);
102
114
  return startText + o.text;
103
115
  }).join("' or '") + "'";
104
- const message = `[Parse Error] Found: '${foundText}', expected: ${expectedTexts}.`
116
+ const message = `[Parse Error] Found: '${foundText}', expected: ${expectedTexts}.`;
105
117
  throw new Error(message);
106
118
  }
107
119
 
@@ -125,38 +137,40 @@ export class Grammar {
125
137
  return;
126
138
  }
127
139
 
128
- body.findAll(n => n.name === "assign-statement" || n.name === "export-name").forEach((n) => {
129
- const typeNode = n.find(n => n.name.includes("literal"));
130
- const type = n.name === "export-name" ? "export-name" : typeNode?.name || "unknown";
140
+ body.findAll(n => n.name === "assign-statement").forEach((n) => {
141
+ const patternNode = n.children.find(n => patternNodes[n.name] != null);
131
142
 
132
- switch (type) {
143
+ if (patternNode == null) {
144
+ return;
145
+ }
146
+
147
+ switch (patternNode.name) {
133
148
  case "literal": {
134
- this._buildLiteral(n)
149
+ this._saveLiteral(n);
135
150
  break;
136
151
  }
137
152
  case "regex-literal": {
138
- this._buildRegex(n);
153
+ this._saveRegex(n);
139
154
  break;
140
155
  }
141
- case "or-literal": {
142
- this._buildOr(n);
156
+ case "options-literal": {
157
+ this._saveOptions(n);
143
158
  break;
144
159
  }
145
- case "and-literal": {
146
- this._buildAnd(n)
160
+ case "sequence-literal": {
161
+ this._saveSequence(n);
147
162
  break;
148
163
  }
149
164
  case "repeat-literal": {
150
- this._buildRepeat(n)
165
+ this._saveRepeat(n);
151
166
  break;
152
167
  }
153
168
  case "alias-literal": {
154
- this._buildAlias(n)
169
+ this._saveAlias(n);
155
170
  break;
156
171
  }
157
- case "export-name": {
158
- const pattern = this._getPattern(n.value);
159
- this._parseContext.patternsByName.set(n.value, pattern);
172
+ case "configurable-anonymous-pattern": {
173
+ this._saveConfigurableAnonymous(n);
160
174
  break;
161
175
  }
162
176
  default: {
@@ -164,6 +178,205 @@ export class Grammar {
164
178
  }
165
179
  }
166
180
  });
181
+
182
+ body.findAll(n => n.name === "export-name").forEach((n) => {
183
+ const pattern = this._getPattern(n.value).clone();
184
+ this._parseContext.patternsByName.set(n.value, pattern);
185
+ });
186
+ }
187
+
188
+ private _saveLiteral(statementNode: Node) {
189
+ const nameNode = statementNode.find(n => n.name === "name") as Node;
190
+ const literalNode = statementNode.find(n => n.name === "literal") as Node;
191
+ const name = nameNode.value;
192
+ const literal = this._buildLiteral(name, literalNode);
193
+
194
+ this._parseContext.patternsByName.set(name, literal);
195
+ }
196
+
197
+ private _buildLiteral(name: string, node: Node) {
198
+ return new Literal(name, this._resolveStringValue(node.value));
199
+ }
200
+
201
+ private _resolveStringValue(value: string) {
202
+ return value.replace(/\\n/g, '\n')
203
+ .replace(/\\r/g, '\r')
204
+ .replace(/\\t/g, '\t')
205
+ .replace(/\\b/g, '\b')
206
+ .replace(/\\f/g, '\f')
207
+ .replace(/\\v/g, '\v')
208
+ .replace(/\\0/g, '\0')
209
+ .replace(/\\x([0-9A-Fa-f]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
210
+ .replace(/\\u([0-9A-Fa-f]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
211
+ .replace(/\\(.)/g, '$1').slice(1, -1);
212
+ }
213
+
214
+ private _saveRegex(statementNode: Node) {
215
+ const nameNode = statementNode.find(n => n.name === "name") as Node;
216
+ const regexNode = statementNode.find(n => n.name === "regex-literal") as Node;
217
+ const name = nameNode.value;
218
+ const regex = this._buildRegex(name, regexNode);
219
+
220
+ this._parseContext.patternsByName.set(name, regex);
221
+ }
222
+
223
+ private _buildRegex(name: string, node: Node) {
224
+ const value = node.value.slice(1, node.value.length - 1);
225
+ return new Regex(name, value);
226
+ }
227
+
228
+ private _saveOptions(statementNode: Node) {
229
+ const nameNode = statementNode.find(n => n.name === "name") as Node;
230
+ const name = nameNode.value;
231
+ const optionsNode = statementNode.find(n => n.name === "options-literal") as Node;
232
+ const options = this._buildOptions(name, optionsNode);
233
+
234
+ this._parseContext.patternsByName.set(name, options);
235
+ }
236
+
237
+ private _buildOptions(name: string, node: Node) {
238
+ const patternNodes = node.children.filter(n => n.name !== "default-divider" && n.name !== "greedy-divider");
239
+ const isGreedy = node.find(n => n.name === "greedy-divider") != null;
240
+ const patterns = patternNodes.map(n => this._buildPattern(n));
241
+ const or = new Options(name, patterns, isGreedy);
242
+
243
+ return or;
244
+ }
245
+
246
+ private _buildPattern(node: Node): Pattern {
247
+ const type = node.name;
248
+ const name = `anonymous-pattern-${anonymousIndexId++}`;
249
+
250
+ switch (type) {
251
+ case "pattern-name": {
252
+ return this._getPattern(node.value).clone();
253
+ }
254
+ case "literal": {
255
+ return this._buildLiteral(node.value.slice(1, -1), node);
256
+ }
257
+ case "regex-literal": {
258
+ return this._buildRegex(node.value.slice(1, -1), node);
259
+ }
260
+ case "repeat-literal": {
261
+ return this._buildRepeat(name, node);
262
+ }
263
+ case "options-literal": {
264
+ return this._buildOptions(name, node);
265
+ }
266
+ case "sequence-literal": {
267
+ return this._buildSequence(name, node);
268
+ }
269
+ case "complex-anonymous-pattern": {
270
+ return this._buildComplexAnonymousPattern(node);
271
+ }
272
+ }
273
+
274
+ throw new Error(`Couldn't build node: ${node.name}.`);
275
+ }
276
+
277
+ private _saveSequence(statementNode: Node) {
278
+ const nameNode = statementNode.find(n => n.name === "name") as Node;
279
+ const name = nameNode.value;
280
+ const sequenceNode = statementNode.find(n => n.name === "sequence-literal") as Node;
281
+ const sequence = this._buildSequence(name, sequenceNode);
282
+
283
+ this._parseContext.patternsByName.set(name, sequence);
284
+ }
285
+
286
+ private _buildSequence(name: string, node: Node) {
287
+ const patternNodes = node.children.filter(n => n.name !== "and-divider");
288
+
289
+ const patterns = patternNodes.map(n => {
290
+ const patternNode = n.children[0].name === "not" ? n.children[1] : n.children[0];
291
+ const isNot = n.find(n => n.name === "not") != null;
292
+ const isOptional = n.find(n => n.name === "is-optional");
293
+ const pattern = this._buildPattern(patternNode);
294
+ const finalPattern = isOptional ? new Optional(pattern.name, pattern) : pattern;
295
+
296
+ if (isNot) {
297
+ return new Not(`not-${finalPattern.name}`, finalPattern);
298
+ }
299
+
300
+ return finalPattern;
301
+ });
302
+
303
+ return new Sequence(name, patterns);
304
+ }
305
+
306
+ private _saveRepeat(statementNode: Node) {
307
+ const nameNode = statementNode.find(n => n.name === "name") as Node;
308
+ const name = nameNode.value;
309
+ const repeatNode = statementNode.find(n => n.name === "repeat-literal") as Node;
310
+ const repeat = this._buildRepeat(name, repeatNode);
311
+
312
+ this._parseContext.patternsByName.set(name, repeat);
313
+ }
314
+
315
+ private _buildRepeat(name: string, repeatNode: Node) {
316
+ let isOptional = false;
317
+ const bounds = repeatNode.find(n => n.name === "bounds");
318
+ const exactCount = repeatNode.find(n => n.name === "exact-count");
319
+ const quantifier = repeatNode.find(n => n.name === "quantifier-shorthand");
320
+ const trimDivider = repeatNode.find(n => n.name === "trim-flag") != null;
321
+ const patterNode = repeatNode.children[1].type === "spaces" ? repeatNode.children[2] : repeatNode.children[1];
322
+ const pattern = this._buildPattern(patterNode);
323
+ const dividerSectionNode = repeatNode.find(n => n.name === "divider-section");
324
+
325
+ const options: RepeatOptions = {
326
+ min: 1,
327
+ max: Infinity
328
+ };
329
+
330
+ if (trimDivider) {
331
+ options.trimDivider = trimDivider;
332
+ }
333
+
334
+ if (dividerSectionNode != null) {
335
+ const dividerNode = dividerSectionNode.children[1];
336
+ options.divider = this._buildPattern(dividerNode);
337
+ }
338
+
339
+ if (bounds != null) {
340
+ const minNode = bounds.find(p => p.name === "min");
341
+ const maxNode = bounds.find(p => p.name === "max");
342
+
343
+ const min = minNode == null ? 0 : Number(minNode.value);
344
+ const max = maxNode == null ? Infinity : Number(maxNode.value);
345
+
346
+ options.min = min;
347
+ options.max = max;
348
+ } else if (exactCount != null) {
349
+ const integerNode = exactCount.find(p => p.name === "integer") as Node;
350
+ const integer = Number(integerNode.value);
351
+
352
+ options.min = integer;
353
+ options.max = integer;
354
+ } else if (quantifier != null) {
355
+ const type = quantifier.value;
356
+ if (type === "+") {
357
+ options.min = 1;
358
+ options.max = Infinity;
359
+ } else {
360
+ isOptional = true;
361
+ }
362
+ }
363
+
364
+ return isOptional ? new Optional(name, new Repeat(name, pattern, options)) : new Repeat(name, pattern, options);
365
+ }
366
+
367
+ private _saveConfigurableAnonymous(node: Node) {
368
+ const nameNode = node.find(n => n.name === "name") as Node;
369
+ const name = nameNode.value;
370
+ const anonymousNode = node.find(n => n.name === "complex-anonymous-pattern") as Node;
371
+ const isOptional = node.children[1] != null;
372
+
373
+ const anonymous = isOptional ? new Optional(name, this._buildPattern(anonymousNode)) : this._buildPattern(anonymousNode);
374
+ this._parseContext.patternsByName.set(name, anonymous);
375
+ }
376
+
377
+ private _buildComplexAnonymousPattern(node: Node) {
378
+ const wrappedNode = node.children[1].name === "line-spaces" ? node.children[2] : node.children[1];
379
+ return this._buildPattern(wrappedNode);
167
380
  }
168
381
 
169
382
  private async _resolveImports(ast: Node) {
@@ -197,7 +410,7 @@ export class Grammar {
197
410
  throw new Error(`'${importName}' was already used within another import.`);
198
411
  }
199
412
 
200
- const pattern = patterns.get(importName);
413
+ const pattern = patterns[importName];
201
414
  if (pattern == null) {
202
415
  throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
203
416
  }
@@ -213,7 +426,7 @@ export class Grammar {
213
426
  throw new Error(`'${alias}' was already used within another import.`);
214
427
  }
215
428
 
216
- const pattern = patterns.get(importName);
429
+ const pattern = patterns[importName];
217
430
  if (pattern == null) {
218
431
  throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
219
432
  }
@@ -244,7 +457,7 @@ export class Grammar {
244
457
  ._parseContext
245
458
  .importedPatternsByName
246
459
  .values()
247
- )
460
+ );
248
461
 
249
462
  const grammar = new Grammar({
250
463
  params: importedValues,
@@ -253,59 +466,13 @@ export class Grammar {
253
466
  });
254
467
 
255
468
  const patterns = grammar.parseString(expression);
256
- params = Array.from(patterns.values());
469
+ params = Array.from(Object.values(patterns));
257
470
  }
258
471
  }
259
472
 
260
473
  return params;
261
474
  }
262
475
 
263
- private _buildLiteral(statementNode: Node) {
264
- const nameNode = statementNode.find(n => n.name === "name") as Node;
265
- const literalNode = statementNode.find(n => n.name === "literal") as Node;
266
- const name = nameNode.value;
267
- const value = this._resolveStringValue(literalNode.value.slice(1, -1));
268
- const literal = new Literal(name, value);
269
-
270
- this._parseContext.patternsByName.set(name, literal)
271
- }
272
-
273
- private _resolveStringValue(value: string) {
274
- return value.replace(/\\n/g, '\n')
275
- .replace(/\\r/g, '\r')
276
- .replace(/\\t/g, '\t')
277
- .replace(/\\b/g, '\b')
278
- .replace(/\\f/g, '\f')
279
- .replace(/\\v/g, '\v')
280
- .replace(/\\0/g, '\0')
281
- .replace(/\\x([0-9A-Fa-f]{2})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
282
- .replace(/\\u([0-9A-Fa-f]{4})/g, (_, hex) => String.fromCharCode(parseInt(hex, 16)))
283
- .replace(/\\(.)/g, '$1');
284
- }
285
-
286
- private _buildRegex(statementNode: Node) {
287
- const nameNode = statementNode.find(n => n.name === "name") as Node;
288
- const regexNode = statementNode.find(n => n.name === "regex-literal") as Node;
289
- const value = regexNode.value.slice(1, regexNode.value.length - 1);
290
- const name = nameNode.value;
291
-
292
- const regex = new Regex(name, value);
293
-
294
- this._parseContext.patternsByName.set(name, regex);
295
- }
296
-
297
- private _buildOr(statementNode: Node) {
298
- const nameNode = statementNode.find(n => n.name === "name") as Node;
299
- const orNode = statementNode.find(n => n.name === "or-literal") as Node;
300
- const patternNodes = orNode.children.filter(n => n.name === "pattern-name");
301
-
302
- const name = nameNode.value;
303
- const patterns = patternNodes.map(n => this._getPattern(n.value));
304
- const or = new Or(name, patterns, false, true);
305
-
306
- this._parseContext.patternsByName.set(name, or);
307
- }
308
-
309
476
  private _getPattern(name: string) {
310
477
  let pattern = this._parseContext.patternsByName.get(name);
311
478
 
@@ -324,98 +491,14 @@ export class Grammar {
324
491
  return pattern;
325
492
  }
326
493
 
327
- private _buildAnd(statementNode: Node) {
328
- const nameNode = statementNode.find(n => n.name === "name") as Node;
329
- const andNode = statementNode.find(n => n.name === "and-literal") as Node;
330
- const patternNodes = andNode.children.filter(n => n.name === "pattern");
331
-
332
- const name = nameNode.value;
333
- const patterns = patternNodes.map(n => {
334
- const nameNode = n.find(n => n.name === "pattern-name") as Node;
335
- const isNot = n.find(n => n.name === "not") != null;
336
- const isOptional = n.find(n => n.name === "is-optional") != null;
337
- const name = nameNode.value;
338
- const pattern = this._getPattern(name);
339
-
340
- if (isNot) {
341
- return new Not(`not-${name}`, pattern.clone(name, isOptional));
342
- }
343
-
344
- return pattern.clone(name, isOptional);
345
- });
346
-
347
- const and = new And(name, patterns);
348
-
349
- this._parseContext.patternsByName.set(name, and);
350
- }
351
-
352
- private _buildRepeat(statementNode: Node) {
353
- const nameNode = statementNode.find(n => n.name === "name") as Node;
354
- const repeatNode = statementNode.find(n => n.name === "repeat-literal") as Node;
355
- const patternNameNode = statementNode.find(n => n.name === "pattern-name") as Node;
356
- const dividerNode = repeatNode.find(n => n.name === "divider-pattern");
357
- const bounds = repeatNode.find(n => n.name === "bounds");
358
- const exactCount = repeatNode.find(n => n.name === "exact-count");
359
- const quantifier = repeatNode.find(n => n.name === "quantifier-shorthand");
360
- const isPatternOptional = repeatNode.find(n => n.name === "is-optional") != null;
361
- const trimDivider = repeatNode.find(n => n.name === "trim-divider") != null;
362
-
363
- const name = nameNode.value;
364
- const pattern = this._getPattern(patternNameNode.value);
365
-
366
- const options: RepeatOptions = {
367
- min: 1,
368
- max: Infinity
369
- }
370
-
371
- if (trimDivider) {
372
- options.trimDivider = trimDivider;
373
- }
374
-
375
- if (dividerNode != null) {
376
- options.divider = this._getPattern(dividerNode.value);
377
- }
378
-
379
- if (bounds != null) {
380
- const minNode = bounds.find(p => p.name === "min");
381
- const maxNode = bounds.find(p => p.name === "max");
382
-
383
- const min = minNode == null ? 0 : Number(minNode.value);
384
- const max = maxNode == null ? Infinity : Number(maxNode.value);
385
-
386
- options.min = min;
387
- options.max = max;
388
- } else if (exactCount != null) {
389
- const integerNode = exactCount.find(p => p.name === "integer") as Node;
390
- const integer = Number(integerNode.value);
391
-
392
- options.min = integer;
393
- options.max = integer;
394
- } else if (quantifier != null) {
395
- const type = quantifier.value;
396
- if (type === "+") {
397
- options.min = 1;
398
- options.max = Infinity;
399
- } else {
400
- options.min = 0;
401
- options.max = Infinity;
402
- }
403
- }
404
-
405
- const repeat = new Repeat(name, pattern.clone(pattern.name, isPatternOptional), options);
406
-
407
- this._parseContext.patternsByName.set(name, repeat);
408
- }
409
-
410
- private _buildAlias(statementNode: Node) {
494
+ private _saveAlias(statementNode: Node) {
411
495
  const nameNode = statementNode.find(n => n.name === "name") as Node;
412
496
  const aliasNode = statementNode.find(n => n.name === "alias-literal") as Node;
413
497
  const aliasName = aliasNode.value;
414
498
  const name = nameNode.value;
415
- const pattern = this._getPattern(aliasName);
416
- const alias = pattern.clone(name);
499
+ const alias = this._getPattern(aliasName).clone(name);
417
500
 
418
- this._parseContext.patternsByName.set(name, alias)
501
+ this._parseContext.patternsByName.set(name, alias);
419
502
  }
420
503
 
421
504
  static parse(expression: string, options?: GrammarOptions) {
@@ -0,0 +1,23 @@
1
+ import { Literal } from "../../patterns/Literal";
2
+ import { Sequence } from "../../patterns/Sequence";
3
+ import { lineSpaces } from "./spaces";
4
+ import { anonymousLiterals, anonymousWrappedLiterals } from './literals';
5
+ import { Options } from "../../patterns/Options";
6
+ import { Optional } from "../../patterns/Optional";
7
+
8
+ const inlinePatternOpenParen = new Literal("anonymous-pattern-open-paren", "(");
9
+ const inlinePatternCloseParen = new Literal("anonymous-pattern-close-paren", ")");
10
+ const optionalLineSpaces = new Optional("optional-line-spaces", lineSpaces);
11
+
12
+ const complexAnonymousPattern = new Sequence("complex-anonymous-pattern", [
13
+ inlinePatternOpenParen,
14
+ optionalLineSpaces,
15
+ anonymousWrappedLiterals,
16
+ optionalLineSpaces,
17
+ inlinePatternCloseParen,
18
+ ]);
19
+
20
+ export const anonymousPattern = new Options("anonymous-pattern", [
21
+ anonymousLiterals,
22
+ complexAnonymousPattern
23
+ ]);
@@ -1,19 +1,22 @@
1
- import { And } from "../../patterns/And";
2
- import { Or } from "../../patterns/Or";
1
+ import { Sequence } from "../../patterns/Sequence";
2
+ import { Options } from "../../patterns/Options";
3
3
  import { Repeat } from "../../patterns/Repeat";
4
4
  import { comment } from "./comment";
5
5
  import { lineSpaces, newLine } from "./spaces";
6
6
  import { statement } from "./statement";
7
+ import { Optional } from "../../patterns/Optional";
7
8
 
8
- const bodyLineContent = new Or("body-line-content", [
9
+ const bodyLineContent = new Options("body-line-content", [
9
10
  comment,
10
11
  statement
11
12
  ]);
12
13
 
13
- const bodyLine = new And("body-line", [
14
- lineSpaces.clone("line-spaces", true),
14
+ const optionalLineSpaces = new Optional("optional-line-spaces", lineSpaces);
15
+
16
+ const bodyLine = new Sequence("body-line", [
17
+ optionalLineSpaces,
15
18
  bodyLineContent,
16
- lineSpaces.clone("line-spaces", true),
19
+ optionalLineSpaces,
17
20
  ]);
18
21
 
19
22
  export const body = new Repeat("body", bodyLine, {divider: newLine, min: 0});
@@ -1,3 +1,4 @@
1
- import { Regex } from "../../patterns/Regex"
1
+ import { Regex } from "../../patterns/Regex";
2
2
 
3
- export const comment = new Regex("comment", "#[^\r\n]+");
3
+ export const comment = new Regex("comment", "#[^\r\n]+");
4
+ comment.setTokens(["# "]);
@@ -1,11 +1,12 @@
1
- import { Or } from "../../patterns/Or";
1
+ import { Options } from "../../patterns/Options";
2
2
  import { Regex } from "../../patterns/Regex";
3
3
  import { Repeat } from "../../patterns/Repeat";
4
4
  import { comment } from "./comment";
5
5
  import { importStatement } from './import';
6
- import { And } from "../../patterns/And";
6
+ import { Sequence } from "../../patterns/Sequence";
7
7
  import { allSpaces } from "./spaces";
8
8
  import { body } from "./body";
9
+ import { Optional } from "../../patterns/Optional";
9
10
 
10
11
  const tabs = new Regex("tabs", "\\t+");
11
12
  const spaces = new Regex("spaces", "[ ]+");
@@ -15,25 +16,27 @@ spaces.setTokens([" "]);
15
16
  tabs.setTokens(["\t"]);
16
17
  newLine.setTokens(["\n"]);
17
18
 
18
- const lineSpaces = new Repeat("line-spaces", new Or("line-space", [tabs, spaces]));
19
+ const lineSpaces = new Repeat("line-spaces", new Options("line-space", [tabs, spaces]));
20
+ const optionalLineSpaces = new Optional("optional-line-spaces", lineSpaces);
19
21
 
20
- const headLineContent = new Or("head-line-content", [
22
+ const headLineContent = new Options("head-line-content", [
21
23
  comment,
22
24
  importStatement
23
25
  ]);
24
26
 
25
- const headLine = new And("head-line-content", [
26
- lineSpaces.clone("line-spaces", true),
27
+ const headLine = new Sequence("head-line-content", [
28
+ optionalLineSpaces,
27
29
  headLineContent,
28
- lineSpaces.clone("line-spaces", true),
30
+ optionalLineSpaces,
29
31
  ]);
30
32
 
31
- const head = new Repeat("head", headLine, { divider: newLine, min: 0 });
33
+ const head = new Optional("optional-head", new Repeat("head", headLine, { divider: newLine }));
34
+ const optionalSpaces = new Optional("optional-spaces", allSpaces);
32
35
 
33
- export const grammar = new And("grammar", [
34
- allSpaces,
36
+ export const grammar = new Sequence("grammar", [
37
+ optionalSpaces,
35
38
  head,
36
- allSpaces,
39
+ optionalSpaces,
37
40
  body,
38
- allSpaces
41
+ optionalSpaces
39
42
  ]);