@willbooster/tree-sitter-haskell 0.0.0-placeholder.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/grammar/exp.js ADDED
@@ -0,0 +1,413 @@
1
+ const {
2
+ sep1,
3
+ sep,
4
+ parens,
5
+ braces,
6
+ brackets,
7
+ layout_sort,
8
+ layout,
9
+ unboxed_tuple_nonempty,
10
+ unboxed_sum_single,
11
+ qualified,
12
+ } = require('./util.js')
13
+
14
+ module.exports = {
15
+
16
+ // ------------------------------------------------------------------------
17
+ // names
18
+ // ------------------------------------------------------------------------
19
+
20
+ _exp_name: $ => choice(
21
+ $._cons,
22
+ $._vars,
23
+ $.variable,
24
+ $.implicit_variable,
25
+ $.label,
26
+ ),
27
+
28
+ _exp_th_quoted_name: $ => choice(
29
+ seq('\'', field('name', choice($._vars, $._cons))),
30
+ prec('prefix', seq('\'\'', field('type', $.type))),
31
+ ),
32
+
33
+ // ------------------------------------------------------------------------
34
+ // tuples and parens
35
+ // ------------------------------------------------------------------------
36
+
37
+ _exp_parens: $ => parens($, field('expression', $._exp)),
38
+
39
+ // Having this separate reduces size by ~15kB
40
+ _exp_tuple_elems: $ => seq(
41
+ choice(
42
+ seq(repeat1(','), field('element', $._exp)),
43
+ seq(field('element', $._exp), ',', optional(field('element', $._exp))),
44
+ ),
45
+ repeat(seq(',', optional(field('element', $._exp))))
46
+ ),
47
+
48
+ /**
49
+ * This needs to be disambiguated from `prefix_tuple`, which is a constructor with _only_ commas.
50
+ * Tuple sections aren't allowed in patterns.
51
+ *
52
+ * Since tuple expressions can contain singular expressions in sections like `(a,)` and `(,a)`, it has to be ensured
53
+ * that there is _at least_ each one comma and one expression in there, but the comma may be on either side and be
54
+ * preceded by any number of further commas, like `(,,,a)`.
55
+ *
56
+ * The final `repeat` is simpler, it just has to ensure that no two `_exp`s can be successive, but this encoding
57
+ * means that the optional `_exp` after `(5,)` needs to be included in the `choice`, otherwise a simple pair
58
+ * would be impossible.
59
+ */
60
+ _exp_tuple: $ => parens($, $._exp_tuple_elems),
61
+
62
+ /**
63
+ * Unlike their boxed variants, unboxed tuples may be nullary and unary, making it simpler to parse them.
64
+ */
65
+ _exp_unboxed_tuple: $ => unboxed_tuple_nonempty($, $._exp),
66
+
67
+ /**
68
+ * Unboxed sums must have at least one separating `|`, otherwise the expression would be a unary or nullary tuple.
69
+ * This is a lenient parser that allows multiple variants to be filled in, for simplicity.
70
+ */
71
+ _exp_unboxed_sum: $ => unboxed_sum_single($, $._exp),
72
+
73
+ // ------------------------------------------------------------------------
74
+ // lists
75
+ // ------------------------------------------------------------------------
76
+
77
+ _exp_list: $ => brackets($, sep1(',', field('element', $._exp)), optional(',')),
78
+
79
+ /**
80
+ * An expression like `[1,2..20]`.
81
+ */
82
+ _exp_arithmetic_sequence: $ => brackets(
83
+ $,
84
+ field('from', $._exp),
85
+ optional(seq(',', field('step', $._exp))),
86
+ $._dotdot,
87
+ optional(field('to', $._exp)),
88
+ ),
89
+
90
+ /**
91
+ * `TransformListComp`, group style.
92
+ *
93
+ * Inlining `_exp` here is necessary to avoid a conflict.
94
+ */
95
+ group: $ => seq(
96
+ 'then',
97
+ 'group',
98
+ optional(seq('by', field('key', choice(alias($._exp_signature, $.signature), $.expression)))),
99
+ 'using',
100
+ field('classifier', $._exp),
101
+ ),
102
+
103
+ /**
104
+ * `TransformListComp`, simple transformation style.
105
+ */
106
+ transform: $ => seq(
107
+ 'then',
108
+ field('transformation', $._exp),
109
+ optional(seq('by', field('key', $._exp))),
110
+ ),
111
+
112
+ qualifier: $ => choice(
113
+ $.generator,
114
+ $.let,
115
+ $.transform,
116
+ $.group,
117
+ alias($._exp, $.boolean),
118
+ ),
119
+
120
+ /**
121
+ * This is a supertype.
122
+ */
123
+ qualifiers: $ => seq(sep1(',', field('qualifier', $.qualifier))),
124
+
125
+ _exp_list_comprehension: $ => brackets(
126
+ $,
127
+ field('expression', $._exp),
128
+ repeat1(seq('|', field('qualifiers', $.qualifiers))),
129
+ ),
130
+
131
+ // ------------------------------------------------------------------------
132
+ // greedy block args
133
+ // ------------------------------------------------------------------------
134
+
135
+ _exp_lambda: $ => seq(
136
+ '\\',
137
+ field('patterns', $.patterns),
138
+ $._arrow,
139
+ field('expression', $._exp),
140
+ ),
141
+
142
+ _exp_let_in: $ => seq($._let, optional($._phantom_in), 'in', field('expression', $._exp)),
143
+
144
+ _exp_conditional: $ => seq(
145
+ 'if',
146
+ field('if', $._exp),
147
+ repeat(';'),
148
+ 'then',
149
+ field('then', $._exp),
150
+ repeat(';'),
151
+ 'else',
152
+ field('else', $._exp),
153
+ ),
154
+
155
+ /**
156
+ * These block arguments don't end in a layout, so they all range over all following block arguments and will
157
+ * therefore always be the last argument in an application or infix chain.
158
+ * They also pull a trailing type annotation into their body.
159
+ */
160
+ _exp_greedy: $ => choice(
161
+ alias($._exp_lambda, $.lambda),
162
+ alias($._exp_let_in, $.let_in),
163
+ alias($._exp_conditional, $.conditional),
164
+ ),
165
+
166
+ // ------------------------------------------------------------------------
167
+ // do
168
+ // ------------------------------------------------------------------------
169
+
170
+ _exp_statement: $ => $._exp,
171
+
172
+ /**
173
+ * This is a supertype.
174
+ */
175
+ statement: $ => choice(
176
+ alias($._exp_statement, $.exp),
177
+ alias($.generator, $.bind),
178
+ $.let,
179
+ $.rec,
180
+ ),
181
+
182
+ _statements: $ => layout_sort($, $._cmd_layout_start_do, field('statement', $.statement)),
183
+
184
+ rec: $ => seq('rec', $._statements),
185
+
186
+ _do_keyword: _ => choice('mdo', 'do'),
187
+
188
+ do_module: $ => field('qualified_do', qualified($, $._do_keyword)),
189
+
190
+ _do: $ => choice(
191
+ $.do_module,
192
+ $._do_keyword
193
+ ),
194
+
195
+ _exp_do: $ => seq($._do, $._statements),
196
+
197
+ // ------------------------------------------------------------------------
198
+ // case
199
+ // ------------------------------------------------------------------------
200
+
201
+ match: $ => seq(
202
+ $._guards,
203
+ optional($._phantom_arrow),
204
+ $._arrow,
205
+ $._cmd_texp_end,
206
+ field('expression', $._exp),
207
+ ),
208
+
209
+ _simple_match: $ => seq($._arrow, field('expression', $._exp)),
210
+
211
+ _matches: $ => field('match', choice(
212
+ alias($._simple_match, $.match),
213
+ repeat1($.match),
214
+ )),
215
+
216
+ alternative: $ => seq(
217
+ field('pattern', $._pat),
218
+ $._matches,
219
+ optional($._where_binds),
220
+ ),
221
+
222
+ _nalt: $ => seq(
223
+ field('patterns', $.patterns),
224
+ $._matches,
225
+ optional($._where_binds),
226
+ ),
227
+
228
+ alternatives: $ => layout_sort($, $._cmd_layout_start_case, field('alternative', $.alternative)),
229
+ _nalts: $ => layout_sort($, $._cmd_layout_start_case, field('alternative', alias($._nalt, $.alternative))),
230
+
231
+ _exp_case: $ => seq('case', $._exp, 'of', optional(field('alternatives', $.alternatives))),
232
+
233
+ _exp_lambda_case: $ => seq(
234
+ '\\',
235
+ 'case',
236
+ optional(field('alternatives', $.alternatives)),
237
+ ),
238
+
239
+ /**
240
+ * alternatives are not optional in a `\cases` expression, but we're lenient.
241
+ */
242
+ _exp_lambda_cases: $ => seq(
243
+ '\\',
244
+ 'cases',
245
+ optional(field('alternatives', alias($._nalts, $.alternatives))),
246
+ ),
247
+
248
+ _exp_multi_way_if: $ => seq(
249
+ 'if',
250
+ $._cmd_layout_start_if,
251
+ repeat(field('match', $.match)),
252
+ $._cond_layout_end,
253
+ ),
254
+
255
+ // ------------------------------------------------------------------------
256
+ // record
257
+ // ------------------------------------------------------------------------
258
+
259
+ field_update: $ => choice(
260
+ alias('..', $.wildcard),
261
+ seq(
262
+ field('field', $._field_spec),
263
+ optional(seq('=', field('expression', $._exp)))
264
+ ),
265
+ ),
266
+
267
+ _exp_record: $ => prec('record', seq(
268
+ field('expression', $.expression),
269
+ braces($, sep(',', field('field', $.field_update)))),
270
+ ),
271
+
272
+ _exp_projection_selector: $ => parens(
273
+ $,
274
+ $._any_prefix_dot,
275
+ field('field', $.variable),
276
+ repeat(seq($._tight_dot, field('field', $.variable))),
277
+ ),
278
+
279
+ /**
280
+ * A dot-syntax field projection like `var.name.othername`.
281
+ */
282
+ _exp_projection: $ => seq(
283
+ prec('projection', seq(
284
+ field('expression', $.expression),
285
+ $._tight_dot,
286
+ )),
287
+ field('field', $.field_name),
288
+ ),
289
+
290
+ // ------------------------------------------------------------------------
291
+ // application
292
+ // ------------------------------------------------------------------------
293
+
294
+ explicit_type: $ => parens($, 'type', field('type', $.type)),
295
+
296
+ _exp_apply: $ => prec.left('apply', seq(
297
+ field('function', $.expression),
298
+ field('argument', choice(
299
+ $.expression,
300
+ alias($._at_type, $.type_application),
301
+ $.explicit_type,
302
+ )),
303
+ )),
304
+
305
+ // ------------------------------------------------------------------------
306
+ // operators
307
+ // ------------------------------------------------------------------------
308
+
309
+ _exp_op: $ => choice(
310
+ $._sym,
311
+ $._op_ticked,
312
+ alias($._prefix_dot, $.operator),
313
+ ),
314
+
315
+ _exp_section_left: $ => parens(
316
+ $,
317
+ field('left_operand', $.expression),
318
+ $._cond_left_section_op,
319
+ field('operator', choice(
320
+ $._exp_op,
321
+ $._operator_minus,
322
+ $._qsym,
323
+ )),
324
+ ),
325
+
326
+ _exp_section_right: $ => parens(
327
+ $,
328
+ choice(
329
+ alias($._operator_qual_dot_head, $.operator),
330
+ $._ops,
331
+ ),
332
+ field('right_operand', $.expression),
333
+ ),
334
+
335
+ _exp_negation: $ => seq(
336
+ field('minus', '-'),
337
+ prec('negation', field('expression', $.expression)),
338
+ ),
339
+
340
+ /**
341
+ * Infix expressions have severe conflicts with several structures:
342
+ *
343
+ * - Negation is supposed to bind less tight than application and tighter than infix, which requires an unsolvable
344
+ * precedence configuration
345
+ * - Qualified operators cannot be identified with single-token lookahead, which causes ambiguity with function
346
+ * application
347
+ * - Left operator sections require infix expressions in their operand to reduce before the section operator, but
348
+ * single-token lookahead also makes this decision impossible
349
+ *
350
+ * All of these are solved with external symbols.
351
+ * Consult `grammar/externals.js` for more information.
352
+ */
353
+ _exp_infix: $ => prec.right('infix', seq(
354
+ field('left_operand', $.expression),
355
+ optional($._cond_no_section_op),
356
+ field('operator', choice(
357
+ seq($._cond_minus, $._operator_minus),
358
+ $._exp_op,
359
+ seq($._cond_qualified_op, $._qsym),
360
+ )),
361
+ field('right_operand', $.expression),
362
+ )),
363
+
364
+ // ------------------------------------------------------------------------
365
+ // top level
366
+ // ------------------------------------------------------------------------
367
+
368
+ /**
369
+ * This is a supertype.
370
+ */
371
+ expression: $ => choice(
372
+ alias($._exp_infix, $.infix),
373
+ alias($._exp_negation, $.negation),
374
+ alias($._exp_apply, $.apply),
375
+ alias($._exp_record, $.record),
376
+ alias($._exp_projection, $.projection),
377
+ alias($._exp_arithmetic_sequence, $.arithmetic_sequence),
378
+ alias($._exp_list_comprehension, $.list_comprehension),
379
+ alias($._exp_unboxed_tuple, $.unboxed_tuple),
380
+ alias($._exp_unboxed_sum, $.unboxed_sum),
381
+ alias($._exp_projection_selector, $.projection_selector),
382
+ alias($._exp_quote, $.quote),
383
+ alias($._exp_typed_quote, $.typed_quote),
384
+ alias($._exp_th_quoted_name, $.th_quoted_name),
385
+ alias($._exp_lambda_case, $.lambda_case),
386
+ alias($._exp_lambda_cases, $.lambda_cases),
387
+ alias($._exp_do, $.do),
388
+ alias($._exp_parens, $.parens),
389
+ alias($._exp_tuple, $.tuple),
390
+ alias($._exp_list, $.list),
391
+ // Not using a name like "empty list" here because it's only really special in types.
392
+ alias($._plist, $.list),
393
+ alias($._exp_section_left, $.left_section),
394
+ alias($._exp_section_right, $.right_section),
395
+ $._exp_greedy,
396
+ alias($._exp_case, $.case),
397
+ alias($._exp_multi_way_if, $.multi_way_if),
398
+ $._exp_name,
399
+ $._universal,
400
+ ),
401
+
402
+ _exp_signature: $ => prec.right('annotated', seq(
403
+ field('expression', $.expression),
404
+ $._type_annotation,
405
+ )),
406
+
407
+ _exp: $ => choice(
408
+ alias($._exp_signature, $.signature),
409
+ // Right-associative means that the reduction of `expression` to `_exp` loses against any shift.
410
+ prec.right($.expression),
411
+ ),
412
+
413
+ }
@@ -0,0 +1,177 @@
1
+ module.exports = {
2
+
3
+ /**
4
+ * These rules are handled manually by the custom lexer in `src/scanner.c`.
5
+ * Whenever the symbols are used in the rule tree, the parser executes the scanner.
6
+ * Since several symbols are present both here and in `extras`, the scanner will be invoked before every single
7
+ * natively lexed symbol, repeatedly, until it fails.
8
+ * This makes indentation/layout tracking simpler.
9
+ *
10
+ * There are three special behavioral classes of symbols in this grammar, indicated by their name prefix:
11
+ *
12
+ * `cmd`: Commands are sequenced after key tokens like opening braces that unconditionally trigger a state change in
13
+ * the scanner.
14
+ * They don't require the scanner to _decide_ that a symbol is valid – the native parser has already committed
15
+ * to a symbol, and the command relays that information to the scanner so it can update its state and return.
16
+ * For example, after having parsed an opening brace, the scanner adds a brace context to the stack in reaction
17
+ * to `_cond_brace_open`, which will influence its future behavior.
18
+ * These symbols do not produce nodes in the parse tree.
19
+ *
20
+ * `cond`: Conditions are hard requirements in the grammar that are decided by the scanner based on its state and the
21
+ * lookahead.
22
+ * For example, whitespace-sensitive operators (tight infix /prefix ops) like the `@` in a type application or
23
+ * the `.` in a record projection are lexed when the following characters have certain properties.
24
+ * When the scanner decides that such a symbol is valid, the parser cannot attempt to use an alternative
25
+ * interpretation like it can with conflicts.
26
+ * This is often difficult, but also especially useful to force declarations and other layout items to be
27
+ * terminated when a new line has smaller or equal indent, preventing incorrect interpretations as top level
28
+ * expression splices spanning multiple lines.
29
+ *
30
+ * `phantom`: Phantom symbols are used to signal to the scanner that certain constructs are valid without requiring
31
+ * the scanner to actually parse them and produce text nodes for them.
32
+ * In the grammar, they are always optional, and the scanner never emits the phantom symbol itself, but
33
+ * decides whether to emit _other_ symbols when the phantom symbol is _not_ valid.
34
+ * This is used to implement GHC's tactic of allowing layouts to end _whenever a parse error occurs_, but
35
+ * using specialized heuristics.
36
+ *
37
+ * Most other symbols produce nodes, except for newline and the error sentinel.
38
+ */
39
+ externals: $ => [
40
+
41
+ // This is an unused symbol that indicates to the scanner that a parse error has occurred.
42
+ // Tree-sitter marks _all_ symbols as valid when calling the scanner after an error, so a symbol that's not used in
43
+ // the grammar is only valid if that is the case.
44
+ $.error_sentinel,
45
+
46
+ // Emitted after every newline with equal or less indent to terminate layout-based rules, with a few exceptions.
47
+ $._cond_layout_semicolon,
48
+
49
+ // Instruct the scanner to push a layout context.
50
+ // The first one is for declarations and miscellaneous other layouts.
51
+ // The others are for the specific syntax construct.
52
+ // The quote layout is for declaration quotes (`[d|data A ...|]`).
53
+ $._cmd_layout_start,
54
+ $._cmd_layout_start_do,
55
+ $._cmd_layout_start_case,
56
+ $._cmd_layout_start_if,
57
+ $._cmd_layout_start_let,
58
+ $._cmd_layout_start_quote,
59
+ // This variant is used in a `choice` with the others, and serves only to create a terminal node for explicit
60
+ // braces.
61
+ // If the scanner emitted the same symbol for virtual and explicit braces, we would either get an anonymous node
62
+ // ranging over the brace, or a terminal brace node even for virtual starts if we were to alias the symbol to '{'
63
+ // unconditionally.
64
+ // So we use separate symbols and alias only this one.
65
+ // The same reasoning applies to `_cond_layout_end_explicit`.
66
+ // The terminal could be ensured in different ways – adding an `optional('{')` after the start symbol, using
67
+ // `seq($._cmd_layout_start_explicit, '{')` instead of including the brace in the scanner range, or branching the
68
+ // entire layout on the start token to unconditionally use `_cmd_brace_close` instead of
69
+ // `_cond_layout_end_explicit`.
70
+ // However, these solutions are all very expensive, adding between 500 and 1000kB to the shared object size, and up
71
+ // to a second in generation time.
72
+ $._cmd_layout_start_explicit,
73
+
74
+ // Emitted when a new line's indent mandates ending the current layout (depending on the layout sort), or when a
75
+ // special inline layout-ending token is encountered, like an `in`.
76
+ $._cond_layout_end,
77
+ $._cond_layout_end_explicit,
78
+
79
+ // Instruct the scanner to push or pop a brace context.
80
+ $._cmd_brace_open,
81
+ $._cmd_brace_close,
82
+
83
+ // Instruct the scanner to push or pop a tuple expression context.
84
+ // In parenthesized or bracketed expressions, certain tokens (like commas, bars, and closing brackets), can end
85
+ // layouts, so the scanner must be aware of them.
86
+ $._cmd_texp_start,
87
+ $._cmd_texp_end,
88
+
89
+ // Signal to the scanner that these symbols are valid.
90
+ // See the explanation of phantom symbols above.
91
+ $._phantom_where,
92
+ $._phantom_in,
93
+ $._phantom_arrow,
94
+ $._phantom_bar,
95
+ $._phantom_deriving,
96
+
97
+ // Detect and emit text nodes for comments and CPP.
98
+ // In particular, #else branches of CPP conditionals a fully contained in the resulting node, since their nonlinear
99
+ // nature means they cannot be parsed.
100
+ $.comment,
101
+ $.haddock,
102
+ $.cpp,
103
+ $.pragma,
104
+
105
+ // Starting quote brackets are a bit messy, so it's easier to let the scanner signal that it encountered one.
106
+ // The body produces a text node until the ending bracket.
107
+ $._cond_quote_start,
108
+ $.quasiquote_body,
109
+
110
+ // Whitespace-sensitive operators for splices (`$`, `$$`), projection and module dots (`a.b`, `A.b`), arithmetic
111
+ // sequence dots `[1..10]`, as-pattern (`a@(Just b)`), type application (`@Int`), strictness and laziness
112
+ // annotations (`!pat`, `~Int`), and modifiers (`Int %1 -> Int`).
113
+ $._cond_splice,
114
+ $._cond_qual_dot,
115
+ $._cond_tight_dot,
116
+ $._cond_prefix_dot,
117
+ $._cond_dotdot,
118
+ $._cond_tight_at,
119
+ $._cond_prefix_at,
120
+ $._cond_tight_bang,
121
+ $._cond_prefix_bang,
122
+ $._cond_tight_tilde,
123
+ $._cond_prefix_tilde,
124
+ $._cond_prefix_percent,
125
+
126
+ // GHC lexes all qualified names as atomic tokens, but we can't do that because we need nodes for their
127
+ // substructures.
128
+ // However, infix expressions need single-token lookahead for the operator to resolve conflicts, which is
129
+ // impossible without an external.
130
+ // This symbol detects a qualified symbolic operator.
131
+ $._cond_qualified_op,
132
+ // This one performs an additional lookahead check for a following closing parenthesis, to disambiguate left
133
+ // sections from infix ops in `(a - b +)`.
134
+ $._cond_left_section_op,
135
+ // This is an auxiliary for `_cond_left_section_op` that allows restarting the scanner without that symbol being
136
+ // valid again when whitespace was skipped after a symop to discover that there's no parenthesis.
137
+ // Without this, we would get wrong token ranges for the operator.
138
+ $._cond_no_section_op,
139
+
140
+ // This symbol always succeeds when a minus is ahead.
141
+ // Infix expressions with minus as the operator conflict with function application.
142
+ // `a - b` can be parsed as `a (- b)`, which would normally be solved by a simple precedence entry, but is
143
+ // impossible to express because it contradicts another conflict: Negation in the left operand, `- a + b`, which
144
+ // must be parsed as `(- a) + b`.
145
+ // Simply sequencing this external before the operator solves this conflict, because a minus following an expression
146
+ // can never be negation; it can only occur at the beginning of an expression.
147
+ $._cond_minus,
148
+
149
+ /**
150
+ * The following symbols perform lookahead for various type constructs to resolve conflicts between infix types,
151
+ * contexts, and type/datacon heads, because using GLR conflicts for these is very brittle and frequently leads to
152
+ * misparsed trees.
153
+ *
154
+ * See the documentation under 'Constraints' in `src/scanner.c` for more.
155
+ */
156
+ $._cond_context,
157
+ $._cond_infix,
158
+ $._cond_data_infix,
159
+ $._cond_assoc_tyinst,
160
+
161
+ // Symbolic operators, producing text nodes.
162
+ // These are very difficult to parse in the grammar, because unlike most languages, Haskell's operators are not a
163
+ // finite set, and therefore cannot be lexically disambiguated from special operators like `->`.
164
+ // In the presence of runtime conflicts, this can easily lead to the invalid interpretation of reserved operators as
165
+ // identifiers.
166
+ // Furthermore, the regexes for all the unicode categories produce very large ternary operator trees if specified
167
+ // in the grammar.
168
+ $._varsym,
169
+ $._consym,
170
+
171
+ // The newline is used as a dummy symbol that is emitted whenever the scanner has to update its state even though
172
+ // the current position must be parsed by the grammar.
173
+ token(prec(0, /\n/)),
174
+
175
+ ],
176
+
177
+ }
@@ -0,0 +1,54 @@
1
+ const {
2
+ sep1,
3
+ layout_sort,
4
+ } = require('./util.js')
5
+
6
+ module.exports = {
7
+
8
+ // ------------------------------------------------------------------------
9
+ // guard
10
+ // ------------------------------------------------------------------------
11
+
12
+ generator: $ => seq(
13
+ field('pattern', $._pat),
14
+ field('arrow', $._larrow),
15
+ field('expression', $._exp),
16
+ ),
17
+
18
+ _let_binds: $ => layout_sort($, $._cmd_layout_start_let, field('decl', $.decl)),
19
+
20
+ _let: $ => seq('let', optional(field('binds', alias($._let_binds, $.local_binds)))),
21
+
22
+ let: $ => $._let,
23
+
24
+ /**
25
+ * This is a supertype.
26
+ */
27
+ guard: $ => choice(
28
+ // Cannot be named `pattern` because name clash.
29
+ alias($.generator, $.pattern_guard),
30
+ $.let,
31
+ alias($._exp, $.boolean),
32
+ ),
33
+
34
+ guards: $ => sep1(',', field('guard', $.guard)),
35
+
36
+ _guards: $ => seq(
37
+ $._bar,
38
+ $._cmd_texp_start,
39
+ field('guards', $.guards),
40
+ ),
41
+
42
+ // ------------------------------------------------------------------------
43
+ // rules shared by expression, pattern, type
44
+ // ------------------------------------------------------------------------
45
+
46
+ _universal: $ => choice(
47
+ $.splice,
48
+ $.quasiquote,
49
+ $.literal,
50
+ $._unit_cons,
51
+ $._tuple_cons,
52
+ ),
53
+
54
+ }