clarity-pattern-parser 11.5.4 → 11.6.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/architecture.md +300 -0
- package/dist/grammar/Grammar.d.ts +24 -25
- package/dist/grammar/patterns/grammar.d.ts +99 -0
- package/dist/grammar/patterns/grammar.test.d.ts +1 -0
- package/dist/index.browser.js +2314 -2592
- package/dist/index.browser.js.map +1 -1
- package/dist/index.esm.js +2314 -2592
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +2314 -2592
- package/dist/index.js.map +1 -1
- package/grammar-guide.md +836 -0
- package/package.json +1 -1
- package/src/grammar/Grammar.test.ts +418 -0
- package/src/grammar/Grammar.ts +483 -515
- package/src/grammar/patterns/grammar.test.ts +276 -0
- package/src/grammar/patterns/grammar.ts +113 -37
- package/src/grammar/patterns.ts +6 -6
- package/src/grammar/patterns/anonymousPattern.ts +0 -23
- package/src/grammar/patterns/body.ts +0 -22
- package/src/grammar/patterns/comment.ts +0 -4
- package/src/grammar/patterns/decoratorStatement.ts +0 -85
- package/src/grammar/patterns/import.ts +0 -88
- package/src/grammar/patterns/literal.ts +0 -4
- package/src/grammar/patterns/literals.ts +0 -21
- package/src/grammar/patterns/name.ts +0 -3
- package/src/grammar/patterns/optionsLiteral.ts +0 -25
- package/src/grammar/patterns/pattern.ts +0 -29
- package/src/grammar/patterns/regexLiteral.ts +0 -5
- package/src/grammar/patterns/repeatLiteral.ts +0 -71
- package/src/grammar/patterns/sequenceLiteral.ts +0 -24
- package/src/grammar/patterns/spaces.ts +0 -16
- package/src/grammar/patterns/statement.ts +0 -22
- package/src/grammar/patterns/takeUtilLiteral.ts +0 -20
- package/src/grammar/spec.md +0 -331
- package/src/grammar_v2/patterns/Grammar.ts +0 -170
- package/src/grammar_v2/patterns/patterns/cpat.cpat +0 -91
- package/src/grammar_v2/patterns/patterns/grammar.test.ts +0 -218
- package/src/grammar_v2/patterns/patterns/grammar.ts +0 -103
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { grammar } from "./grammar";
|
|
2
|
+
import { Node } from "../../ast/Node";
|
|
3
|
+
|
|
4
|
+
describe("grammar", () => {
|
|
5
|
+
test("syntax version", () => {
|
|
6
|
+
const { ast } = grammar.exec("syntax 1.0");
|
|
7
|
+
|
|
8
|
+
expect(ast).toBeDefined();
|
|
9
|
+
expect(ast?.find((p: Node) => p.name === "syntax")).toBeDefined();
|
|
10
|
+
expect(ast?.find((p: Node) => p.name === "syntax")?.value).toBe("syntax");
|
|
11
|
+
expect(ast?.find((p: Node) => p.name === "syntaxVersion")).toBeDefined();
|
|
12
|
+
expect(ast?.find((p: Node) => p.name === "syntaxVersion")?.value).toBe("1.0");
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("import", () => {
|
|
16
|
+
const { ast } = grammar.exec('import {pattern} from "resource"');
|
|
17
|
+
|
|
18
|
+
expect(ast).toBeDefined();
|
|
19
|
+
expect(ast?.find((p: Node) => p.name === "importStatement")).toBeDefined();
|
|
20
|
+
expect(ast?.find((p: Node) => p.name === "import")).toBeDefined();
|
|
21
|
+
expect(ast?.find((p: Node) => p.name === "import")?.value).toBe("import");
|
|
22
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
23
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("pattern");
|
|
24
|
+
expect(ast?.find((p: Node) => p.name === "from")).toBeDefined();
|
|
25
|
+
expect(ast?.find((p: Node) => p.name === "from")?.value).toBe("from");
|
|
26
|
+
expect(ast?.find((p: Node) => p.name === "resource")).toBeDefined();
|
|
27
|
+
expect(ast?.find((p: Node) => p.name === "resource")?.value).toBe('"resource"');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("import with params", () => {
|
|
31
|
+
const { ast } = grammar.exec('import {pattern} from "resource" with params {param = "value"}');
|
|
32
|
+
|
|
33
|
+
expect(ast).toBeDefined();
|
|
34
|
+
expect(ast?.find((p: Node) => p.name === "importStatement")).toBeDefined();
|
|
35
|
+
expect(ast?.find((p: Node) => p.name === "import")).toBeDefined();
|
|
36
|
+
expect(ast?.find((p: Node) => p.name === "import")?.value).toBe("import");
|
|
37
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
38
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("pattern");
|
|
39
|
+
expect(ast?.find((p: Node) => p.name === "from")).toBeDefined();
|
|
40
|
+
expect(ast?.find((p: Node) => p.name === "from")?.value).toBe("from");
|
|
41
|
+
expect(ast?.find((p: Node) => p.name === "resource")).toBeDefined();
|
|
42
|
+
expect(ast?.find((p: Node) => p.name === "resource")?.value).toBe('"resource"');
|
|
43
|
+
expect(ast?.find((p: Node) => p.name === "withParamsExpr")).toBeDefined();
|
|
44
|
+
expect(ast?.find((p: Node) => p.name === "withParamsExpr")?.value).toBe("with params {param = \"value\"}");
|
|
45
|
+
expect(ast?.find((p: Node) => p.name === "statements")?.find((p: Node) => p.name === "param = \"value\"")).toBeDefined();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("use params", () => {
|
|
49
|
+
const { ast } = grammar.exec('use params { param }');
|
|
50
|
+
|
|
51
|
+
expect(ast).toBeDefined();
|
|
52
|
+
expect(ast?.find((p: Node) => p.name === "useParamsStatement")).toBeDefined();
|
|
53
|
+
expect(ast?.find((p: Node) => p.name === "useParamsStatement")?.value).toBe("use params { param }");
|
|
54
|
+
expect(ast?.find((p: Node) => p.name === "useParams")).toBeDefined();
|
|
55
|
+
expect(ast?.find((p: Node) => p.name === "useParams")?.value).toBe("use params");
|
|
56
|
+
expect(ast?.find((p: Node) => p.name === "useParamPatterns")).toBeDefined();
|
|
57
|
+
expect(ast?.find((p: Node) => p.name === "useParamPatterns")?.value).toBe("param");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("literal", () => {
|
|
61
|
+
const { ast } = grammar.exec('literal = "Hello, world!"');
|
|
62
|
+
|
|
63
|
+
expect(ast).toBeDefined();
|
|
64
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")).toBeDefined();
|
|
65
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")?.value).toBe("literal = \"Hello, world!\"");
|
|
66
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
67
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("literal");
|
|
68
|
+
expect(ast?.find((p: Node) => p.name === "literal")).toBeDefined();
|
|
69
|
+
expect(ast?.find((p: Node) => p.name === "literal")?.value).toBe("\"Hello, world!\"");
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
test("regex", () => {
|
|
74
|
+
const { ast } = grammar.exec('regex = /Hello, world!/');
|
|
75
|
+
|
|
76
|
+
expect(ast).toBeDefined();
|
|
77
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")).toBeDefined();
|
|
78
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")?.value).toBe("regex = /Hello, world!/");
|
|
79
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
80
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("regex");
|
|
81
|
+
expect(ast?.find((p: Node) => p.name === "regex")).toBeDefined();
|
|
82
|
+
expect(ast?.find((p: Node) => p.name === "regex")?.value).toBe("/Hello, world!/");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("regex stops at first unescaped slash", () => {
|
|
86
|
+
const { ast } = grammar.exec('expr = /regex/ + ("Text" <|> /regex/)');
|
|
87
|
+
|
|
88
|
+
expect(ast).toBeDefined();
|
|
89
|
+
const regexNodes = ast?.findAll((p: Node) => p.name === "regex");
|
|
90
|
+
expect(regexNodes?.length).toBe(2);
|
|
91
|
+
expect(regexNodes?.[0].value).toBe("/regex/");
|
|
92
|
+
expect(regexNodes?.[1].value).toBe("/regex/");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("regex allows escaped slashes", () => {
|
|
96
|
+
const { ast } = grammar.exec('pattern = /a\\/b/');
|
|
97
|
+
|
|
98
|
+
expect(ast).toBeDefined();
|
|
99
|
+
expect(ast?.find((p: Node) => p.name === "regex")?.value).toBe('/a\\/b/');
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
test("comment", () => {
|
|
103
|
+
const { ast } = grammar.exec('# Comment');
|
|
104
|
+
|
|
105
|
+
expect(ast).toBeDefined();
|
|
106
|
+
expect(ast?.find((p: Node) => p.name === "comment")).toBeDefined();
|
|
107
|
+
expect(ast?.find((p: Node) => p.name === "comment")?.value).toBe("# Comment");
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("sequence", () => {
|
|
111
|
+
const { ast } = grammar.exec('sequence = "Hello" + "world"');
|
|
112
|
+
|
|
113
|
+
expect(ast).toBeDefined();
|
|
114
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")).toBeDefined();
|
|
115
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")?.value).toBe("sequence = \"Hello\" + \"world\"");
|
|
116
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
117
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("sequence");
|
|
118
|
+
expect(ast?.find((p: Node) => p.name === "sequenceExpr")).toBeDefined();
|
|
119
|
+
expect(ast?.find((p: Node) => p.name === "sequenceExpr")?.value).toBe("\"Hello\" + \"world\"");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("options", () => {
|
|
123
|
+
const { ast } = grammar.exec('options = "Hello" | "world"');
|
|
124
|
+
|
|
125
|
+
expect(ast).toBeDefined();
|
|
126
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")).toBeDefined();
|
|
127
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")?.value).toBe("options = \"Hello\" | \"world\"");
|
|
128
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
129
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("options");
|
|
130
|
+
expect(ast?.find((p: Node) => p.name === "optionsExpr")).toBeDefined();
|
|
131
|
+
expect(ast?.find((p: Node) => p.name === "optionsExpr")?.value).toBe("\"Hello\" | \"world\"");
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
test("greedy options", () => {
|
|
135
|
+
const { ast } = grammar.exec('greedyOptions = "Hello" <|> "world"');
|
|
136
|
+
|
|
137
|
+
expect(ast).toBeDefined();
|
|
138
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")).toBeDefined();
|
|
139
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")?.value).toBe("greedyOptions = \"Hello\" <|> \"world\"");
|
|
140
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
141
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("greedyOptions");
|
|
142
|
+
expect(ast?.find((p: Node) => p.name === "greedyOptionsExpr")).toBeDefined();
|
|
143
|
+
expect(ast?.find((p: Node) => p.name === "greedyOptionsExpr")?.value).toBe("\"Hello\" <|> \"world\"");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("repeat", () => {
|
|
147
|
+
const { ast } = grammar.exec('repeat = (Hello)+');
|
|
148
|
+
|
|
149
|
+
expect(ast).toBeDefined();
|
|
150
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")).toBeDefined();
|
|
151
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")?.value).toBe("repeat = (Hello)+");
|
|
152
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
153
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("repeat");
|
|
154
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")).toBeDefined();
|
|
155
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")?.value).toBe("(Hello)+");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
test("repeat zero or more", () => {
|
|
159
|
+
const { ast } = grammar.exec('repeat = (Hello)*');
|
|
160
|
+
|
|
161
|
+
expect(ast).toBeDefined();
|
|
162
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")).toBeDefined();
|
|
163
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")?.value).toBe("repeat = (Hello)*");
|
|
164
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
165
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("repeat");
|
|
166
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")).toBeDefined();
|
|
167
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")?.value).toBe("(Hello)*");
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("repeat with bounds", () => {
|
|
171
|
+
const { ast } = grammar.exec('repeat = (Hello){2, 4}');
|
|
172
|
+
|
|
173
|
+
expect(ast).toBeDefined();
|
|
174
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")).toBeDefined();
|
|
175
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")?.value).toBe("repeat = (Hello){2, 4}");
|
|
176
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
177
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("repeat");
|
|
178
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")).toBeDefined();
|
|
179
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")?.value).toBe("(Hello){2, 4}");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
test("repeat with upper limit", () => {
|
|
183
|
+
const { ast } = grammar.exec('repeat = (Hello){, 4}');
|
|
184
|
+
|
|
185
|
+
expect(ast).toBeDefined();
|
|
186
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")).toBeDefined();
|
|
187
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")?.value).toBe("repeat = (Hello){, 4}");
|
|
188
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
189
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("repeat");
|
|
190
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")).toBeDefined();
|
|
191
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")?.value).toBe("(Hello){, 4}");
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("repeat with lower limit", () => {
|
|
195
|
+
const { ast } = grammar.exec('repeat = (Hello){1,}');
|
|
196
|
+
|
|
197
|
+
expect(ast).toBeDefined();
|
|
198
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")).toBeDefined();
|
|
199
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")?.value).toBe("repeat = (Hello){1,}");
|
|
200
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
201
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("repeat");
|
|
202
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")).toBeDefined();
|
|
203
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")?.value).toBe("(Hello){1,}");
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
test("repeat with delimiter", () => {
|
|
207
|
+
const { ast } = grammar.exec('repeat = (Hello, "world")+');
|
|
208
|
+
|
|
209
|
+
expect(ast).toBeDefined();
|
|
210
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")).toBeDefined();
|
|
211
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")?.value).toBe("repeat = (Hello, \"world\")+");
|
|
212
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
213
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("repeat");
|
|
214
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")).toBeDefined();
|
|
215
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")?.value).toBe("(Hello, \"world\")+");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
test("repeat with trim delimiter", () => {
|
|
219
|
+
const { ast } = grammar.exec('repeat = (Hello, "world" trim)+');
|
|
220
|
+
|
|
221
|
+
expect(ast).toBeDefined();
|
|
222
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")).toBeDefined();
|
|
223
|
+
expect(ast?.find((p: Node) => p.name === "patternAssignment")?.value).toBe("repeat = (Hello, \"world\" trim)+");
|
|
224
|
+
expect(ast?.find((p: Node) => p.name === "patternName")).toBeDefined();
|
|
225
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("repeat");
|
|
226
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")).toBeDefined();
|
|
227
|
+
expect(ast?.find((p: Node) => p.name === "repeatExpr")?.value).toBe("(Hello, \"world\" trim)+");
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("take until", () => {
|
|
231
|
+
const { ast } = grammar.exec('script-text = ?->| "</script"');
|
|
232
|
+
|
|
233
|
+
expect(ast).toBeDefined();
|
|
234
|
+
expect(ast?.find((p: Node) => p.name === "takeUntilExpr")).toBeDefined();
|
|
235
|
+
expect(ast?.find((p: Node) => p.name === "takeUntilExpr")?.value).toBe('?->| "</script"');
|
|
236
|
+
expect(ast?.find((p: Node) => p.name === "anyChar")).toBeDefined();
|
|
237
|
+
expect(ast?.find((p: Node) => p.name === "upTo")).toBeDefined();
|
|
238
|
+
expect(ast?.find((p: Node) => p.name === "wall")).toBeDefined();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("import alias", () => {
|
|
242
|
+
const { ast } = grammar.exec('import {value as alias} from "resource"');
|
|
243
|
+
|
|
244
|
+
expect(ast).toBeDefined();
|
|
245
|
+
expect(ast?.find((p: Node) => p.name === "importAlias")).toBeDefined();
|
|
246
|
+
expect(ast?.find((p: Node) => p.name === "patternName")?.value).toBe("value");
|
|
247
|
+
expect(ast?.find((p: Node) => p.name === "as")?.value).toBe("as");
|
|
248
|
+
expect(ast?.find((p: Node) => p.name === "importNameAlias")?.value).toBe("alias");
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
test("decorator without parens", () => {
|
|
252
|
+
const { ast } = grammar.exec('@record\nspaces = /\\s+/');
|
|
253
|
+
|
|
254
|
+
expect(ast).toBeDefined();
|
|
255
|
+
expect(ast?.find((p: Node) => p.name === "nameDecorationStatement")).toBeDefined();
|
|
256
|
+
expect(ast?.find((p: Node) => p.name === "decorationName")?.value).toBe("record");
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test("decorator with empty args", () => {
|
|
260
|
+
const { ast } = grammar.exec('@tokens()\nspaces = /\\s+/');
|
|
261
|
+
|
|
262
|
+
expect(ast).toBeDefined();
|
|
263
|
+
expect(ast?.find((p: Node) => p.name === "methodDecorationStatement")).toBeDefined();
|
|
264
|
+
expect(ast?.find((p: Node) => p.name === "decorationName")?.value).toBe("tokens");
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
test("decorator with args", () => {
|
|
268
|
+
const { ast } = grammar.exec('@tokens([" "])\nspaces = /\\s+/');
|
|
269
|
+
|
|
270
|
+
expect(ast).toBeDefined();
|
|
271
|
+
expect(ast?.find((p: Node) => p.name === "methodDecorationStatement")).toBeDefined();
|
|
272
|
+
expect(ast?.find((p: Node) => p.name === "decorationName")?.value).toBe("tokens");
|
|
273
|
+
expect(ast?.find((p: Node) => p.name === "jsonArray")).toBeDefined();
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
});
|
|
@@ -1,42 +1,118 @@
|
|
|
1
|
+
import { Expression } from "../../patterns/Expression";
|
|
2
|
+
import { Literal } from "../../patterns/Literal";
|
|
3
|
+
import { Optional } from "../../patterns/Optional";
|
|
1
4
|
import { Options } from "../../patterns/Options";
|
|
5
|
+
import { Reference } from "../../patterns/Reference";
|
|
2
6
|
import { Regex } from "../../patterns/Regex";
|
|
3
7
|
import { Repeat } from "../../patterns/Repeat";
|
|
4
|
-
import { comment } from "./comment";
|
|
5
|
-
import { importStatement } from './import';
|
|
6
8
|
import { Sequence } from "../../patterns/Sequence";
|
|
7
|
-
import { allSpaces } from "./spaces";
|
|
8
|
-
import { body } from "./body";
|
|
9
|
-
import { Optional } from "../../patterns/Optional";
|
|
10
9
|
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
export const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
10
|
+
export const syntax = new Literal("syntax", "syntax");
|
|
11
|
+
export const imprt = new Literal("import", "import");
|
|
12
|
+
export const useParams = new Literal("useParams", "use params");
|
|
13
|
+
export const withParams = new Literal("withParams", "with params");
|
|
14
|
+
export const from = new Literal("from", "from");
|
|
15
|
+
export const right = new Literal("right", "right");
|
|
16
|
+
export const ws = new Regex("ws", "\\s+");
|
|
17
|
+
export const ls = new Regex("ls", "[ \\t]+");
|
|
18
|
+
export const assign = new Literal("assign", "=");
|
|
19
|
+
export const bar = new Literal("|", "|");
|
|
20
|
+
export const greedyBar = new Literal("<|>", "<|>");
|
|
21
|
+
export const concat = new Literal("+", "+");
|
|
22
|
+
export const colon = new Literal(":", ":");
|
|
23
|
+
export const openParen = new Literal("(", "(");
|
|
24
|
+
export const closeParen = new Literal(")", ")");
|
|
25
|
+
export const openSquareBracket = new Literal("[", "[");
|
|
26
|
+
export const closeSquareBracket = new Literal("]", "]");
|
|
27
|
+
export const openBracket = new Literal("{", "{");
|
|
28
|
+
export const closeBracket = new Literal("}", "}");
|
|
29
|
+
export const comma = new Regex(",", "\\s*[,]\\s*");
|
|
30
|
+
export const trim = new Literal("trim", "trim");
|
|
31
|
+
export const not = new Literal("not", "!");
|
|
32
|
+
export const optional = new Literal("?", "?");
|
|
33
|
+
export const anyChar = new Literal("anyChar", "?");
|
|
34
|
+
export const upTo = new Literal("upTo", "->");
|
|
35
|
+
export const wall = new Literal("wall", "|");
|
|
36
|
+
export const asKeyword = new Literal("as", "as");
|
|
37
|
+
export const newLine = new Regex("newLine", "\\s*(\\r\\n|\\r|\\n)\\s*");
|
|
38
|
+
export const syntaxVersion = new Regex("syntaxVersion", "\\S*");
|
|
39
|
+
export const at = new Literal("@", "@");
|
|
40
|
+
export const optionalWS = new Optional("optionalWS", ws);
|
|
41
|
+
export const optionalLS = new Optional("optionalLS", ls);
|
|
42
|
+
|
|
43
|
+
export const literal = new Regex("literal", '"(?:\\\\.|[^"\\\\])*"');
|
|
44
|
+
export const regex = new Regex("regex", "\\/(?:\\\\.|[^\\/\\n\\r])*\\/");
|
|
45
|
+
|
|
46
|
+
export const integer = new Regex("integer", "[1-9][0-9]*|[0]");
|
|
47
|
+
export const name = new Regex("name", "[a-zA-Z_-]+[a-zA-Z0-9_-]*");
|
|
48
|
+
export const patternName = name.clone("patternName");
|
|
49
|
+
export const patternIdentifier = name.clone("patternIdentifier");
|
|
50
|
+
export const resource = literal.clone("resource");
|
|
51
|
+
|
|
52
|
+
export const comment = new Regex("comment", "#[^\\n\\r]*");
|
|
53
|
+
|
|
54
|
+
export const jsonString = literal.clone("jsonString");
|
|
55
|
+
export const jsonNumber = new Regex("jsonNumber", "-?\\d+(\\.\\d+)?");
|
|
56
|
+
export const trueLiteral = new Literal("trueLiteral", "true");
|
|
57
|
+
export const falseLiteral = new Literal("falseLiteral", "false");
|
|
58
|
+
export const jsonBoolean = new Options("jsonBoolean", [trueLiteral, falseLiteral]);
|
|
59
|
+
export const jsonNull = new Literal("jsonNull", "null");
|
|
60
|
+
export const jsonArrayItems = new Repeat("jsonArrayItems", new Reference("jsonValue"), { divider: comma, trimDivider: true });
|
|
61
|
+
export const jsonArray = new Sequence("jsonArray", [openSquareBracket, optionalWS, jsonArrayItems, optionalWS, closeSquareBracket]);
|
|
62
|
+
export const jsonObjectPropertyName = literal.clone("jsonObjectPropertyName");
|
|
63
|
+
export const jsonObjectProperty = new Sequence("jsonObjectProperty", [jsonObjectPropertyName, optionalWS, colon, optionalWS, new Reference("jsonValue")]);
|
|
64
|
+
export const jsonObjectProperties = new Repeat("jsonObjectProperties", jsonObjectProperty, { divider: comma, trimDivider: true });
|
|
65
|
+
export const jsonObject = new Sequence("jsonObject", [openBracket, optionalWS, new Optional("optionalJsonObjectProperties", jsonObjectProperties), optionalWS, closeBracket]);
|
|
66
|
+
export const jsonValue = new Options("jsonValue", [jsonString, jsonNumber, jsonBoolean, jsonNull, jsonArray, jsonObject]);
|
|
67
|
+
|
|
68
|
+
export const syntaxStatement = new Sequence("syntaxStatement", [syntax, optionalWS, syntaxVersion]);
|
|
69
|
+
|
|
70
|
+
export const decorationName = name.clone("decorationName");
|
|
71
|
+
export const methodDecorationStatement = new Sequence("methodDecorationStatement", [at, optionalWS, decorationName, optionalWS, openParen, optionalWS, new Optional("optionalJsonValue", jsonValue), optionalWS, closeParen]);
|
|
72
|
+
export const nameDecorationStatement = new Sequence("nameDecorationStatement", [at, optionalWS, decorationName]);
|
|
73
|
+
export const decorationStatement = new Options("decorationStatement", [methodDecorationStatement, nameDecorationStatement]);
|
|
74
|
+
|
|
75
|
+
export const defaultParamName = name.clone("defaultParamName");
|
|
76
|
+
export const paramDefault = new Sequence("paramDefault", [optionalLS, assign, optionalLS, defaultParamName]);
|
|
77
|
+
export const paramNameWithDefault = new Sequence("paramNameWithDefault", [patternName, new Optional("optionalParamDefault", paramDefault)]);
|
|
78
|
+
export const useParamPatterns = new Repeat("useParamPatterns", paramNameWithDefault, { divider: comma, trimDivider: true });
|
|
79
|
+
export const useParamsStatement = new Sequence("useParamsStatement", [useParams, optionalLS, openBracket, optionalWS, useParamPatterns, optionalWS, closeBracket]);
|
|
80
|
+
|
|
81
|
+
export const withParamExportPattern = patternName.clone("withParamExportPattern");
|
|
82
|
+
export const withParamStatement = new Options("withParamStatement", [new Reference("patternAssignment"), withParamExportPattern]);
|
|
83
|
+
export const withParamStatements = new Repeat("withParamStatements", withParamStatement, { divider: newLine, trimDivider: true });
|
|
84
|
+
export const withParamsExpr = new Sequence("withParamsExpr", [withParams, optionalLS, openBracket, optionalWS, withParamStatements, optionalWS, closeBracket]);
|
|
85
|
+
|
|
86
|
+
export const importNameAlias = name.clone("importNameAlias");
|
|
87
|
+
export const importAlias = new Sequence("importAlias", [patternName, ls, asKeyword, ls, importNameAlias]);
|
|
88
|
+
export const importNameOrAlias = new Options("importNameOrAlias", [importAlias, patternName]);
|
|
89
|
+
export const patternNames = new Repeat("patternNames", importNameOrAlias, { divider: comma, trimDivider: true });
|
|
90
|
+
export const importedPatterns = new Sequence("importedPatterns", [openBracket, optionalWS, patternNames, optionalWS, closeBracket]);
|
|
91
|
+
export const importStatement = new Sequence("importStatement", [imprt, optionalLS, importedPatterns, optionalLS, from, optionalLS, resource, optionalLS, new Optional("optionalWithParamsExpr", withParamsExpr)]);
|
|
92
|
+
|
|
93
|
+
export const repeatBounds = new Sequence("repeatBounds", [openBracket, optionalWS, new Optional("optionalInteger", integer), optionalWS, new Optional("optionalComma", comma), optionalWS, new Optional("optionalInteger", integer), optionalWS, closeBracket]);
|
|
94
|
+
export const oneOrMore = new Literal("oneOrMore", "+");
|
|
95
|
+
export const zeroOrMore = new Literal("zeroOrMore", "*");
|
|
96
|
+
export const repeatOptions = new Options("repeatOptions", [oneOrMore, zeroOrMore, repeatBounds]);
|
|
97
|
+
export const delimiter = new Sequence("delimiter", [comma, new Reference("patternExpr"), optionalWS, new Optional("optionalTrim", trim)]);
|
|
98
|
+
export const repeatExpr = new Sequence("repeatExpr", [openParen, optionalWS, new Reference("patternExpr"), optionalWS, new Optional("optionalDelimiter", delimiter), optionalWS, closeParen, repeatOptions]);
|
|
99
|
+
|
|
100
|
+
export const takeUntilExpr = new Sequence("takeUntilExpr", [anyChar, optionalLS, upTo, optionalLS, wall, optionalLS, new Reference("patternExpr")]);
|
|
101
|
+
|
|
102
|
+
export const sequenceExpr = new Sequence("sequenceExpr", [new Reference("patternExpr"), optionalWS, concat, optionalWS, new Reference("patternExpr")]);
|
|
103
|
+
export const optionsExpr = new Sequence("optionsExpr", [new Reference("patternExpr"), optionalWS, bar, optionalWS, new Reference("patternExpr")]);
|
|
104
|
+
export const greedyOptionsExpr = new Sequence("greedyOptionsExpr", [new Reference("patternExpr"), optionalWS, greedyBar, optionalWS, new Reference("patternExpr")]);
|
|
105
|
+
export const patternGroupExpr = new Sequence("patternGroupExpr", [openParen, optionalWS, new Reference("patternExpr"), optionalWS, closeParen]);
|
|
106
|
+
|
|
107
|
+
export const notExpr = new Sequence("notExpr", [not, optionalLS, new Reference("patternExpr")]);
|
|
108
|
+
export const optionalExpr = new Sequence("optionalExpr", [new Reference("patternExpr"), optionalLS, optional]);
|
|
109
|
+
export const rightAssociationExpr = new Sequence("rightAssociationExpr", [new Reference("patternExpr"), optionalLS, right]);
|
|
110
|
+
|
|
111
|
+
export const exportPattern = patternName.clone("exportPattern");
|
|
112
|
+
export const patternExpr = new Expression("patternExpr", [notExpr, optionalExpr, rightAssociationExpr, sequenceExpr, optionsExpr, greedyOptionsExpr, repeatExpr, patternGroupExpr, takeUntilExpr, literal, regex, patternIdentifier]);
|
|
113
|
+
export const patternAssignment = new Sequence("patternAssignment", [patternName, optionalWS, assign, optionalWS, patternExpr]);
|
|
114
|
+
export const statement = new Options("statement", [useParamsStatement, importStatement, patternAssignment, decorationStatement, exportPattern, comment]);
|
|
115
|
+
export const statements = new Repeat("statements", statement, { divider: newLine });
|
|
116
|
+
export const cpat = new Sequence("cpat", [optionalWS, new Optional("optionalSyntaxStatement", syntaxStatement), optionalWS, new Optional("optionalStatements", statements)]);
|
|
117
|
+
|
|
118
|
+
export const grammar = cpat;
|
package/src/grammar/patterns.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Pattern } from "../patterns/Pattern";
|
|
2
2
|
import { Grammar, GrammarOptions } from "./Grammar";
|
|
3
3
|
|
|
4
|
-
const kebabRegex = /-([a-z])/g;
|
|
4
|
+
const kebabRegex = /-([a-z])/g;
|
|
5
5
|
|
|
6
6
|
function kebabToCamelCase(str: string) {
|
|
7
7
|
return str.replace(kebabRegex, (_, char) => char.toUpperCase());
|
|
@@ -23,20 +23,20 @@ export function patterns(strings: TemplateStringsArray, ...values: any) {
|
|
|
23
23
|
return result;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
export function createPatternsTemplate(options: GrammarOptions){
|
|
26
|
+
export function createPatternsTemplate(options: GrammarOptions) {
|
|
27
27
|
return function patterns(strings: TemplateStringsArray, ...values: any) {
|
|
28
28
|
const combinedString = strings.reduce(
|
|
29
29
|
(result, str, i) => result + str + (values[i] || ''),
|
|
30
30
|
''
|
|
31
31
|
);
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
const result: Record<string, Pattern> = {};
|
|
34
34
|
const patterns = Grammar.parseString(combinedString, options);
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
Object.keys(patterns).forEach(k => {
|
|
37
37
|
result[kebabToCamelCase(k)] = patterns[k];
|
|
38
38
|
});
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
return result;
|
|
41
41
|
};
|
|
42
|
-
}
|
|
42
|
+
}
|
|
@@ -1,23 +0,0 @@
|
|
|
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,22 +0,0 @@
|
|
|
1
|
-
import { Sequence } from "../../patterns/Sequence";
|
|
2
|
-
import { Options } from "../../patterns/Options";
|
|
3
|
-
import { Repeat } from "../../patterns/Repeat";
|
|
4
|
-
import { comment } from "./comment";
|
|
5
|
-
import { lineSpaces, newLine } from "./spaces";
|
|
6
|
-
import { statement } from "./statement";
|
|
7
|
-
import { Optional } from "../../patterns/Optional";
|
|
8
|
-
|
|
9
|
-
const bodyLineContent = new Options("body-line-content", [
|
|
10
|
-
comment,
|
|
11
|
-
statement
|
|
12
|
-
]);
|
|
13
|
-
|
|
14
|
-
const optionalLineSpaces = new Optional("optional-line-spaces", lineSpaces);
|
|
15
|
-
|
|
16
|
-
const bodyLine = new Sequence("body-line", [
|
|
17
|
-
optionalLineSpaces,
|
|
18
|
-
new Optional("optional-body-line-content", bodyLineContent),
|
|
19
|
-
optionalLineSpaces,
|
|
20
|
-
]);
|
|
21
|
-
|
|
22
|
-
export const body = new Optional("optional-body", new Repeat("body", bodyLine, { divider: newLine }));
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
import { Literal } from "../../patterns/Literal";
|
|
2
|
-
import { Optional } from "../../patterns/Optional";
|
|
3
|
-
import { Options } from "../../patterns/Options";
|
|
4
|
-
import { Reference } from "../../patterns/Reference";
|
|
5
|
-
import { Regex } from "../../patterns/Regex";
|
|
6
|
-
import { Repeat } from "../../patterns/Repeat";
|
|
7
|
-
import { Sequence } from "../../patterns/Sequence";
|
|
8
|
-
import { name } from "./name";
|
|
9
|
-
import { allSpaces } from "./spaces";
|
|
10
|
-
|
|
11
|
-
const colon = new Literal("colon", ":");
|
|
12
|
-
const comma = new Regex("comma", "\\s*,\\s*");
|
|
13
|
-
const openBracket = new Literal("open-bracket", "{");
|
|
14
|
-
const closeBracket = new Literal("close-bracket", "}");
|
|
15
|
-
const openSquareBracket = new Literal("open-square-bracket", "[");
|
|
16
|
-
const closeSquareBracket = new Literal("close-square-bracket", "]");
|
|
17
|
-
const optionalAllSpaces = new Optional("optional-all-spaces", allSpaces);
|
|
18
|
-
|
|
19
|
-
const stringLiteral = new Regex("string-literal", '"(?:\\\\.|[^"\\\\])*"');
|
|
20
|
-
const numberLiteral = new Regex("number-literal", '[+-]?\\d+(\\.\\d+)?([eE][+-]?\\d+)?');
|
|
21
|
-
const nullLiteral = new Literal("null-literal", "null");
|
|
22
|
-
const trueLiteral = new Literal("true-literal", "true");
|
|
23
|
-
const falseLiteral = new Literal("false-literal", "false");
|
|
24
|
-
const booleanLiteral = new Options("", [trueLiteral, falseLiteral]);
|
|
25
|
-
|
|
26
|
-
const objectKey = stringLiteral.clone("object-key");
|
|
27
|
-
const objectProperty = new Sequence("object-property", [
|
|
28
|
-
objectKey,
|
|
29
|
-
optionalAllSpaces,
|
|
30
|
-
colon,
|
|
31
|
-
optionalAllSpaces,
|
|
32
|
-
new Reference("literal"),
|
|
33
|
-
]);
|
|
34
|
-
const objectProperies = new Repeat("object-properties", objectProperty, { divider: comma });
|
|
35
|
-
const objectLiteral = new Sequence("object-literal", [
|
|
36
|
-
openBracket,
|
|
37
|
-
optionalAllSpaces,
|
|
38
|
-
new Optional("optional-object-properties", objectProperies),
|
|
39
|
-
optionalAllSpaces,
|
|
40
|
-
closeBracket
|
|
41
|
-
]);
|
|
42
|
-
|
|
43
|
-
const arrayItems = new Repeat("array-items", new Reference("literal"), { divider: comma });
|
|
44
|
-
const arrayLiteral = new Sequence("array-literal", [
|
|
45
|
-
openSquareBracket,
|
|
46
|
-
optionalAllSpaces,
|
|
47
|
-
new Optional("optional-array-items", arrayItems),
|
|
48
|
-
optionalAllSpaces,
|
|
49
|
-
closeSquareBracket,
|
|
50
|
-
]);
|
|
51
|
-
|
|
52
|
-
const literal = new Options("literal", [
|
|
53
|
-
objectLiteral,
|
|
54
|
-
arrayLiteral,
|
|
55
|
-
stringLiteral,
|
|
56
|
-
booleanLiteral,
|
|
57
|
-
nullLiteral,
|
|
58
|
-
numberLiteral,
|
|
59
|
-
]);
|
|
60
|
-
|
|
61
|
-
const decoratorPrefix = new Literal("decorator-prefix", "@");
|
|
62
|
-
const decoratorName = name.clone("decorator-name");
|
|
63
|
-
const openParen = new Literal("open-paren", "(");
|
|
64
|
-
const closeParen = new Literal("close-paren", ")");
|
|
65
|
-
|
|
66
|
-
const methodDecoration = new Sequence("method-decorator", [
|
|
67
|
-
decoratorPrefix,
|
|
68
|
-
decoratorName,
|
|
69
|
-
optionalAllSpaces,
|
|
70
|
-
openParen,
|
|
71
|
-
optionalAllSpaces,
|
|
72
|
-
new Optional("optional-args", literal),
|
|
73
|
-
optionalAllSpaces,
|
|
74
|
-
closeParen
|
|
75
|
-
]);
|
|
76
|
-
|
|
77
|
-
const nameDecoration = new Sequence("name-decorator", [
|
|
78
|
-
decoratorPrefix,
|
|
79
|
-
decoratorName,
|
|
80
|
-
]);
|
|
81
|
-
|
|
82
|
-
export const decoratorStatement = new Options("decorator-statement", [
|
|
83
|
-
methodDecoration,
|
|
84
|
-
nameDecoration,
|
|
85
|
-
]);
|