clarity-pattern-parser 11.3.9 → 11.3.11

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.
@@ -1,182 +1,331 @@
1
- # Grammar
1
+ # Grammar Documentation
2
2
 
3
- ## Literal
3
+ This guide describes the syntax rules and composition patterns supported by cpat. Each section shows how to define reusable parsing rules.
4
4
 
5
- ```
5
+ ---
6
+
7
+ ## Literals
8
+
9
+ A **literal** matches an exact string.
10
+
11
+ ```grammar
6
12
  name = "Literal"
7
13
  ```
8
14
 
15
+ ---
16
+
9
17
  ## Regex
10
18
 
11
- ```
19
+ A **regex** pattern matches text using a regular expression.
20
+
21
+ ```grammar
12
22
  digits = /\d+/
13
23
  ```
14
24
 
15
25
  ### Regex Caveats
26
+ Do **not** use `^` at the start or `$` at the end of your regex. If you want to constrain the beginning or end of the input, use a dedicated pattern instead.
16
27
 
17
- Do not use "^" at the beginning or "$" at the end of your regular expression. If
18
- you are creating a regular expression that is concerned about the beginning and
19
- end of the text you should probably just use a regular expression.
28
+ ---
20
29
 
21
- ## Or
22
- This succeeds if it matches any of the options.
23
- ```
24
- multiply = "*"
25
- divide = "/"
26
- operators = mulitply | divide
27
- ```
30
+ ## Sequence
28
31
 
29
- ## And
30
- This succeeds if it matches all of the patterns in the order they are placed.
31
- ```
32
+ A **sequence** succeeds only if all patterns match in the given order.
33
+
34
+ ```grammar
32
35
  space = " "
33
36
  first-name = "John"
34
37
  last-name = "Doe"
35
- full-name = first-name & space & last-name
38
+ full-name = first-name + space + last-name
36
39
  ```
37
40
 
38
- ### Optional pattern
39
- Patterns within the and sequence can be optional.
40
- ```
41
+ ---
42
+
43
+ ## Optional Pattern
44
+
45
+ Patterns in a sequence may be marked **optional**.
46
+
47
+ ```grammar
41
48
  space = " "
42
49
  first-name = /\w+/
43
50
  last-name = /\w+/
44
51
  middle-name = /\w+/
45
- middle-name-with-space = middle-name & space
52
+ middle-name-with-space = middle-name + space
46
53
 
47
- full-name = first-name & space & middle-name-with-space? & last-name
54
+ full-name = first-name + space + middle-name-with-space? + last-name
48
55
  ```
49
56
 
50
- ### Negative Look Ahead
51
- This will ensure that the first name isn't `Jack` before continuing to match for
52
- a name.
57
+ ---
53
58
 
54
- ```
59
+ ## Negative Lookahead
60
+
61
+ Use `!` to prevent a specific pattern from matching.
62
+
63
+ ```grammar
55
64
  space = " "
56
65
  first-name = /\w+/
57
66
  last-name = /\w+/
58
- middle-name = /\w+/
59
- middle-name-with-space = m-middle-name & space
60
67
  jack = "Jack"
61
68
 
62
- full-name = !jack & first-name & space & middle-name-with-space? & last-name
69
+ full-name = !jack + first-name + space + last-name
63
70
  ```
64
71
 
65
- ## Repeat
72
+ This ensures the first name is not `"Jack"`.
73
+
74
+ ---
75
+
76
+ ## Options
77
+
78
+ An **options** pattern succeeds if *any one* of the choices matches.
79
+
80
+ ```grammar
81
+ multiply = "*"
82
+ divide = "/"
83
+ operators = multiply | divide
66
84
  ```
85
+
86
+ ---
87
+
88
+ ## Repeat
89
+
90
+ ### Zero or More
91
+
92
+ ```grammar
67
93
  digit = /\d/
68
94
  digits = (digit)*
69
95
  ```
70
96
 
71
- ### Zero Or More Pattern
72
- ```
97
+ ### Zero or More with Delimiters
98
+
99
+ ```grammar
73
100
  digit = /\d/
74
101
  comma = ","
75
102
  digits = (digit, comma)*
76
103
  ```
77
104
 
78
- ### Zero Or More & Trim Trailing Divider
79
- ```
105
+ ### One or More with Trimmed Trailing Delimiter
106
+
107
+ ```grammar
80
108
  digit = /\d/
81
109
  comma = ","
82
- digits = (digit, comma){t}
110
+ digits = (digit, comma trim)+
83
111
  ```
84
112
 
85
- This is a useful feature if you don't want the divider to be the last pattern found. Let's look at the example below to understand.
113
+ This prevents trailing commas from being accepted.
86
114
 
87
- ```ts
88
- const expression = `
89
- digit = /\d/
90
- comma = ","
91
- digits = (digit, comma){t}
92
- `;
93
-
94
- const { digits } = Gammar.parse(expression);
115
+ ---
95
116
 
96
- let result = digits.exec("1,2,3");
97
- expect(result.ast?.value).toBe("1,2,3");
117
+ ### One or More
98
118
 
99
- result = digits.exec("1,2,");
100
- expect(result.ast).toBeNull();
119
+ ```grammar
120
+ digit = /\d/
121
+ digits = (digit)+
101
122
  ```
102
123
 
103
- ### Zero Or More
124
+ ### Exact Count
104
125
 
105
- ```
126
+ ```grammar
106
127
  digit = /\d/
107
- comma = ","
108
- digits = (digit, comma)*
128
+ digits = (digit){2}
109
129
  ```
110
130
 
111
- ### Upper Limit
131
+ ### Bounded Repeats
112
132
 
113
- ```
133
+ ```grammar
114
134
  digit = /\d/
115
- comma = ","
116
- digits = (digit, comma){,3}
135
+ digits = (digit){1,3} # between 1 and 3
136
+ digits = (digit){,3} # up to 3
117
137
  ```
118
138
 
119
- ### Bounded
139
+ ---
140
+
141
+ ## Expressions
142
+
143
+ Expressions support **prefix**, **infix**, **postfix**, and **right-associative** notation, with operator precedence and recursion.
144
+
145
+ - **Prefix**: Operator(s) come before the expression. The sequence must end with the name of the expression being made.
146
+ - **Infix**: Operator(s) come between expressions.
147
+ - **Postfix**: Operator(s) come after the expression.
148
+ - **Right-associative**: Operator(s) group toward the right.
149
+
150
+ ### Prefix Expression
120
151
 
152
+ ```grammar
153
+ increment = "++"
154
+ integer = /[1-9][0-9]*/
155
+ space = /\s+/
156
+
157
+ prefix-expr = increment + space? + expr
158
+ expr = prefix-expr | integer
121
159
  ```
122
- digit = /\d/
123
- comma = ","
124
- digits = (digit, comma){1,3}
160
+
161
+ Examples:
162
+ - `++5`
163
+ - `++ 10`
164
+
165
+ ---
166
+
167
+ ### Infix Expression
168
+
169
+ ```grammar
170
+ add-sub = "+" | "-"
171
+ mul-div = "*" | "/"
172
+ integer = /[1-9][0-9]*/
173
+ space = /\s+/
174
+
175
+ add-sub-expr = expr + space? + add-sub + space? + expr
176
+ mul-div-expr = expr + space? + mul-div + space? + expr
177
+
178
+ expr = mul-div-expr | add-sub-expr | integer
125
179
  ```
126
180
 
127
- ### Lower Limit
181
+ Examples:
182
+ - `4 * 2`
183
+ - `7 + 3`
184
+
185
+ ---
128
186
 
187
+ ### Postfix Expression
188
+
189
+ ```grammar
190
+ factorial = "!"
191
+ integer = /[1-9][0-9]?/
192
+ space = /\s+/
193
+
194
+ postfix-expr = expr + space? + factorial
195
+ expr = postfix-expr | integer
129
196
  ```
130
- digit = /\d/
131
- comma = ","
132
- digits = (digit, comma){1,}
197
+
198
+ Examples:
199
+ - `5!`
200
+ - `10 !`
201
+
202
+ ---
203
+
204
+ ### Combined Expressions
205
+
206
+ By layering them into a single `expr` rule, you can combine prefix, infix, and postfix with precedence:
207
+
208
+ ```grammar
209
+ increment = "++"
210
+ factorial = "!"
211
+ add-sub = "+" | "-"
212
+ mul-div = "*" | "/"
213
+
214
+ integer = /[1-9][0-9]*/
215
+ space = /\s+/
216
+
217
+ prefix-expr = increment + space? + expr
218
+ postfix-expr = expr + space? + factorial
219
+ mul-div-expr = expr + space? + mul-div + space? + expr
220
+ add-sub-expr = expr + space? + add-sub + space? + expr
221
+
222
+ expr = postfix-expr
223
+ | prefix-expr
224
+ | mul-div-expr
225
+ | add-sub-expr
226
+ | integer
133
227
  ```
134
228
 
135
- ### Import
229
+ Examples:
230
+ - `++5`
231
+ - `5!`
232
+ - `++5!`
233
+ - `2 + 3 * 4`
234
+
235
+ ---
236
+
237
+ ### Recursive Expressions
238
+
239
+ Since each rule references `expr`, the grammar is recursive and can handle deeply nested inputs.
240
+
241
+ Examples:
242
+ - `7++` → `postfix-expr`
243
+ - `7++ * 9` → `mul-div-expr`
244
+ - `7++ * 9 + 10` → `(7++) * 9 + 10` with correct precedence
245
+
246
+ ---
247
+
248
+ ### Right-Associative Expressions
249
+
250
+ Some operators must associate to the **right**. Mark the operator with `right` to enforce this.
251
+
252
+ ```grammar
253
+ power = "^"
254
+ integer = /[1-9][0-9]*/
255
+ space = /\s+/
256
+
257
+ power-expr = expr + space? + power + space? + expr
258
+ expr = power-expr right | integer
136
259
  ```
260
+
261
+ Examples:
262
+ - `2 ^ 3 ^ 2`
263
+ - Right-associative → `2 ^ (3 ^ 2)` = `512`
264
+ - Left-associative → `(2 ^ 3) ^ 2` = `64`
265
+
266
+ ---
267
+
268
+
269
+ ## Imports
270
+
271
+ ### Basic Import
272
+
273
+ ```grammar
137
274
  import { spaces } from "https://some.cdn.com/some/spaces.cpat"
138
275
 
139
276
  first-name = "John"
140
277
  last-name = "Doe"
141
- full-name = first-name & spaces & last-name
278
+ full-name = first-name + spaces + last-name
142
279
  ```
143
280
 
144
- ### Muliple Named Imports
145
- ```
281
+ ### Multiple Named Imports
282
+
283
+ ```grammar
146
284
  import { spaces, first-name } from "https://some.cdn.com/some/spaces.cpat"
147
285
 
148
286
  last-name = "Doe"
149
- full-name = first-name & spaces & last-name
287
+ full-name = first-name + spaces + last-name
150
288
  ```
151
289
 
152
- ### Muliple Imports
153
- ```
290
+ ### Multiple Imports
291
+
292
+ ```grammar
154
293
  import { spaces, first-name } from "https://some.cdn.com/some/patterns.cpat"
155
294
  import { last-name } from "https://some.cdn.com/some/last-name.cpat"
156
295
 
157
- full-name = first-name & spaces & last-name
296
+ full-name = first-name + spaces + last-name
158
297
  ```
159
298
 
160
- ### Import Params
161
- This allows you to inject patterns within another pattern.
299
+ ---
300
+
301
+ ## Import Parameters
302
+
303
+ You can inject parameters into imported patterns.
304
+
305
+ **File:** `main.ts`
162
306
  ```ts
163
- const firstName = new Literal("first-name", "Jared");
164
- const grammar = Grammar.import('file.cpat', {params: [firstName, LastName]})
165
- ```
166
- file.cpat
307
+ const firstName = new Literal("first-name", "John");
308
+ const lastName = new Literal("last-name", "Doe");
309
+ const grammar = Grammar.import('file.cpat', { params: [firstName, LastName] });
167
310
  ```
168
- import params { first-names, last-names }
169
311
 
170
- full-name = first-names & spaces & last-names
312
+ **File:** `file.cpat`
313
+ ```grammar
314
+ use params { first-name, last-name }
315
+
316
+ full-name = first-name + spaces + last-name
171
317
  ```
172
318
 
173
319
  ### Imports with Params
174
- ```
175
- import params { other-pattern }
320
+
321
+ ```grammar
322
+ use params { other-pattern }
176
323
  import { first-names, last-names } from "some-file.cpat" with params {
177
324
  some-pattern = "Some Pattern"
178
325
  some-pattern2 = other-pattern
179
326
  }
180
327
 
181
- full-name = first-names & spaces & last-names
328
+ full-name = first-names + spaces + last-names
182
329
  ```
330
+
331
+ ---