clarity-pattern-parser 11.3.13 → 11.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/grammar/Grammar.d.ts +6 -2
- package/dist/grammar_v2/patterns/Grammar.d.ts +23 -0
- package/dist/grammar_v2/patterns/patterns/grammar.d.ts +87 -0
- package/dist/grammar_v2/patterns/patterns/grammar.test.d.ts +1 -0
- package/dist/index.browser.js +82 -13
- package/dist/index.browser.js.map +1 -1
- package/dist/index.esm.js +82 -13
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +82 -13
- package/dist/index.js.map +1 -1
- package/dist/patterns/Cursor.d.ts +1 -1
- package/package.json +1 -1
- package/src/grammar/Grammar.test.ts +38 -0
- package/src/grammar/Grammar.ts +87 -8
- package/src/grammar_v2/patterns/Grammar.ts +170 -0
- package/src/grammar_v2/patterns/patterns/cpat.cpat +91 -0
- package/src/grammar_v2/patterns/patterns/grammar.test.ts +218 -0
- package/src/grammar_v2/patterns/patterns/grammar.ts +103 -0
- package/src/patterns/Cursor.ts +6 -6
- package/src/patterns/Regex.ts +4 -2
- package/src/patterns/Sequence.test.ts +11 -0
package/package.json
CHANGED
|
@@ -779,4 +779,42 @@ describe("Grammar", () => {
|
|
|
779
779
|
expect(result?.value).toBe("function(){}");
|
|
780
780
|
});
|
|
781
781
|
|
|
782
|
+
test("Import Sync", () => {
|
|
783
|
+
function resolveImportSync(path: string, importer: string | null) {
|
|
784
|
+
return {
|
|
785
|
+
expression: pathMap[path],
|
|
786
|
+
resource: path,
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
const rootExpression = `
|
|
791
|
+
import { name } from "first-name.cpat"
|
|
792
|
+
full-name = name
|
|
793
|
+
`;
|
|
794
|
+
|
|
795
|
+
const firstNameExpression = `
|
|
796
|
+
import { last-name } from "last-name.cpat"
|
|
797
|
+
first-name = "John"
|
|
798
|
+
name = first-name + " " + last-name
|
|
799
|
+
`;
|
|
800
|
+
|
|
801
|
+
const lastNameExpression = `
|
|
802
|
+
last-name = "Doe"
|
|
803
|
+
`;
|
|
804
|
+
|
|
805
|
+
const pathMap: Record<string, string> = {
|
|
806
|
+
"first-name.cpat": firstNameExpression,
|
|
807
|
+
"last-name.cpat": lastNameExpression,
|
|
808
|
+
};
|
|
809
|
+
|
|
810
|
+
const patterns = Grammar.parseString(rootExpression, {
|
|
811
|
+
resolveImportSync: resolveImportSync,
|
|
812
|
+
originResource: "/root.cpat",
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
expect(patterns["full-name"]).not.toBeNull();
|
|
816
|
+
const result = patterns["full-name"].exec("John Doe");
|
|
817
|
+
expect(result?.ast?.value).toBe("John Doe");
|
|
818
|
+
});
|
|
819
|
+
|
|
782
820
|
});
|
package/src/grammar/Grammar.ts
CHANGED
|
@@ -50,6 +50,10 @@ function defaultImportResolver(_path: string, _basePath: string | null): Promise
|
|
|
50
50
|
throw new Error("No import resolver supplied.");
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
+
function defaultImportResolverSync(_path: string, _basePath: string | null): GrammarFile {
|
|
54
|
+
throw new Error("No import resolver supplied.");
|
|
55
|
+
}
|
|
56
|
+
|
|
53
57
|
export interface GrammarFile {
|
|
54
58
|
resource: string;
|
|
55
59
|
expression: string;
|
|
@@ -57,6 +61,7 @@ export interface GrammarFile {
|
|
|
57
61
|
|
|
58
62
|
export interface GrammarOptions {
|
|
59
63
|
resolveImport?: (resource: string, originResource: string | null) => Promise<GrammarFile>;
|
|
64
|
+
resolveImportSync?: (resource: string, originResource: string | null) => GrammarFile;
|
|
60
65
|
originResource?: string | null;
|
|
61
66
|
params?: Pattern[];
|
|
62
67
|
decorators?: Record<string, Decorator>;
|
|
@@ -66,12 +71,14 @@ export class Grammar {
|
|
|
66
71
|
private _params: Pattern[];
|
|
67
72
|
private _originResource?: string | null;
|
|
68
73
|
private _resolveImport: (resource: string, originResource: string | null) => Promise<GrammarFile>;
|
|
74
|
+
private _resolveImportSync: (resource: string, originResource: string | null) => GrammarFile;
|
|
69
75
|
private _parseContext: ParseContext;
|
|
70
76
|
|
|
71
77
|
constructor(options: GrammarOptions = {}) {
|
|
72
78
|
this._params = options?.params == null ? [] : options.params;
|
|
73
79
|
this._originResource = options?.originResource == null ? null : options.originResource;
|
|
74
80
|
this._resolveImport = options.resolveImport == null ? defaultImportResolver : options.resolveImport;
|
|
81
|
+
this._resolveImportSync = options.resolveImportSync == null ? defaultImportResolverSync : options.resolveImportSync;
|
|
75
82
|
this._parseContext = new ParseContext(this._params, options.decorators || {});
|
|
76
83
|
}
|
|
77
84
|
|
|
@@ -101,10 +108,7 @@ export class Grammar {
|
|
|
101
108
|
this._parseContext = new ParseContext(this._params, this._parseContext.decorators);
|
|
102
109
|
const ast = this._tryToParse(expression);
|
|
103
110
|
|
|
104
|
-
|
|
105
|
-
throw new Error("Cannot use imports on parseString, use parse instead.");
|
|
106
|
-
}
|
|
107
|
-
|
|
111
|
+
this._resolveImportsSync(ast);
|
|
108
112
|
this._buildPatterns(ast);
|
|
109
113
|
|
|
110
114
|
return this._buildPatternRecord();
|
|
@@ -476,14 +480,89 @@ export class Grammar {
|
|
|
476
480
|
|
|
477
481
|
for (const statement of importStatements) {
|
|
478
482
|
if (statement.name === "import-from") {
|
|
479
|
-
await this.
|
|
483
|
+
await this._processImport(statement);
|
|
480
484
|
} else {
|
|
481
|
-
this.
|
|
485
|
+
this._processUseParams(statement);
|
|
482
486
|
}
|
|
483
487
|
}
|
|
484
488
|
}
|
|
485
489
|
|
|
486
|
-
private
|
|
490
|
+
private _resolveImportsSync(ast: Node) {
|
|
491
|
+
const importStatements = ast.findAll(n => {
|
|
492
|
+
return n.name === "import-from" || n.name === "param-name-with-default-value";
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
for (const statement of importStatements) {
|
|
496
|
+
if (statement.name === "import-from") {
|
|
497
|
+
this._processImportSync(statement);
|
|
498
|
+
} else {
|
|
499
|
+
this._processUseParams(statement);
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
private _processImportSync(importStatement: Node) {
|
|
505
|
+
const parseContext = this._parseContext;
|
|
506
|
+
const resourceNode = importStatement.find(n => n.name === "resource") as Node;
|
|
507
|
+
const params = this._getParams(importStatement);
|
|
508
|
+
const resource = resourceNode.value.slice(1, -1);
|
|
509
|
+
const grammarFile = this._resolveImportSync(resource, this._originResource || null);
|
|
510
|
+
const grammar = new Grammar({
|
|
511
|
+
resolveImport: this._resolveImport,
|
|
512
|
+
resolveImportSync: this._resolveImportSync,
|
|
513
|
+
originResource: grammarFile.resource,
|
|
514
|
+
params,
|
|
515
|
+
decorators: this._parseContext.decorators
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
try {
|
|
519
|
+
const patterns = grammar.parseString(grammarFile.expression);
|
|
520
|
+
const importStatements = importStatement.findAll(n => n.name === "import-name" || n.name === "import-alias");
|
|
521
|
+
|
|
522
|
+
importStatements.forEach((node) => {
|
|
523
|
+
if (node.name === "import-name" && node.parent?.name === "import-alias") {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
if (node.name === "import-name" && node.parent?.name !== "import-alias") {
|
|
528
|
+
const importName = node.value;
|
|
529
|
+
|
|
530
|
+
if (parseContext.importedPatternsByName.has(importName)) {
|
|
531
|
+
throw new Error(`'${importName}' was already used within another import.`);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
const pattern = patterns[importName];
|
|
535
|
+
if (pattern == null) {
|
|
536
|
+
throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
parseContext.importedPatternsByName.set(importName, pattern);
|
|
540
|
+
} else {
|
|
541
|
+
const importNameNode = node.find(n => n.name === "import-name") as Node;
|
|
542
|
+
const importName = importNameNode.value;
|
|
543
|
+
const aliasNode = node.find(n => n.name === "import-name-alias") as Node;
|
|
544
|
+
const alias = aliasNode.value;
|
|
545
|
+
|
|
546
|
+
if (parseContext.importedPatternsByName.has(alias)) {
|
|
547
|
+
throw new Error(`'${alias}' was already used within another import.`);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
const pattern = patterns[importName];
|
|
551
|
+
if (pattern == null) {
|
|
552
|
+
throw new Error(`Couldn't find pattern with name: ${importName}, from import: ${resource}.`);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
parseContext.importedPatternsByName.set(alias, pattern.clone(alias));
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
|
|
559
|
+
} catch (e: any) {
|
|
560
|
+
throw new Error(`Failed loading expression from: "${resource}". Error details: "${e.message}"`);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
private async _processImport(importStatement: Node) {
|
|
487
566
|
const parseContext = this._parseContext;
|
|
488
567
|
const resourceNode = importStatement.find(n => n.name === "resource") as Node;
|
|
489
568
|
const params = this._getParams(importStatement);
|
|
@@ -543,7 +622,7 @@ export class Grammar {
|
|
|
543
622
|
|
|
544
623
|
}
|
|
545
624
|
|
|
546
|
-
private
|
|
625
|
+
private _processUseParams(paramName: Node) {
|
|
547
626
|
const defaultValueNode = paramName.find(n => n.name === "param-default");
|
|
548
627
|
if (defaultValueNode === null) {
|
|
549
628
|
return;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { Node } from "../../ast/Node";
|
|
2
|
+
import { tokens } from "../../grammar/decorators/tokens";
|
|
3
|
+
import { GrammarFile } from "../../grammar/Grammar";
|
|
4
|
+
import { generateErrorMessage } from "../../patterns/generate_error_message";
|
|
5
|
+
import { Pattern } from "../../patterns/Pattern";
|
|
6
|
+
import { grammar } from "./patterns/grammar"
|
|
7
|
+
|
|
8
|
+
let anonymousIndexId = 0;
|
|
9
|
+
|
|
10
|
+
function defaultImportResolver(_path: string, _basePath: string | null): Promise<GrammarFile> {
|
|
11
|
+
throw new Error("No import resolver supplied.");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function defaultImportResolverSync(_path: string, _basePath: string | null): GrammarFile {
|
|
15
|
+
throw new Error("No import resolver supplied.");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type Decorator = (pattern: Pattern, arg?: string | boolean | number | null | Record<string, any> | any[]) => void;
|
|
19
|
+
|
|
20
|
+
const defaultDecorators = {
|
|
21
|
+
tokens: tokens
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export interface GrammarOptions {
|
|
25
|
+
resolveImport?: (resource: string, originResource: string | null) => Promise<GrammarFile>;
|
|
26
|
+
resolveImportSync?: (resource: string, originResource: string | null) => GrammarFile;
|
|
27
|
+
originResource?: string | null;
|
|
28
|
+
params?: Pattern[];
|
|
29
|
+
decorators?: Record<string, Decorator>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
class ParseContext {
|
|
33
|
+
patternsByName = new Map<string, Pattern>();
|
|
34
|
+
importedPatternsByName = new Map<string, Pattern>();
|
|
35
|
+
paramsByName = new Map<string, Pattern>();
|
|
36
|
+
decorators: Record<string, Decorator>;
|
|
37
|
+
|
|
38
|
+
constructor(params: Pattern[], decorators: Record<string, Decorator> = {}) {
|
|
39
|
+
params.forEach(p => this.paramsByName.set(p.name, p));
|
|
40
|
+
this.decorators = { ...decorators, ...defaultDecorators };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
getImportedPatterns() {
|
|
44
|
+
return Array.from(this.importedPatternsByName.values());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
getParams() {
|
|
48
|
+
return Array.from(this.paramsByName.values());
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class Grammar {
|
|
54
|
+
private _options: GrammarOptions;
|
|
55
|
+
private _parseContext: ParseContext;
|
|
56
|
+
private _resolveImportSync: (resource: string, originResource: string | null) => GrammarFile;
|
|
57
|
+
|
|
58
|
+
constructor(options: GrammarOptions) {
|
|
59
|
+
this._options = options;
|
|
60
|
+
this._parseContext = new ParseContext(options.params || [], options.decorators || {});
|
|
61
|
+
this._resolveImportSync = options.resolveImportSync == null ? defaultImportResolverSync : options.resolveImportSync;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// parse(cpat: string): Promise<Pattern> { }
|
|
65
|
+
// import(path: string): Promise<Pattern> { }
|
|
66
|
+
|
|
67
|
+
// parseString(cpat: string): Pattern {
|
|
68
|
+
// const ast = this._tryToParse(cpat);
|
|
69
|
+
|
|
70
|
+
// this._flattenExpressions(ast);
|
|
71
|
+
|
|
72
|
+
// }
|
|
73
|
+
|
|
74
|
+
private _resolveImportsSync(ast: Node) {
|
|
75
|
+
const importStatements = ast.findAll(n => {
|
|
76
|
+
return n.name === "importStatement" || n.name === "useParamsStatement";
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
for (const importStatement of importStatements) {
|
|
80
|
+
if (importStatement.name === "importStatement") {
|
|
81
|
+
this._processImportSync(importStatement);
|
|
82
|
+
} else {
|
|
83
|
+
this._processUseParams(importStatement);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private _processImportSync(importStatement: Node) {
|
|
89
|
+
const parseContext = this._parseContext;
|
|
90
|
+
const resourceNode = importStatement.find(n => n.name === "resource") as Node;
|
|
91
|
+
const params = this._getWithParams(importStatement);
|
|
92
|
+
const resource = resourceNode.value.slice(1, -1);
|
|
93
|
+
const grammarFile = this._resolveImportSync(resource, this._options.originResource || null);
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
if (resourceNode == null) {
|
|
97
|
+
throw new Error("Invalid import statement: resource is required");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private _getWithParams(importStatement: Node) {
|
|
104
|
+
const withParamsStatements = importStatement.find(n => n.name === "withParamsStatements");
|
|
105
|
+
|
|
106
|
+
if (withParamsStatements == null) {
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const expression = withParamsStatements.toString();
|
|
111
|
+
const importedValues = this._parseContext.getImportedPatterns();
|
|
112
|
+
|
|
113
|
+
const grammar = new Grammar({
|
|
114
|
+
params: [...importedValues, ...this._parseContext.paramsByName.values()],
|
|
115
|
+
originResource: this._options.originResource,
|
|
116
|
+
resolveImport: this._options.resolveImport,
|
|
117
|
+
decorators: this._parseContext.decorators
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// const patterns = grammar.parseString(expression);
|
|
121
|
+
// return Array.from(Object.values(patterns));
|
|
122
|
+
return[]
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
private _processUseParams(useParamsStatement: Node) {
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
private _tryToParse(cpat: string): Node {
|
|
130
|
+
const { ast, cursor } = grammar.exec(cpat, true);
|
|
131
|
+
|
|
132
|
+
if (ast == null) {
|
|
133
|
+
const message = generateErrorMessage(grammar, cursor);
|
|
134
|
+
throw new Error(`[Invalid Grammar] ${message}`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return ast;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
private _flattenExpressions(node: Node) {
|
|
142
|
+
switch (node.name) {
|
|
143
|
+
case "sequenceExpr":
|
|
144
|
+
return this._unwrapNode("sequenceExpr", node);
|
|
145
|
+
case "optionsExpr":
|
|
146
|
+
return this._unwrapNode("optionsExpr", node);
|
|
147
|
+
case "greedyOptionsExpr":
|
|
148
|
+
return this._unwrapNode("greedyOptionsExpr", node);
|
|
149
|
+
default:
|
|
150
|
+
return node;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
private _unwrapNode(type: string, node: Node) {
|
|
155
|
+
if (node.name !== type) {
|
|
156
|
+
return node;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
for (let x = 0; x < node.children.length; x++) {
|
|
160
|
+
const child = node.children[x];
|
|
161
|
+
|
|
162
|
+
if (child.name === type) {
|
|
163
|
+
node.spliceChildren(x, 1, ...child.children);
|
|
164
|
+
x--;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return node;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# syntax
|
|
2
|
+
syntax = "syntax"
|
|
3
|
+
import = "import"
|
|
4
|
+
useParams = "use params"
|
|
5
|
+
withParams = "with params"
|
|
6
|
+
from = "from"
|
|
7
|
+
right = "right"
|
|
8
|
+
ws = /\s+/
|
|
9
|
+
ls = /[ \t]+/
|
|
10
|
+
assign = "="
|
|
11
|
+
bar = "|"
|
|
12
|
+
concat = "+"
|
|
13
|
+
colon = ":"
|
|
14
|
+
openParen = "("
|
|
15
|
+
closeParen = ")"
|
|
16
|
+
openSquareBracket = "["
|
|
17
|
+
closeSquareBracket = "]"
|
|
18
|
+
openBracket = "{"
|
|
19
|
+
closeBracket = "}"
|
|
20
|
+
comma = /\s*[,]\s*/
|
|
21
|
+
trim = "trim"
|
|
22
|
+
not = "!"
|
|
23
|
+
optional = "?"
|
|
24
|
+
newLine = /\s*(\r\n|\r|\n)\s*/
|
|
25
|
+
syntaxVersion = /\S*/
|
|
26
|
+
at = "@"
|
|
27
|
+
|
|
28
|
+
literal = /"(?:\\.|[^"\\])*"/
|
|
29
|
+
regexLiteral = /\/(\\/|[^\n\r])*\//
|
|
30
|
+
|
|
31
|
+
integer = /[1-9][0-9]*|[0]/
|
|
32
|
+
name = /[a-zA-Z_-]+[a-zA-Z0-9_-]*/
|
|
33
|
+
patternName = name
|
|
34
|
+
patternIdentifier = name
|
|
35
|
+
resource = literal
|
|
36
|
+
|
|
37
|
+
comment = /#[^\n\r]*/
|
|
38
|
+
|
|
39
|
+
# JSON
|
|
40
|
+
jsonString = literal
|
|
41
|
+
jsonNumber = /-?\d+(\.\d+)?/
|
|
42
|
+
jsonBoolean = "true" | "false"
|
|
43
|
+
jsonNull = "null"
|
|
44
|
+
jsonValue = jsonString | jsonNumber | jsonBoolean | jsonNull | jsonArray | jsonObject
|
|
45
|
+
jsonArrayItems = (jsonValue, comma trim)+
|
|
46
|
+
jsonArray = openSquareBracket +ws? + jsonArrayItems? + ws? + closeSquareBracket
|
|
47
|
+
jsonObjectPropertyName = literal
|
|
48
|
+
jsonObjectProperty = jsonObjectPropertyName + ws? + colon + ws? + jsonValue
|
|
49
|
+
jsonObjectProperties = (jsonObjectProperty, comma trim)+
|
|
50
|
+
jsonObject = openBracket + ws? + jsonObjectProperties? + ws? + closeBracket
|
|
51
|
+
|
|
52
|
+
syntaxStatement = syntax + ws? + syntaxVersion
|
|
53
|
+
|
|
54
|
+
decorationName = name
|
|
55
|
+
decorationStatement = at + ws? + decorationName + ws? + openParen + ws? + jsonValue? + ws? + closeParen
|
|
56
|
+
|
|
57
|
+
useParamPatterns = (patternName, comma trim)+
|
|
58
|
+
useParamsStatement = useParams + ls? + openBracket + ws? + useParamPatterns + ws? + closeBracket
|
|
59
|
+
|
|
60
|
+
withParamStatements = (patternAssignment, newLine trim)+
|
|
61
|
+
withParamsExpr = withParams + ls? + openBracket + ws? + withParamStatements + ws? + closeBracket
|
|
62
|
+
|
|
63
|
+
patternNames = (patternName, comma trim)+
|
|
64
|
+
importedPatterns = openBracket + ws? + patternNames + ws? + closeBracket
|
|
65
|
+
importStatement = import + ls? + importedPatterns + ls? + from + ls? + resource + ls? + withParamsExpr?
|
|
66
|
+
|
|
67
|
+
notExpr = not + ls? + unaryPatternExpr
|
|
68
|
+
optionalExpr = unaryPatternExpr + ls? + optional
|
|
69
|
+
rightAssociationExpr = unaryPatternExpr + ls? + right
|
|
70
|
+
|
|
71
|
+
unaryPatternExpr = notExpr | optionalExpr | rightAssociationExpr | patternIdentifier
|
|
72
|
+
|
|
73
|
+
repeatBounds = openBracket + integer? + comma? + integer? + closeBracket
|
|
74
|
+
oneOrMore = "+"
|
|
75
|
+
zeroOrMore = "*"
|
|
76
|
+
repeatOptions = oneOrMore | zeroOrMore | repeatBounds
|
|
77
|
+
delimiter = comma + patternExpr + ws? + trim?
|
|
78
|
+
repeatExpr = openParen + ws? + patternExpr + ws? + delimiter? + ws? + closeParen + repeatOptions
|
|
79
|
+
|
|
80
|
+
sequenceExpr = patternExpr + ws? + "+" + ws? + patternExpr
|
|
81
|
+
optionsExpr = patternExpr + ws? + "|" + ws? + patternExpr
|
|
82
|
+
greedyOptionsExpr = patternExpr + ws? + "<|>" + ws? + patternExpr
|
|
83
|
+
patternGroupExpr = openParen + ws? + patternExpr + ws? + closeParen
|
|
84
|
+
|
|
85
|
+
exportPattern = patternName
|
|
86
|
+
patternExpr = sequenceExpr | optionsExpr | greedyOptionsExpr | repeatExpr | patternGroupExpr | literal | regexLiteral | unaryPatternExpr
|
|
87
|
+
patternAssignment = patternName + ws? + assign + ws? + patternExpr
|
|
88
|
+
statement = useParamsStatement | importStatement | patternAssignment | decorationStatement | exportPattern | comment
|
|
89
|
+
statements = (statement, newLine)+
|
|
90
|
+
cpat = ws? + syntaxStatement? + ws? + statements?
|
|
91
|
+
|