@willbooster/tree-sitter-haskell 0.0.0-stage → 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.
@@ -0,0 +1,451 @@
1
+ const {
2
+ parens,
3
+ braces,
4
+ brackets,
5
+ prefix_at,
6
+ sep1,
7
+ sep2,
8
+ unboxed_tuple_full,
9
+ unboxed_sum_full,
10
+ forall,
11
+ layout,
12
+ layout_single,
13
+ optional_where,
14
+ } = require('./util.js')
15
+
16
+ module.exports = {
17
+
18
+ // ------------------------------------------------------------------------
19
+ // type parameters
20
+ // ------------------------------------------------------------------------
21
+
22
+ _inferred_tyvar: $ => braces($, $._ktype_param),
23
+
24
+ _type_param_parens: $ => parens($, $._ktype_param),
25
+
26
+ _type_param_wildcard: _ => '_',
27
+
28
+ _type_param_annotated: $ => prec('annotated', seq($.type_param, $._kind_annotation)),
29
+
30
+ _type_param_invisible: $ => prefix_at($, field('bind', $.type_param)),
31
+
32
+ /**
33
+ * This is a supertype.
34
+ */
35
+ type_param: $ => choice(
36
+ alias($._type_param_wildcard, $.wildcard),
37
+ alias($._type_param_invisible, $.invisible),
38
+ alias($._type_param_parens, $.parens),
39
+ field('bind', $.variable),
40
+ ),
41
+
42
+ _ktype_param: $ => choice(
43
+ $.type_param,
44
+ alias($._type_param_annotated, $.annotated),
45
+ ),
46
+
47
+ type_params: $ => repeat1(prec('patterns', $.type_param)),
48
+
49
+ quantified_variables: $ => repeat1(choice($.type_param, alias($._inferred_tyvar, $.inferred))),
50
+
51
+ // ------------------------------------------------------------------------
52
+ // tuples and parens
53
+ // ------------------------------------------------------------------------
54
+
55
+ _type_parens: $ => parens($, field('type', $._ktype)),
56
+
57
+ _type_tuple_elems: $ => sep2(',', field('element', $._ktype)),
58
+
59
+ /**
60
+ * Tuple types must either be saturated or empty, sections aren't legal.
61
+ * We could be lenient here, but it seems useful to have a different node name for the prefix variant.
62
+ */
63
+ _type_tuple: $ => parens($, $._type_tuple_elems),
64
+
65
+ _type_unboxed_tuple: $ => unboxed_tuple_full($, $._ktype),
66
+
67
+ _type_unboxed_sum: $ => unboxed_sum_full($, $._ktype),
68
+
69
+ _type_list: $ => brackets($, sep1(',', field('element', $._ktype))),
70
+
71
+ // ------------------------------------------------------------------------
72
+ // names etc
73
+ // ------------------------------------------------------------------------
74
+
75
+ _type_promoted: $ => seq(
76
+ '\'',
77
+ choice(
78
+ alias($._plist, $.empty_list),
79
+ alias($._type_tuple, $.tuple),
80
+ alias($._type_list, $.list),
81
+ $.prefix_tuple,
82
+ $.unit,
83
+ ),
84
+ ),
85
+
86
+ _type_name: $ => choice(
87
+ $.variable,
88
+ $._promoted_tycons,
89
+ prec('type-name', $._tycons),
90
+ ),
91
+
92
+ _type_star: _ => choice('*', '★'),
93
+
94
+ _type_wildcard: _ => '_',
95
+
96
+ // ------------------------------------------------------------------------
97
+ // application
98
+ // ------------------------------------------------------------------------
99
+
100
+ _at_type: $ => prefix_at($, field('type', $.type)),
101
+
102
+ _type_apply_arg: $ => choice($.type, alias($._at_type, $.kind_application)),
103
+
104
+ /**
105
+ * Type application, as in `Either e (Int, Text)` or `TypeRep @Int`.
106
+ */
107
+ _type_apply: $ => prec.left('apply', seq(
108
+ field('constructor', $.type),
109
+ field('argument', $._type_apply_arg),
110
+ )),
111
+
112
+ // ------------------------------------------------------------------------
113
+ // infix
114
+ // ------------------------------------------------------------------------
115
+
116
+ _type_infix: $ => prec.right('infix', seq(
117
+ field('left_operand', $.type),
118
+ field('operator', $._tyops),
119
+ field('right_operand', $.type),
120
+ )),
121
+
122
+ // ------------------------------------------------------------------------
123
+ // unquantified type
124
+ // ------------------------------------------------------------------------
125
+
126
+ /**
127
+ * This is a supertype.
128
+ */
129
+ type: $ => choice(
130
+ $._type_name,
131
+ alias($._type_star, $.star),
132
+ alias($._type_wildcard, $.wildcard),
133
+ alias($._type_parens, $.parens),
134
+ alias($._type_promoted, $.promoted),
135
+ alias($._type_list, $.list),
136
+ alias($._plist, $.prefix_list),
137
+ alias($._type_unboxed_tuple, $.unboxed_tuple),
138
+ alias($._type_unboxed_sum, $.unboxed_sum),
139
+ alias($._type_tuple, $.tuple),
140
+ alias($._type_infix, $.infix),
141
+ alias($._type_apply, $.apply),
142
+ $._universal,
143
+ ),
144
+
145
+ // ------------------------------------------------------------------------
146
+ // forall
147
+ // ------------------------------------------------------------------------
148
+
149
+ _forall_keyword: _ => choice('forall', '∀'),
150
+
151
+ _forall_body: $ => seq(
152
+ field('quantifier', $._forall_keyword),
153
+ optional(field('variables', $.quantified_variables)),
154
+ ),
155
+
156
+ forall: $ => prec('qtype-single', seq(
157
+ $._forall_body,
158
+ '.',
159
+ )),
160
+
161
+ forall_required: $ => prec('qtype-single', seq(
162
+ $._forall_body,
163
+ $._arrow,
164
+ )),
165
+
166
+ _forall: $ => choice(
167
+ $.forall,
168
+ $.forall_required,
169
+ ),
170
+
171
+ _qtype_forall: $ => prec.right('qtype-curried', seq(
172
+ $._forall_body,
173
+ '.',
174
+ field('type', $.quantified_type),
175
+ )),
176
+
177
+ _qtype_forall_required: $ => prec.right('qtype-curried', seq(
178
+ $._forall_body,
179
+ $._arrow,
180
+ field('type', $.quantified_type),
181
+ )),
182
+
183
+ // ------------------------------------------------------------------------
184
+ // function
185
+ // ------------------------------------------------------------------------
186
+
187
+ _fun_arrow: $ => seq(
188
+ optional($._phantom_arrow),
189
+ field('arrow', $._arrow),
190
+ ),
191
+
192
+ modifier: $ => prec('prefix', seq($._prefix_percent, $.type)),
193
+
194
+ _linear_fun_arrow: $ => choice(
195
+ seq(
196
+ field('multiplicity', $.modifier),
197
+ $._fun_arrow,
198
+ ),
199
+ seq(
200
+ optional($._phantom_arrow),
201
+ field('arrow', $._linear_arrow),
202
+ ),
203
+ ),
204
+
205
+ /**
206
+ * These also allow tight infix because unpack pragmas can precede them without space.
207
+ * Technically pragmas aren't considered for tight infix, but it's simpler to do it this way than to track that in the
208
+ * scanner.
209
+ */
210
+ strict_field: $ => prec('prefix', seq($._any_prefix_bang, field('type', $.type))),
211
+ lazy_field: $ => prec('prefix', seq($._any_prefix_tilde, field('type', $.type))),
212
+
213
+ _parameter_type: $ => field('parameter', choice($.strict_field, $.lazy_field, $.quantified_type)),
214
+
215
+ /**
216
+ * We allow strict and lazy field types in function types so that GADTs don't need a separate rule tree.
217
+ */
218
+ _qtype_function: $ => prec.right(seq(
219
+ $._parameter_type,
220
+ $._fun_arrow,
221
+ field('result', $.quantified_type),
222
+ )),
223
+
224
+ _qtype_linear_function: $ => prec.right(seq(
225
+ $._parameter_type,
226
+ $._linear_fun_arrow,
227
+ field('result', $.quantified_type),
228
+ )),
229
+
230
+ // ------------------------------------------------------------------------
231
+ // context
232
+ // ------------------------------------------------------------------------
233
+
234
+ _qtype_context: $ => prec.right('qtype-curried', seq(
235
+ $._context_inline,
236
+ field('type', $.quantified_type),
237
+ )),
238
+
239
+ // ------------------------------------------------------------------------
240
+ // top level
241
+ // ------------------------------------------------------------------------
242
+
243
+ /**
244
+ * This is a supertype.
245
+ */
246
+ quantified_type: $ => choice(
247
+ alias($._qtype_function, $.function),
248
+ alias($._qtype_linear_function, $.linear_function),
249
+ alias($._qtype_forall, $.forall),
250
+ alias($._qtype_forall_required, $.forall_required),
251
+ alias($._qtype_context, $.context),
252
+ $.implicit_parameter,
253
+ prec.right($.type),
254
+ ),
255
+
256
+ _type_annotation: $ => seq(
257
+ $._colon2,
258
+ field('type', $.quantified_type),
259
+ ),
260
+
261
+ _kind_annotation: $ => seq(
262
+ $._colon2,
263
+ field('kind', $.quantified_type),
264
+ ),
265
+
266
+ _type_signature: $ => prec.right('annotated', seq(
267
+ field('type', $.quantified_type),
268
+ $._kind_annotation,
269
+ )),
270
+
271
+ _ktype: $ => choice(
272
+ alias($._type_signature, $.signature),
273
+ $.quantified_type,
274
+ ),
275
+
276
+ // ------------------------------------------------------------------------
277
+ // type head
278
+ // ------------------------------------------------------------------------
279
+
280
+ _type_head_name: $ => field('name', choice(
281
+ $._tycon,
282
+ $.unit,
283
+ alias($._plist, $.prefix_list),
284
+ )),
285
+
286
+ _type_head_parens: $ => parens(
287
+ $,
288
+ choice(
289
+ $._type_head,
290
+ $._type_head_params,
291
+ ),
292
+ ),
293
+
294
+ _type_head_params: $ => choice(
295
+ $._type_head_name,
296
+ alias($._type_head_parens, $.parens),
297
+ ),
298
+
299
+ _type_head_infix: $ => prec('infix', seq(
300
+ field('left_operand', $.type_param),
301
+ field('operator', $._tyconops),
302
+ field('right_operand', $.type_param),
303
+ )),
304
+
305
+ /**
306
+ * A type head introduces the name and parameters in the declaration of a data type/family, type synonym/family, or
307
+ * class.
308
+ *
309
+ * It can be in prefix or infix form:
310
+ *
311
+ * > A a b
312
+ * > a +++ b
313
+ *
314
+ * Parameters can be visible or invisible, the latter marked by a prefix `@`.
315
+ * They can be plain or parenthesized variable names, the latter with an optional kind signature.
316
+ * They can be wildcards.
317
+ *
318
+ * Examples: `a`, `@a`, `(a :: Type)`, `@(_ :: Type -> Type)`
319
+ *
320
+ * The rules are slightly relaxed compared to GHC.
321
+ */
322
+ _type_head: $ => choice(
323
+ seq($._type_head_params, optional(field('patterns', $.type_params))),
324
+ alias($._type_head_infix, $.infix),
325
+ ),
326
+
327
+ // ------------------------------------------------------------------------
328
+ // type instance head
329
+ // ------------------------------------------------------------------------
330
+
331
+ _type_instance_head_parens: $ => parens(
332
+ $,
333
+ choice(
334
+ $._type_instance_head,
335
+ $._type_instance_head_params,
336
+ ),
337
+ optional($._kind_annotation),
338
+ ),
339
+
340
+ _type_instance_head_params: $ => choice(
341
+ field('name', $._tycons),
342
+ alias($._type_instance_head_parens, $.parens),
343
+ ),
344
+
345
+ type_patterns: $ => repeat1(prec('patterns', $._type_apply_arg)),
346
+
347
+ /**
348
+ * The equivalent of a type head, for type instances, which can contain full type patterns rather than just variable
349
+ * binders.
350
+ */
351
+ _type_instance_head: $ => choice(
352
+ seq($._type_instance_head_params, optional(field('patterns', $.type_patterns))),
353
+ seq($._cond_infix, alias($._type_infix, $.infix)),
354
+ ),
355
+
356
+ // ------------------------------------------------------------------------
357
+ // type decl
358
+ // ------------------------------------------------------------------------
359
+
360
+ type_synomym: $ => seq(
361
+ 'type',
362
+ $._type_head,
363
+ '=',
364
+ field('type', $._ktype),
365
+ ),
366
+
367
+ kind_signature: $ => seq(
368
+ 'type',
369
+ $._type_head,
370
+ $._kind_annotation,
371
+ ),
372
+
373
+ // ------------------------------------------------------------------------
374
+ // type instance
375
+ // ------------------------------------------------------------------------
376
+
377
+ _type_instance_common: $ => seq(
378
+ $._type_instance_head,
379
+ '=',
380
+ $.quantified_type,
381
+ ),
382
+
383
+ _type_instance: $ => seq(
384
+ forall($),
385
+ $._type_instance_common,
386
+ ),
387
+
388
+ type_instance: $ => seq(
389
+ 'type',
390
+ 'instance',
391
+ $._type_instance,
392
+ ),
393
+
394
+ // ------------------------------------------------------------------------
395
+ // type family
396
+ // ------------------------------------------------------------------------
397
+
398
+ type_family_result: $ => seq('=', field('result', $.quantified_type)),
399
+
400
+ type_family_injectivity: $ => seq(
401
+ $._bar,
402
+ field('result', $.variable),
403
+ $._arrow,
404
+ field('determined', repeat1($.variable)),
405
+ ),
406
+
407
+ _tyfam_inj: $ => seq(
408
+ $.type_family_result,
409
+ optional($.type_family_injectivity),
410
+ ),
411
+
412
+ _tyfam: $ => seq(
413
+ $._type_head,
414
+ optional(choice($._kind_annotation, $._tyfam_inj)),
415
+ ),
416
+
417
+ _tyfam_equations: $ => layout($, field('equation', alias($._type_instance, $.equation))),
418
+
419
+ /**
420
+ * This syntax is valid in `.hs-boot` files.
421
+ */
422
+ abstract_family: $ => layout_single($, '..'),
423
+
424
+ type_family: $ => seq(
425
+ 'type',
426
+ 'family',
427
+ $._tyfam,
428
+ optional_where($, field('closed_family', choice(
429
+ alias($._tyfam_equations, $.equations),
430
+ $.abstract_family,
431
+ ))),
432
+ ),
433
+
434
+ // ------------------------------------------------------------------------
435
+ // role
436
+ // ------------------------------------------------------------------------
437
+
438
+ type_role: _ => choice(
439
+ 'representational',
440
+ 'nominal',
441
+ 'phantom',
442
+ '_',
443
+ ),
444
+
445
+ role_annotation: $ => seq(
446
+ 'type',
447
+ 'role',
448
+ field('type', $._tycons),
449
+ repeat1(field('role', $.type_role)),
450
+ )
451
+ }
@@ -0,0 +1,162 @@
1
+ // ------------------------------------------------------------------------
2
+ // structure
3
+ // ------------------------------------------------------------------------
4
+
5
+ const sep1 = (s, rule) => seq(rule, repeat(seq(s, rule)))
6
+
7
+ const sep2 = (s, rule) => seq(rule, repeat1(seq(s, rule)))
8
+
9
+ const sep = (s, rule) => optional(sep1(s, rule))
10
+
11
+ // ------------------------------------------------------------------------
12
+ // syntax
13
+ // ------------------------------------------------------------------------
14
+
15
+ const parens = ($, ...rule) => seq($._paren_open, ...rule, $._paren_close)
16
+
17
+ const braces = ($, ...rule) => seq('{', $._cmd_brace_open, ...rule, '}', $._cmd_brace_close)
18
+
19
+ const brackets = ($, ...rule) => seq($._bracket_open, ...rule, $._bracket_close)
20
+
21
+ const ticked = (...rule) => seq('`', ...rule, '`')
22
+
23
+ const promoted = (...rule) => seq('\'', ...rule)
24
+
25
+ const prefix_at = ($, ...rule) => prec('prefix', seq($._prefix_at, ...rule))
26
+
27
+ const semi = $ => choice(repeat1(';'), $._cond_layout_semicolon)
28
+
29
+ const semi_opt = $ => optional(semi($))
30
+
31
+ const semis = ($, rule) => sep1(semi($), rule)
32
+
33
+ // ------------------------------------------------------------------------
34
+ // layout
35
+ // ------------------------------------------------------------------------
36
+
37
+ /**
38
+ * More general variant of `layout_sort`.
39
+ */
40
+ const layout_sort_single = ($, start, rule) => seq(
41
+ choice(start, alias($._cmd_layout_start_explicit, '{')),
42
+ rule,
43
+ $._layout_end,
44
+ )
45
+
46
+ /**
47
+ * Wrap a repeated rule in a layout.
48
+ * This is used for `where`, `let`, `of`, `if` and `do`, and the toplevel module.
49
+ * The `start` rule must be one of the externals starting with `_cmd_layout_<type>`, which instruct the scanner to push
50
+ * a layout context with the current column as its indentation.
51
+ * When a `_cond_layout_end` or `_cond_layout_semicolon` is encountered by the scanner, the recorded indent is compared
52
+ * to the current one to make a decision.
53
+ */
54
+ const layout_sort = ($, start, rule) => seq(
55
+ choice(start, alias($._cmd_layout_start_explicit, '{')),
56
+ optional(seq(
57
+ semi_opt($),
58
+ semis($, rule),
59
+ semi_opt($),
60
+ )),
61
+ $._layout_end,
62
+ )
63
+
64
+ /**
65
+ * Same as `layout`, but using `layout_sort_single`.
66
+ * This is necessary for braces without repeating layout elements.
67
+ * Usually it is enough to just use `braces` for this (e.g. records), but if the rule is in a choice with a full
68
+ * layout, we need to allow the layout start token since the scanner emits that unconditionally based on preceding
69
+ * tokens.
70
+ */
71
+ const layout_single = ($, rule) => layout_sort_single($, $._cmd_layout_start, rule)
72
+
73
+ /**
74
+ * Alias for `layout_sort` using the common layout type for the start token, which corresponds to declarations and GADT
75
+ * constructors.
76
+ */
77
+ const layout = ($, rule) => layout_sort($, $._cmd_layout_start, rule)
78
+
79
+ // ------------------------------------------------------------------------
80
+ // unboxed
81
+ // ------------------------------------------------------------------------
82
+
83
+ const unboxed = ($, ...rules) => seq($._unboxed_open, ...rules, $._unboxed_close)
84
+
85
+ /**
86
+ * At least one element is filled, for expressions.
87
+ */
88
+ const unboxed_tuple_nonempty = ($, rule) => unboxed(
89
+ $,
90
+ repeat(','),
91
+ field('element', rule),
92
+ repeat(seq(',', optional(field('element', rule))))
93
+ )
94
+
95
+ /**
96
+ * All elements are filled in, for types and patterns.
97
+ */
98
+ const unboxed_tuple_full = ($, rule) => unboxed($, sep1(',', field('element', rule)))
99
+
100
+ /**
101
+ * Exactly one element is filled in, used by expressions, patterns and the special data constructors.
102
+ */
103
+ const unboxed_sum_single = ($, rule) => unboxed(
104
+ $,
105
+ choice(
106
+ seq(repeat1($._unboxed_bar), field('element', rule)),
107
+ seq(field('element', rule), $._unboxed_bar)
108
+ ),
109
+ repeat($._unboxed_bar),
110
+ )
111
+
112
+ /**
113
+ * All elements are filled in, for types.
114
+ */
115
+ const unboxed_sum_full = ($, rule) => unboxed($, sep2($._unboxed_bar, field('element', rule)))
116
+
117
+ // ------------------------------------------------------------------------
118
+ // where
119
+ // ------------------------------------------------------------------------
120
+
121
+ const optional_where = ($, rule) => optional(seq($._where, optional(rule)))
122
+
123
+ // ------------------------------------------------------------------------
124
+ // misc
125
+ // ------------------------------------------------------------------------
126
+
127
+ const qualified = ($, id) => prec('qualified-id', seq(
128
+ field('module', alias($._qualifying_module, $.module)),
129
+ field('id', id),
130
+ ))
131
+
132
+ const context = $ => optional(field('context', $.context))
133
+
134
+ const forall = $ => optional(field('forall', $._forall))
135
+
136
+ module.exports = {
137
+ sep1,
138
+ sep2,
139
+ sep,
140
+ parens,
141
+ braces,
142
+ brackets,
143
+ ticked,
144
+ promoted,
145
+ prefix_at,
146
+ semi,
147
+ semi_opt,
148
+ semis,
149
+ layout_sort_single,
150
+ layout_sort,
151
+ layout_single,
152
+ layout,
153
+ unboxed,
154
+ unboxed_tuple_nonempty,
155
+ unboxed_tuple_full,
156
+ unboxed_sum_single,
157
+ unboxed_sum_full,
158
+ optional_where,
159
+ qualified,
160
+ context,
161
+ forall,
162
+ }
package/grammar.js ADDED
@@ -0,0 +1,102 @@
1
+ const
2
+ class_ = require('./grammar/class.js'),
3
+ conflicts = require('./grammar/conflicts.js'),
4
+ context = require('./grammar/context.js'),
5
+ data = require('./grammar/data.js'),
6
+ decl = require('./grammar/decl.js'),
7
+ exp = require('./grammar/exp.js'),
8
+ externals = require('./grammar/externals.js'),
9
+ general = require('./grammar/general.js'),
10
+ id = require('./grammar/id.js'),
11
+ inline = require('./grammar/inline.js'),
12
+ lexeme = require('./grammar/lexeme.js'),
13
+ literal = require('./grammar/literal.js'),
14
+ module_ = require('./grammar/module.js'),
15
+ operator = require('./grammar/operator.js'),
16
+ pat = require('./grammar/pat.js'),
17
+ patsyn = require('./grammar/patsyn.js'),
18
+ precedences = require('./grammar/precedences.js'),
19
+ th = require('./grammar/th.js'),
20
+ type = require('./grammar/type.js')
21
+
22
+ module.exports = grammar({
23
+ name: 'haskell',
24
+
25
+ rules: {
26
+ haskell: $ => seq(
27
+ optional($.header),
28
+ optional($._body),
29
+ ),
30
+
31
+ ...general,
32
+ ...type,
33
+ ...context,
34
+ ...exp,
35
+ ...pat,
36
+ ...module_,
37
+ ...data,
38
+ ...class_,
39
+ ...decl,
40
+ ...patsyn,
41
+ ...th,
42
+ ...literal,
43
+ ...id,
44
+ ...operator,
45
+ ...lexeme,
46
+
47
+ },
48
+
49
+ ...externals,
50
+ ...precedences,
51
+ ...inline,
52
+ ...conflicts,
53
+
54
+ /**
55
+ * These rules may occur anywhere in the grammar and don't have to be specified in productions.
56
+ */
57
+ extras: $ => [
58
+ /\p{Zs}/,
59
+ // Not upstream's bare `/\n/` here and in grammar/externals.js: see "Differences from upstream" in README.md.
60
+ token(prec(0, /\n/)),
61
+ /\r/,
62
+ $.cpp,
63
+ $.comment,
64
+ $.haddock,
65
+ $.pragma,
66
+ ],
67
+
68
+ /**
69
+ * Rules with leading underscore are generally omitted from the AST, and can therefore not be used in queries.
70
+ * The rules listed in this attribute are omitted from the AST, but their names can be used in queries in place of
71
+ * their children; as well as in combination with them, using the syntax `expression/variable`.
72
+ * This is most useful for choice rules that represent syntactic categories, like expressions, patterns, and types in
73
+ * Haskell.
74
+ *
75
+ * See the readme for a detailed explanation.
76
+ */
77
+ supertypes: $ => [
78
+ $.expression,
79
+ $.pattern,
80
+ $.type,
81
+ $.quantified_type,
82
+ $.constraint,
83
+ $.constraints,
84
+ $.type_param,
85
+ $.declaration,
86
+ $.decl,
87
+ $.class_decl,
88
+ $.instance_decl,
89
+ $.statement,
90
+ $.qualifier,
91
+ $.guard,
92
+ ],
93
+
94
+ /**
95
+ * This rule is used to detect that a reserved keyword is a prefix of an identifier.
96
+ *
97
+ * For example, if the identifier `ifM` occurs in a position where the keyword `if` is valid (so most expressions),
98
+ * the fact that `ifM` matches `variable` prevents tree-sitter from lexing `if` followed by `M` as a `name`.
99
+ */
100
+ word: $ => $.variable,
101
+
102
+ })