@willbooster/tree-sitter-c-sharp 0.0.0-placeholder.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/grammar.js ADDED
@@ -0,0 +1,1895 @@
1
+ /**
2
+ * @file C# grammar for tree-sitter
3
+ * @author Max Brunsfeld <maxbrunsfeld@gmail.com>
4
+ * @author Damien Guard <damieng@gmail.com>
5
+ * @author Amaan Qureshi <amaanq12@gmail.com>
6
+ * @license MIT
7
+ */
8
+
9
+ /// <reference types="tree-sitter-cli/dsl" />
10
+ // @ts-check
11
+
12
+ const PREC = {
13
+ GENERIC: 19,
14
+ DOT: 18,
15
+ INVOCATION: 18,
16
+ POSTFIX: 18,
17
+ PREFIX: 17,
18
+ UNARY: 17,
19
+ CAST: 17,
20
+ RANGE: 16,
21
+ SWITCH: 15,
22
+ WITH: 14,
23
+ MULT: 13,
24
+ ADD: 12,
25
+ SHIFT: 11,
26
+ REL: 10,
27
+ EQUAL: 9,
28
+ AND: 8,
29
+ XOR: 7,
30
+ OR: 6,
31
+ LOGICAL_AND: 5,
32
+ LOGICAL_OR: 4,
33
+ COALESCING: 3,
34
+ CONDITIONAL: 2,
35
+ ASSIGN: 1,
36
+ SELECT: 0,
37
+ };
38
+
39
+ const decimalDigitSequence = /([0-9][0-9_]*[0-9]|[0-9])/;
40
+
41
+ const stringEncoding = /(u|U)8/;
42
+
43
+ // oxlint-disable-next-line unicorn/prefer-module -- This package is CommonJS, so tree-sitter loads grammar.js as CommonJS.
44
+ module.exports = grammar({
45
+ name: 'c_sharp',
46
+
47
+ conflicts: ($) => [
48
+ [$._simple_name, $.generic_name],
49
+ [$._simple_name, $.type_parameter],
50
+ [$._simple_name, $.subpattern],
51
+
52
+ [$.tuple_element, $.type_pattern],
53
+ [$.tuple_element, $.using_variable_declarator],
54
+ [$.tuple_element, $.declaration_expression],
55
+
56
+ [$.tuple_pattern, $.parameter],
57
+ [$.tuple_pattern, $._simple_name],
58
+
59
+ [$.lvalue_expression, $._name],
60
+ [$.parameter, $.lvalue_expression],
61
+ // C# 14 null-conditional assignment: `obj?.x = v` requires
62
+ // `conditional_access_expression` to appear in both lvalue and
63
+ // non-lvalue contexts. Tree-sitter needs GLR for the decision.
64
+ [$.lvalue_expression, $.non_lvalue_expression],
65
+
66
+ [$.type, $.attribute],
67
+ [$.type, $.nullable_type],
68
+ [$.type, $.nullable_type, $.array_creation_expression],
69
+ [$.type, $._array_base_type],
70
+ [$.type, $._array_base_type, $.array_creation_expression],
71
+ [$.type, $.array_creation_expression],
72
+ [$.type, $._pointer_base_type],
73
+
74
+ [$.qualified_name, $.member_access_expression],
75
+ [$.qualified_name, $.explicit_interface_specifier],
76
+
77
+ [$._array_base_type, $.stackalloc_expression],
78
+
79
+ [$.constant_pattern, $.non_lvalue_expression],
80
+ [$.constant_pattern, $._expression_statement_expression],
81
+ [$.constant_pattern, $.lvalue_expression],
82
+ [$.constant_pattern, $._name],
83
+ [$.constant_pattern, $.lvalue_expression, $._name],
84
+
85
+ [$.type, $._name_invocation_pattern, $.recursive_pattern],
86
+ [$.attribute, $.type, $._name_invocation_pattern, $.recursive_pattern],
87
+
88
+ [$.parenthesized_pattern, $._parenthesized_pattern_with_designation],
89
+
90
+ [$.expression_element, $.argument],
91
+ [$.spread_element, $.range_expression],
92
+ [$.collection_expression, $.list_pattern],
93
+
94
+ [$._reserved_identifier, $.modifier],
95
+ [$._reserved_identifier, $.scoped_type],
96
+ [$._reserved_identifier, $.implicit_type],
97
+ [$._reserved_identifier, $.from_clause],
98
+ [$._reserved_identifier, $.implicit_type, $.var_pattern],
99
+ [$._reserved_identifier, $.type_parameter_constraint],
100
+ [$._reserved_identifier, $.parameter, $.scoped_type],
101
+ [$._reserved_identifier, $.parameter],
102
+ [$._simple_name, $.parameter],
103
+ [$.tuple_element, $.parameter, $.declaration_expression],
104
+ [$.parameter, $.tuple_element],
105
+
106
+ [$.event_declaration, $.variable_declarator],
107
+
108
+ [$.base_list],
109
+ [$.using_directive, $.modifier],
110
+ [$.using_directive],
111
+
112
+ [$._constructor_declaration_initializer, $._simple_name],
113
+
114
+ // For C# 14 extension declarations: `extension(scoped X x)` —
115
+ // `scoped` can be a parameter modifier, a scoped_type, or a
116
+ // reserved identifier (when there's no further type). Keep all
117
+ // three alive until later tokens disambiguate.
118
+ [$.receiver_parameter, $.scoped_type, $._reserved_identifier],
119
+ ],
120
+
121
+ externals: ($) => [
122
+ $._optional_semi,
123
+ $.interpolation_regular_start,
124
+ $.interpolation_verbatim_start,
125
+ $.interpolation_raw_start,
126
+ $.interpolation_start_quote,
127
+ $.interpolation_end_quote,
128
+ $.interpolation_open_brace,
129
+ $.interpolation_close_brace,
130
+ $.interpolation_string_content,
131
+ $.raw_string_start,
132
+ $.raw_string_end,
133
+ $.raw_string_content,
134
+ // C# 14: emitted by the scanner at '(' when forward-scanning shows a
135
+ // simple-lambda parameter list (at least one element has a parameter
136
+ // modifier) closed by ')=>'.
137
+ $._lambda_paren_open,
138
+ ],
139
+
140
+ extras: ($) => [
141
+ /[\s\u00A0\uFEFF\u3000]+/,
142
+ $.comment,
143
+ $.preproc_region,
144
+ $.preproc_endregion,
145
+ $.preproc_line,
146
+ $.preproc_pragma,
147
+ $.preproc_nullable,
148
+ $.preproc_error,
149
+ $.preproc_warning,
150
+ $.preproc_define,
151
+ $.preproc_undef,
152
+ ],
153
+
154
+ inline: ($) => [
155
+ $._namespace_member_declaration,
156
+ $._object_creation_type,
157
+ $._nullable_base_type,
158
+ $._parameter_type_with_modifiers,
159
+ $._top_level_item_no_statement,
160
+ ],
161
+
162
+ precedences: ($) => [
163
+ [$._anonymous_object_member_declarator, $._simple_name],
164
+ [$.block, $.initializer_expression],
165
+ ],
166
+
167
+ supertypes: ($) => [
168
+ $.declaration,
169
+ $.expression,
170
+ $.non_lvalue_expression,
171
+ $.lvalue_expression,
172
+ $.literal,
173
+ $.statement,
174
+ $.type,
175
+ $.type_declaration,
176
+ $.pattern,
177
+ ],
178
+
179
+ word: ($) => $._identifier_token,
180
+
181
+ rules: {
182
+ compilation_unit: ($) => seq(optional($.shebang_directive), repeat($._top_level_item)),
183
+
184
+ _top_level_item: ($) => prec(2, choice($._top_level_item_no_statement, $.global_statement)),
185
+
186
+ _top_level_item_no_statement: ($) =>
187
+ choice(
188
+ $.extern_alias_directive,
189
+ $.using_directive,
190
+ $.global_attribute,
191
+ alias($.preproc_if_in_top_level, $.preproc_if),
192
+ $._namespace_member_declaration,
193
+ $.file_scoped_namespace_declaration
194
+ ),
195
+
196
+ global_statement: ($) => prec(1, $.statement),
197
+
198
+ extern_alias_directive: ($) => seq('extern', 'alias', field('name', $.identifier), ';'),
199
+
200
+ using_directive: ($) =>
201
+ seq(
202
+ optional('global'),
203
+ 'using',
204
+ choice(
205
+ seq(optional('unsafe'), field('name', $.identifier), '=', $.type),
206
+ seq(repeat(choice('static', 'unsafe')), $._name)
207
+ ),
208
+ ';'
209
+ ),
210
+
211
+ global_attribute: ($) => seq('[', choice('assembly', 'module'), ':', commaSep1($.attribute), optional(','), ']'),
212
+
213
+ attribute: ($) => seq(field('name', $._name), optional($.attribute_argument_list)),
214
+
215
+ attribute_argument_list: ($) => prec(-1, seq('(', commaSep($.attribute_argument), ')')),
216
+
217
+ attribute_argument: ($) =>
218
+ prec(-1, seq(optional(prec(1, seq(field('name', $.identifier), choice(':', '=')))), $.expression)),
219
+
220
+ attribute_list: ($) => seq('[', optional($.attribute_target_specifier), commaSep1($.attribute), optional(','), ']'),
221
+
222
+ _attribute_list: ($) => choice($.attribute_list, $.preproc_if_in_attribute_list),
223
+
224
+ // Higher precedence than `_reserved_identifier`: when both interpretations
225
+ // are valid (e.g. `[field :` could be `_reserved_identifier` followed by
226
+ // bogus `:`, or `attribute_target_specifier`), prefer the target-specifier
227
+ // reading. `_reserved_identifier` still wins when no `:` follows, so
228
+ // `[field]` continues to parse as collection_expression with identifier.
229
+ attribute_target_specifier: () =>
230
+ prec(1, seq(choice('field', 'event', 'method', 'param', 'property', 'return', 'type', 'typevar'), ':')),
231
+
232
+ _namespace_member_declaration: ($) => choice($.namespace_declaration, $.type_declaration),
233
+
234
+ namespace_declaration: ($) =>
235
+ seq('namespace', field('name', $._name), field('body', $.declaration_list), $._optional_semi),
236
+
237
+ file_scoped_namespace_declaration: ($) => seq('namespace', field('name', $._name), ';'),
238
+
239
+ type_declaration: ($) =>
240
+ choice(
241
+ $.class_declaration,
242
+ $.struct_declaration,
243
+ $.enum_declaration,
244
+ $.interface_declaration,
245
+ $.delegate_declaration,
246
+ $.record_declaration
247
+ ),
248
+
249
+ class_declaration: ($) => seq($._class_declaration_initializer, $._declaration_list_body),
250
+
251
+ _class_declaration_initializer: ($) =>
252
+ seq(
253
+ repeat($._attribute_list),
254
+ repeat($.modifier),
255
+ 'class',
256
+ field('name', $.identifier),
257
+ repeat(choice($.type_parameter_list, $.parameter_list, $.base_list)),
258
+ repeat($.type_parameter_constraints_clause)
259
+ ),
260
+
261
+ struct_declaration: ($) => seq($._struct_declaration_initializer, $._declaration_list_body),
262
+
263
+ _struct_declaration_initializer: ($) =>
264
+ seq(
265
+ repeat($._attribute_list),
266
+ repeat($.modifier),
267
+ optional('ref'),
268
+ 'struct',
269
+ field('name', $.identifier),
270
+ repeat(choice($.type_parameter_list, $.parameter_list, $.base_list)),
271
+ repeat($.type_parameter_constraints_clause)
272
+ ),
273
+
274
+ enum_declaration: ($) =>
275
+ seq(
276
+ $._enum_declaration_initializer,
277
+ choice(seq(field('body', $.enum_member_declaration_list), $._optional_semi), ';')
278
+ ),
279
+
280
+ _enum_declaration_initializer: ($) =>
281
+ seq(repeat($._attribute_list), repeat($.modifier), 'enum', field('name', $.identifier), optional($.base_list)),
282
+
283
+ enum_member_declaration_list: ($) =>
284
+ seq(
285
+ '{',
286
+ commaSep(choice($.enum_member_declaration, alias($.preproc_if_in_enum_member_declaration, $.preproc_if))),
287
+ optional(','),
288
+ '}'
289
+ ),
290
+
291
+ enum_member_declaration: ($) =>
292
+ seq(repeat($._attribute_list), field('name', $.identifier), optional(seq('=', field('value', $.expression)))),
293
+
294
+ interface_declaration: ($) => seq($._interface_declaration_initializer, $._declaration_list_body),
295
+
296
+ _interface_declaration_initializer: ($) =>
297
+ seq(
298
+ repeat($._attribute_list),
299
+ repeat($.modifier),
300
+ 'interface',
301
+ field('name', $.identifier),
302
+ field('type_parameters', optional($.type_parameter_list)),
303
+ optional($.base_list),
304
+ repeat($.type_parameter_constraints_clause)
305
+ ),
306
+
307
+ delegate_declaration: ($) =>
308
+ seq($._delegate_declaration_initializer, repeat($.type_parameter_constraints_clause), ';'),
309
+
310
+ _delegate_declaration_initializer: ($) =>
311
+ seq(
312
+ repeat($._attribute_list),
313
+ repeat($.modifier),
314
+ 'delegate',
315
+ field('type', $.type),
316
+ field('name', $.identifier),
317
+ field('type_parameters', optional($.type_parameter_list)),
318
+ field('parameters', $.parameter_list)
319
+ ),
320
+
321
+ record_declaration: ($) => seq($._record_declaration_initializer, $._declaration_list_body),
322
+
323
+ _record_declaration_initializer: ($) =>
324
+ seq(
325
+ repeat($._attribute_list),
326
+ repeat($.modifier),
327
+ 'record',
328
+ optional(choice('class', 'struct')),
329
+ field('name', $.identifier),
330
+ repeat(choice($.type_parameter_list, $.parameter_list)),
331
+ optional(alias($.record_base, $.base_list)),
332
+ repeat($.type_parameter_constraints_clause)
333
+ ),
334
+
335
+ record_base: ($) =>
336
+ choice(
337
+ seq(':', commaSep1($._name)),
338
+ seq(':', $.primary_constructor_base_type, optional(seq(',', commaSep1($._name))))
339
+ ),
340
+
341
+ _declaration_list_body: ($) => choice(seq(field('body', $.declaration_list), $._optional_semi), ';'),
342
+
343
+ primary_constructor_base_type: ($) => seq(field('type', $._name), $.argument_list),
344
+
345
+ modifier: () =>
346
+ prec.right(
347
+ choice(
348
+ 'abstract',
349
+ 'async',
350
+ 'const',
351
+ 'extern',
352
+ 'file',
353
+ 'fixed',
354
+ 'internal',
355
+ 'new',
356
+ 'override',
357
+ 'partial',
358
+ 'private',
359
+ 'protected',
360
+ 'public',
361
+ 'readonly',
362
+ 'required',
363
+ // 'ref', // `ref` as a modifier can only be used on struct declarations. Other than that it's a ref type or a ref parameter in a declaration.
364
+ // 'scoped', // `scoped` is either part of a scoped type or a scoped parameter. Both of which are handled outside of `modifier`.
365
+ 'sealed',
366
+ 'static',
367
+ 'unsafe',
368
+ 'virtual',
369
+ 'volatile'
370
+ )
371
+ ),
372
+
373
+ type_parameter_list: ($) => seq('<', commaSep1($.type_parameter), '>'),
374
+
375
+ type_parameter: ($) => seq(repeat($._attribute_list), optional(choice('in', 'out')), field('name', $.identifier)),
376
+
377
+ base_list: ($) => seq(':', commaSep1(seq($.type, optional($.argument_list)))),
378
+
379
+ type_parameter_constraints_clause: ($) => seq('where', $.identifier, ':', commaSep1($.type_parameter_constraint)),
380
+
381
+ type_parameter_constraint: ($) =>
382
+ choice(
383
+ seq('class', optional('?')),
384
+ 'struct',
385
+ 'notnull',
386
+ 'unmanaged',
387
+ $.constructor_constraint,
388
+ field('type', $.type)
389
+ ),
390
+
391
+ constructor_constraint: () => seq('new', '(', ')'),
392
+
393
+ operator_declaration: ($) =>
394
+ seq(
395
+ repeat($._attribute_list),
396
+ repeat($.modifier),
397
+ field('type', $.type),
398
+ optional($.explicit_interface_specifier),
399
+ 'operator',
400
+ optional('checked'),
401
+ field(
402
+ 'operator',
403
+ choice(
404
+ '!',
405
+ '~',
406
+ '++',
407
+ '--',
408
+ 'true',
409
+ 'false',
410
+ '+',
411
+ '-',
412
+ '*',
413
+ '/',
414
+ '%',
415
+ '^',
416
+ '|',
417
+ '&',
418
+ '<<',
419
+ '>>',
420
+ '>>>',
421
+ '==',
422
+ '!=',
423
+ '>',
424
+ '<',
425
+ '>=',
426
+ '<=',
427
+ // C# 14: user-defined compound assignment operators.
428
+ // https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14#user-defined-compound-assignment-operators
429
+ '+=',
430
+ '-=',
431
+ '*=',
432
+ '/=',
433
+ '%=',
434
+ '^=',
435
+ '|=',
436
+ '&=',
437
+ '<<=',
438
+ '>>=',
439
+ '>>>='
440
+ )
441
+ ),
442
+ field('parameters', $.parameter_list),
443
+ $._function_body
444
+ ),
445
+
446
+ conversion_operator_declaration: ($) =>
447
+ seq(
448
+ repeat($._attribute_list),
449
+ repeat($.modifier),
450
+ choice('implicit', 'explicit'),
451
+ repeat1(
452
+ choice(
453
+ // Intentionally structured this way for grammar size
454
+ $.explicit_interface_specifier,
455
+ 'operator',
456
+ 'checked'
457
+ )
458
+ ),
459
+ field('type', $.type),
460
+ field('parameters', $.parameter_list),
461
+ $._function_body
462
+ ),
463
+
464
+ declaration_list: ($) => seq('{', repeat($.declaration), '}'),
465
+
466
+ declaration: ($) =>
467
+ choice(
468
+ $.class_declaration,
469
+ $.struct_declaration,
470
+ $.enum_declaration,
471
+ $.delegate_declaration,
472
+ $.field_declaration,
473
+ $.method_declaration,
474
+ $.event_declaration,
475
+ $.event_field_declaration,
476
+ $.record_declaration,
477
+ $.constructor_declaration,
478
+ $.destructor_declaration,
479
+ $.indexer_declaration,
480
+ $.interface_declaration,
481
+ $.namespace_declaration,
482
+ $.operator_declaration,
483
+ $.conversion_operator_declaration,
484
+ $.property_declaration,
485
+ $.using_directive,
486
+ $.preproc_if,
487
+ $.extension_declaration
488
+ ),
489
+
490
+ // C# 14: extension declarations introduce extension methods, properties,
491
+ // and operators with a shared receiver inside a non-generic static class.
492
+ // https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-14.0/extensions
493
+ //
494
+ // extension_declaration:
495
+ // 'extension' type_parameter_list? '(' receiver_parameter ')'
496
+ // type_parameter_constraints_clause* extension_body
497
+ // extension_body: '{' extension_member_declaration* '}' ';'?
498
+ // extension_member_declaration:
499
+ // method_declaration | property_declaration | operator_declaration
500
+ // receiver_parameter: attributes? parameter_modifiers? type identifier?
501
+ //
502
+ // `extension` is contextual; it is recognized as the start of an
503
+ // extension declaration when followed by `<` or `(` in declaration
504
+ // position. Use prec.dynamic so an identifier named `extension` in
505
+ // other positions still parses.
506
+ extension_declaration: ($) =>
507
+ prec.dynamic(
508
+ 1,
509
+ seq(
510
+ repeat($._attribute_list),
511
+ 'extension',
512
+ optional($.type_parameter_list),
513
+ '(',
514
+ $.receiver_parameter,
515
+ ')',
516
+ repeat($.type_parameter_constraints_clause),
517
+ $.extension_body
518
+ )
519
+ ),
520
+
521
+ receiver_parameter: ($) =>
522
+ seq(repeat($._attribute_list), $._parameter_type_with_modifiers, optional(field('name', $.identifier))),
523
+
524
+ extension_body: ($) => seq('{', repeat($._extension_member_declaration), '}', optional(';')),
525
+
526
+ _extension_member_declaration: ($) => choice($.method_declaration, $.property_declaration, $.operator_declaration),
527
+
528
+ field_declaration: ($) => seq(repeat($._attribute_list), repeat($.modifier), $.variable_declaration, ';'),
529
+
530
+ constructor_declaration: ($) => seq($._constructor_declaration_initializer, $._function_body),
531
+
532
+ _constructor_declaration_initializer: ($) =>
533
+ seq(
534
+ repeat($._attribute_list),
535
+ repeat($.modifier),
536
+ field('name', $.identifier),
537
+ field('parameters', $.parameter_list),
538
+ optional($.constructor_initializer)
539
+ ),
540
+
541
+ destructor_declaration: ($) =>
542
+ seq(
543
+ repeat($._attribute_list),
544
+ optional('extern'),
545
+ '~',
546
+ field('name', $.identifier),
547
+ field('parameters', $.parameter_list),
548
+ $._function_body
549
+ ),
550
+
551
+ method_declaration: ($) =>
552
+ seq(
553
+ repeat($._attribute_list),
554
+ repeat($.modifier),
555
+ field('returns', $.type),
556
+ optional($.explicit_interface_specifier),
557
+ field('name', $.identifier),
558
+ field('type_parameters', optional($.type_parameter_list)),
559
+ field('parameters', $.parameter_list),
560
+ repeat($.type_parameter_constraints_clause),
561
+ $._function_body
562
+ ),
563
+
564
+ event_declaration: ($) =>
565
+ seq(
566
+ repeat($._attribute_list),
567
+ repeat($.modifier),
568
+ 'event',
569
+ field('type', $.type),
570
+ optional($.explicit_interface_specifier),
571
+ field('name', $.identifier),
572
+ choice(field('accessors', $.accessor_list), ';')
573
+ ),
574
+
575
+ event_field_declaration: ($) =>
576
+ prec.dynamic(1, seq(repeat($._attribute_list), repeat($.modifier), 'event', $.variable_declaration, ';')),
577
+
578
+ accessor_list: ($) => seq('{', repeat($.accessor_declaration), '}'),
579
+
580
+ accessor_declaration: ($) =>
581
+ seq(
582
+ repeat($._attribute_list),
583
+ repeat($.modifier),
584
+ field('name', choice('get', 'set', 'add', 'remove', 'init', $.identifier)),
585
+ $._function_body
586
+ ),
587
+
588
+ indexer_declaration: ($) =>
589
+ seq(
590
+ repeat($._attribute_list),
591
+ repeat($.modifier),
592
+ field('type', $.type),
593
+ optional($.explicit_interface_specifier),
594
+ 'this',
595
+ field('parameters', $.bracketed_parameter_list),
596
+ choice(field('accessors', $.accessor_list), seq(field('value', $.arrow_expression_clause), ';'))
597
+ ),
598
+
599
+ bracketed_parameter_list: ($) => seq('[', sep(choice($.parameter, $._parameter_array), ','), ']'),
600
+
601
+ property_declaration: ($) =>
602
+ seq(
603
+ repeat($._attribute_list),
604
+ repeat($.modifier),
605
+ field('type', $.type),
606
+ optional($.explicit_interface_specifier),
607
+ field('name', $.identifier),
608
+ choice(
609
+ seq(field('accessors', $.accessor_list), optional(seq('=', field('value', $.expression), ';'))),
610
+ seq(field('value', $.arrow_expression_clause), ';')
611
+ )
612
+ ),
613
+
614
+ explicit_interface_specifier: ($) => prec(PREC.DOT, seq($._name, '.')),
615
+
616
+ parameter_list: ($) => seq('(', sep(choice($.parameter, $._parameter_array), ','), ')'),
617
+
618
+ _parameter_type_with_modifiers: ($) =>
619
+ seq(
620
+ repeat(prec.left(alias(choice('this', 'scoped', 'ref', 'out', 'in', 'readonly'), $.modifier))),
621
+ field('type', $.type)
622
+ ),
623
+
624
+ parameter: ($) =>
625
+ seq(
626
+ repeat($._attribute_list),
627
+ optional($._parameter_type_with_modifiers),
628
+ field('name', $.identifier),
629
+ optional(seq('=', $.expression))
630
+ ),
631
+
632
+ _parameter_array: ($) =>
633
+ seq(repeat($._attribute_list), 'params', field('type', $.type), field('name', $.identifier)),
634
+
635
+ constructor_initializer: ($) => seq(':', choice('base', 'this'), $.argument_list),
636
+
637
+ argument_list: ($) => seq('(', commaSep($.argument), ')'),
638
+
639
+ tuple_pattern: ($) => seq('(', commaSep1(choice(field('name', $.identifier), $.discard, $.tuple_pattern)), ')'),
640
+
641
+ argument: ($) =>
642
+ prec(
643
+ 1,
644
+ seq(
645
+ optional(seq(field('name', $.identifier), ':')),
646
+ optional(choice('ref', 'out', 'in')),
647
+ choice($.expression, $.declaration_expression)
648
+ )
649
+ ),
650
+
651
+ block: ($) => seq('{', repeat($.statement), '}'),
652
+
653
+ arrow_expression_clause: ($) => seq('=>', $.expression),
654
+
655
+ _function_body: ($) => choice(field('body', $.block), seq(field('body', $.arrow_expression_clause), ';'), ';'),
656
+
657
+ variable_declaration: ($) => seq(field('type', $.type), commaSep1($.variable_declarator)),
658
+
659
+ using_variable_declaration: ($) =>
660
+ seq(field('type', $.type), commaSep1(alias($.using_variable_declarator, $.variable_declarator))),
661
+
662
+ variable_declarator: ($) =>
663
+ seq(
664
+ choice(field('name', $.identifier), $.tuple_pattern),
665
+ optional($.bracketed_argument_list),
666
+ optional(seq('=', $.expression))
667
+ ),
668
+
669
+ using_variable_declarator: ($) => seq(field('name', $.identifier), optional(seq('=', $.expression))),
670
+
671
+ bracketed_argument_list: ($) => seq('[', commaSep1($.argument), optional(','), ']'),
672
+
673
+ qualified_identifier: ($) => sep1($.identifier, '.'),
674
+
675
+ _name: ($) => choice($.alias_qualified_name, $.qualified_name, $._simple_name),
676
+
677
+ alias_qualified_name: ($) => seq(field('alias', $.identifier), '::', field('name', $._simple_name)),
678
+
679
+ _simple_name: ($) => choice($.identifier, $.generic_name),
680
+
681
+ qualified_name: ($) => prec(PREC.DOT, seq(field('qualifier', $._name), '.', field('name', $._simple_name))),
682
+
683
+ generic_name: ($) => seq($.identifier, $.type_argument_list),
684
+
685
+ type_argument_list: ($) => seq('<', choice(repeat(','), commaSep1($.type)), '>'),
686
+
687
+ type: ($) =>
688
+ choice(
689
+ $.implicit_type,
690
+ $.array_type,
691
+ $._name,
692
+ $.nullable_type,
693
+ $.pointer_type,
694
+ $.function_pointer_type,
695
+ $.predefined_type,
696
+ $.tuple_type,
697
+ $.ref_type,
698
+ $.scoped_type
699
+ ),
700
+
701
+ implicit_type: () => prec.dynamic(1, 'var'),
702
+
703
+ array_type: ($) => seq(field('type', $._array_base_type), field('rank', $.array_rank_specifier)),
704
+
705
+ _array_base_type: ($) =>
706
+ choice(
707
+ $.array_type,
708
+ $._name,
709
+ $.nullable_type,
710
+ $.pointer_type,
711
+ $.function_pointer_type,
712
+ $.predefined_type,
713
+ $.tuple_type
714
+ ),
715
+
716
+ array_rank_specifier: ($) => seq('[', commaSep(optional($.expression)), ']'),
717
+
718
+ nullable_type: ($) => seq(field('type', $._nullable_base_type), '?'),
719
+
720
+ _nullable_base_type: ($) => choice($.array_type, $._name, $.predefined_type, $.tuple_type),
721
+
722
+ pointer_type: ($) => seq(field('type', $._pointer_base_type), '*'),
723
+
724
+ _pointer_base_type: ($) =>
725
+ choice($._name, $.nullable_type, $.pointer_type, $.function_pointer_type, $.predefined_type, $.tuple_type),
726
+
727
+ function_pointer_type: ($) =>
728
+ seq(
729
+ 'delegate',
730
+ '*',
731
+ optional($.calling_convention),
732
+ '<',
733
+ repeat(seq($.function_pointer_parameter, ',')),
734
+ field('returns', $.type),
735
+ '>'
736
+ ),
737
+
738
+ calling_convention: ($) =>
739
+ choice(
740
+ 'managed',
741
+ seq(
742
+ 'unmanaged',
743
+ optional(seq('[', commaSep1(choice('Cdecl', 'Stdcall', 'Thiscall', 'Fastcall', $.identifier)), ']'))
744
+ )
745
+ ),
746
+
747
+ function_pointer_parameter: ($) => seq(optional(choice('ref', 'out', 'in')), field('type', $._ref_base_type)),
748
+
749
+ predefined_type: () =>
750
+ token(
751
+ choice(
752
+ 'bool',
753
+ 'byte',
754
+ 'char',
755
+ 'decimal',
756
+ 'double',
757
+ 'float',
758
+ 'int',
759
+ 'long',
760
+ 'object',
761
+ 'sbyte',
762
+ 'short',
763
+ 'string',
764
+ 'uint',
765
+ 'ulong',
766
+ 'ushort',
767
+ 'nint',
768
+ 'nuint',
769
+ 'void'
770
+ )
771
+ ),
772
+
773
+ ref_type: ($) => seq('ref', optional('readonly'), field('type', $.type)),
774
+
775
+ _ref_base_type: ($) =>
776
+ choice(
777
+ $.implicit_type,
778
+ $._name,
779
+ $.nullable_type,
780
+ $.array_type,
781
+ $.pointer_type,
782
+ $.function_pointer_type,
783
+ $.predefined_type,
784
+ $.tuple_type
785
+ ),
786
+
787
+ scoped_type: ($) => seq('scoped', field('type', $._scoped_base_type)),
788
+
789
+ _scoped_base_type: ($) => choice($._name, $.ref_type),
790
+
791
+ tuple_type: ($) => seq('(', commaSep2($.tuple_element), ')'),
792
+
793
+ tuple_element: ($) => seq(field('type', $.type), field('name', optional($.identifier))),
794
+
795
+ statement: ($) =>
796
+ prec(
797
+ 1,
798
+ choice(
799
+ $.block,
800
+ $.break_statement,
801
+ $.checked_statement,
802
+ $.continue_statement,
803
+ $.do_statement,
804
+ $.empty_statement,
805
+ $.expression_statement,
806
+ $.fixed_statement,
807
+ $.for_statement,
808
+ $.return_statement,
809
+ $.lock_statement,
810
+ $.yield_statement,
811
+ $.switch_statement,
812
+ $.throw_statement,
813
+ $.try_statement,
814
+ $.unsafe_statement,
815
+ $.using_statement,
816
+ $.foreach_statement,
817
+ $.goto_statement,
818
+ $.labeled_statement,
819
+ $.if_statement,
820
+ $.while_statement,
821
+ $.local_declaration_statement,
822
+ $.local_function_statement,
823
+ alias($.preproc_if_in_top_level, $.preproc_if)
824
+ )
825
+ ),
826
+
827
+ break_statement: () => seq('break', ';'),
828
+
829
+ checked_statement: ($) => seq(choice('checked', 'unchecked'), $.block),
830
+
831
+ continue_statement: () => seq('continue', ';'),
832
+
833
+ do_statement: ($) =>
834
+ seq('do', field('body', $.statement), 'while', '(', field('condition', $.expression), ')', ';'),
835
+
836
+ empty_statement: () => ';',
837
+
838
+ expression_statement: ($) => seq($._expression_statement_expression, ';'),
839
+
840
+ fixed_statement: ($) => seq('fixed', '(', $.variable_declaration, ')', $.statement),
841
+
842
+ for_statement: ($) => seq('for', $._for_statement_conditions, field('body', $.statement)),
843
+
844
+ _for_statement_conditions: ($) =>
845
+ seq(
846
+ '(',
847
+ field('initializer', optional(choice($.variable_declaration, commaSep1($.expression)))),
848
+ ';',
849
+ field('condition', optional($.expression)),
850
+ ';',
851
+ field('update', optional(commaSep1($.expression))),
852
+ ')'
853
+ ),
854
+
855
+ return_statement: ($) => seq('return', optional($.expression), ';'),
856
+
857
+ lock_statement: ($) => seq('lock', '(', $.expression, ')', $.statement),
858
+
859
+ yield_statement: ($) => seq('yield', choice(seq('return', $.expression), 'break'), ';'),
860
+
861
+ switch_statement: ($) =>
862
+ seq(
863
+ 'switch',
864
+ choice(seq('(', field('value', $.expression), ')'), field('value', $.tuple_expression)),
865
+ field('body', $.switch_body)
866
+ ),
867
+
868
+ switch_body: ($) => seq('{', repeat($.switch_section), '}'),
869
+
870
+ switch_section: ($) =>
871
+ prec.left(
872
+ seq(
873
+ choice(seq('case', choice($.expression, seq($.pattern, optional($.when_clause)))), 'default'),
874
+ ':',
875
+ repeat($.statement)
876
+ )
877
+ ),
878
+
879
+ throw_statement: ($) => seq('throw', optional($.expression), ';'),
880
+
881
+ try_statement: ($) => seq('try', field('body', $.block), repeat($.catch_clause), optional($.finally_clause)),
882
+
883
+ catch_clause: ($) =>
884
+ seq('catch', repeat(choice($.catch_declaration, $.catch_filter_clause)), field('body', $.block)),
885
+
886
+ catch_declaration: ($) => seq('(', field('type', $.type), optional(field('name', $.identifier)), ')'),
887
+
888
+ catch_filter_clause: ($) => seq('when', '(', $.expression, ')'),
889
+
890
+ finally_clause: ($) => seq('finally', $.block),
891
+
892
+ unsafe_statement: ($) => seq('unsafe', $.block),
893
+
894
+ using_statement: ($) =>
895
+ seq(
896
+ optional('await'),
897
+ 'using',
898
+ '(',
899
+ choice(alias($.using_variable_declaration, $.variable_declaration), $.expression),
900
+ ')',
901
+ field('body', $.statement)
902
+ ),
903
+
904
+ foreach_statement: ($) => seq($._foreach_statement_initializer, field('body', $.statement)),
905
+
906
+ _foreach_statement_initializer: ($) =>
907
+ seq(
908
+ optional('await'),
909
+ 'foreach',
910
+ '(',
911
+ choice(
912
+ seq(field('type', $.type), field('left', choice($.identifier, $.tuple_pattern))),
913
+ field('left', $.expression)
914
+ ),
915
+ 'in',
916
+ field('right', $.expression),
917
+ ')'
918
+ ),
919
+
920
+ goto_statement: ($) => seq('goto', optional(choice('case', 'default')), optional($.expression), ';'),
921
+
922
+ labeled_statement: ($) => seq($.identifier, ':', $.statement),
923
+
924
+ if_statement: ($) =>
925
+ prec.right(
926
+ seq(
927
+ 'if',
928
+ '(',
929
+ field('condition', $.expression),
930
+ ')',
931
+ field('consequence', $.statement),
932
+ optional(seq('else', field('alternative', $.statement)))
933
+ )
934
+ ),
935
+
936
+ while_statement: ($) => seq('while', '(', field('condition', $.expression), ')', field('body', $.statement)),
937
+
938
+ local_declaration_statement: ($) =>
939
+ seq(optional('await'), optional('using'), repeat($.modifier), $.variable_declaration, ';'),
940
+
941
+ local_function_statement: ($) =>
942
+ seq($._local_function_declaration, repeat($.type_parameter_constraints_clause), $._function_body),
943
+
944
+ _local_function_declaration: ($) =>
945
+ seq(
946
+ repeat($._attribute_list),
947
+ repeat($.modifier),
948
+ field('type', $.type),
949
+ field('name', $.identifier),
950
+ field('type_parameters', optional($.type_parameter_list)),
951
+ field('parameters', $.parameter_list)
952
+ ),
953
+
954
+ pattern: ($) =>
955
+ choice(
956
+ $.constant_pattern,
957
+ $.declaration_pattern,
958
+ $.discard,
959
+ $.recursive_pattern,
960
+ $.var_pattern,
961
+ $.negated_pattern,
962
+ // This must come before plain parenthesized_pattern to create GLR conflict
963
+ prec.dynamic(1, alias($._parenthesized_pattern_with_designation, $.recursive_pattern)),
964
+ $.parenthesized_pattern,
965
+ $.relational_pattern,
966
+ $.or_pattern,
967
+ $.and_pattern,
968
+ $.list_pattern,
969
+ $.type_pattern
970
+ ),
971
+
972
+ // Uses '(' pattern ')' to create direct conflict with parenthesized_pattern
973
+ _parenthesized_pattern_with_designation: ($) => seq('(', $.pattern, ')', $._variable_designation),
974
+
975
+ constant_pattern: ($) =>
976
+ choice(
977
+ $.binary_expression,
978
+ $.default_expression,
979
+ $.interpolated_string_expression,
980
+ $.parenthesized_expression,
981
+ $.postfix_unary_expression,
982
+ $.prefix_unary_expression,
983
+ $.sizeof_expression,
984
+ $.tuple_expression,
985
+ $.typeof_expression,
986
+ $.member_access_expression,
987
+ alias($._name_invocation_pattern, $.invocation_expression),
988
+ alias($._complex_invocation_expression, $.invocation_expression),
989
+ $.cast_expression,
990
+ $._simple_name,
991
+ $.literal
992
+ ),
993
+
994
+ // Invocation with name - creates conflict with recursive_pattern's Name(positional_pattern_clause)
995
+ _name_invocation_pattern: ($) => seq(field('function', $._name), field('arguments', $.argument_list)),
996
+
997
+ // Invocation where function is not a simple name
998
+ _complex_invocation_expression: ($) =>
999
+ prec(
1000
+ PREC.INVOCATION,
1001
+ seq(
1002
+ field(
1003
+ 'function',
1004
+ choice(
1005
+ $.member_access_expression,
1006
+ $.element_access_expression,
1007
+ $.invocation_expression,
1008
+ $.parenthesized_expression,
1009
+ $.conditional_access_expression,
1010
+ $.cast_expression
1011
+ )
1012
+ ),
1013
+ field('arguments', $.argument_list)
1014
+ )
1015
+ ),
1016
+
1017
+ discard: () => '_',
1018
+
1019
+ parenthesized_pattern: ($) => seq('(', $.pattern, ')'),
1020
+
1021
+ var_pattern: ($) => seq('var', $._variable_designation),
1022
+
1023
+ // No associativity: tree-sitter 0.27 resolves a precedence tie with a right-associative reduce as a shift, which
1024
+ // makes `case int when x:` and `x is A or nameof(y)` read `when` and `(y)` as a variable designation.
1025
+ // A name such as `A.B` in `R(A.B or C)` also parses as a constant pattern. Without the negative dynamic
1026
+ // precedence, the reading depends on the other GLR stack versions alive at that point, so an incremental
1027
+ // reparse can switch it without reporting a changed range.
1028
+ type_pattern: ($) => prec.dynamic(-1, field('type', $.type)),
1029
+
1030
+ list_pattern: ($) =>
1031
+ prec.right(
1032
+ seq(
1033
+ '[',
1034
+ optional(seq(commaSep1(choice($.pattern, $.slice_pattern)), optional(','))),
1035
+ ']',
1036
+ optional($._variable_designation)
1037
+ )
1038
+ ),
1039
+
1040
+ // C# 11 slice pattern: `..` optionally followed by a subpattern that
1041
+ // binds the captured slice. `[a, .. var rest, z]`, `[..]` (bare),
1042
+ // `[.. List<int> rest]` (declaration_pattern), etc.
1043
+ slice_pattern: ($) => prec.right(seq('..', optional($.pattern))),
1044
+
1045
+ recursive_pattern: ($) =>
1046
+ prec.left(
1047
+ choice(
1048
+ // name followed by positional pattern WITH variable designation
1049
+ prec.dynamic(
1050
+ 1,
1051
+ seq(
1052
+ field('type', $._name),
1053
+ $.positional_pattern_clause,
1054
+ optional($.property_pattern_clause),
1055
+ $._variable_designation
1056
+ )
1057
+ ),
1058
+ // name followed by positional pattern WITHOUT variable designation
1059
+ prec.dynamic(
1060
+ -1,
1061
+ seq(field('type', $._name), $.positional_pattern_clause, optional($.property_pattern_clause))
1062
+ ),
1063
+ // positional pattern with variable designation (no type prefix)
1064
+ prec.dynamic(1, seq($.positional_pattern_clause, $._variable_designation)),
1065
+ // positional pattern without variable designation (no type prefix)
1066
+ $.positional_pattern_clause,
1067
+ // other type followed by pattern clauses (type is required here to avoid ambiguity)
1068
+ seq(
1069
+ field('type', $.type),
1070
+ choice(seq($.positional_pattern_clause, optional($.property_pattern_clause)), $.property_pattern_clause),
1071
+ optional($._variable_designation)
1072
+ ),
1073
+ // no type, just pattern clauses (no variable designation to avoid conflict with above)
1074
+ seq(
1075
+ choice(seq($.positional_pattern_clause, $.property_pattern_clause), $.property_pattern_clause),
1076
+ optional($._variable_designation)
1077
+ )
1078
+ )
1079
+ ),
1080
+
1081
+ positional_pattern_clause: ($) => prec(1, seq('(', optional(commaSep($.subpattern)), ')')),
1082
+
1083
+ property_pattern_clause: ($) => prec(1, seq('{', commaSep($.subpattern), optional(','), '}')),
1084
+
1085
+ subpattern: ($) => prec.right(seq(optional(choice(seq($.expression, ':'), seq($.identifier, ':'))), $.pattern)),
1086
+
1087
+ relational_pattern: ($) =>
1088
+ choice(seq('<', $.expression), seq('<=', $.expression), seq('>', $.expression), seq('>=', $.expression)),
1089
+
1090
+ negated_pattern: ($) => seq('not', $.pattern),
1091
+
1092
+ and_pattern: ($) =>
1093
+ prec.left(PREC.AND, seq(field('left', $.pattern), field('operator', 'and'), field('right', $.pattern))),
1094
+
1095
+ or_pattern: ($) =>
1096
+ prec.left(PREC.OR, seq(field('left', $.pattern), field('operator', 'or'), field('right', $.pattern))),
1097
+
1098
+ declaration_pattern: ($) => seq(field('type', $.type), $._variable_designation),
1099
+
1100
+ _variable_designation: ($) =>
1101
+ prec(1, choice($.discard, $.parenthesized_variable_designation, field('name', $.identifier))),
1102
+
1103
+ parenthesized_variable_designation: ($) => seq('(', commaSep($._variable_designation), ')'),
1104
+
1105
+ expression: ($) => choice($.non_lvalue_expression, $.lvalue_expression),
1106
+
1107
+ non_lvalue_expression: ($) =>
1108
+ choice(
1109
+ 'base',
1110
+ $.binary_expression,
1111
+ $.interpolated_string_expression,
1112
+ $.conditional_expression,
1113
+ $.conditional_access_expression,
1114
+ $.literal,
1115
+ $._expression_statement_expression,
1116
+ $.is_expression,
1117
+ $.is_pattern_expression,
1118
+ $.as_expression,
1119
+ $.cast_expression,
1120
+ $.checked_expression,
1121
+ $.collection_expression,
1122
+ $.switch_expression,
1123
+ $.throw_expression,
1124
+ $.default_expression,
1125
+ $.lambda_expression,
1126
+ $.with_expression,
1127
+ $.sizeof_expression,
1128
+ $.typeof_expression,
1129
+ $.makeref_expression,
1130
+ $.ref_expression,
1131
+ // Address-of (see `_address_of_expression` below): aliased to
1132
+ // `prefix_unary_expression` to preserve the public AST shape.
1133
+ // Parallels `_pointer_indirection_expression` (the `*` operator),
1134
+ // which is similarly aliased back into `lvalue_expression`.
1135
+ alias($._address_of_expression, $.prefix_unary_expression),
1136
+ alias($._value_indirection_expression, $.prefix_unary_expression),
1137
+ $.reftype_expression,
1138
+ $.refvalue_expression,
1139
+ $.stackalloc_expression,
1140
+ $.range_expression,
1141
+ $.array_creation_expression,
1142
+ $.anonymous_method_expression,
1143
+ $.anonymous_object_creation_expression,
1144
+ $.implicit_array_creation_expression,
1145
+ $.implicit_object_creation_expression,
1146
+ $.implicit_stackalloc_expression,
1147
+ $.initializer_expression,
1148
+ $.query_expression,
1149
+ alias($.preproc_if_in_expression, $.preproc_if)
1150
+ ),
1151
+
1152
+ lvalue_expression: ($) =>
1153
+ choice(
1154
+ 'this',
1155
+ $.member_access_expression,
1156
+ $.tuple_expression,
1157
+ $._simple_name,
1158
+ $.element_access_expression,
1159
+ alias($.bracketed_argument_list, $.element_binding_expression),
1160
+ alias($._pointer_indirection_expression, $.prefix_unary_expression),
1161
+ alias($._parenthesized_lvalue_expression, $.parenthesized_expression),
1162
+ // C# 14 null-conditional assignment: `obj?.x = v`, `obj?[i] = v`.
1163
+ // https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14#null-conditional-assignment
1164
+ $.conditional_access_expression
1165
+ ),
1166
+
1167
+ // Covers error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
1168
+ _expression_statement_expression: ($) =>
1169
+ choice(
1170
+ $.assignment_expression,
1171
+ $.invocation_expression,
1172
+ $.postfix_unary_expression,
1173
+ $.prefix_unary_expression,
1174
+ $.await_expression,
1175
+ $.object_creation_expression,
1176
+ $.parenthesized_expression
1177
+ ),
1178
+
1179
+ assignment_expression: ($) =>
1180
+ seq(
1181
+ field('left', $.lvalue_expression),
1182
+ field('operator', choice('=', '+=', '-=', '*=', '/=', '%=', '&=', '^=', '|=', '<<=', '>>=', '>>>=', '??=')),
1183
+ field('right', $.expression)
1184
+ ),
1185
+
1186
+ binary_expression: ($) =>
1187
+ choice(
1188
+ ...[
1189
+ ['&&', PREC.LOGICAL_AND],
1190
+ ['||', PREC.LOGICAL_OR],
1191
+ ['>>', PREC.SHIFT],
1192
+ ['>>>', PREC.SHIFT],
1193
+ ['<<', PREC.SHIFT],
1194
+ ['&', PREC.AND],
1195
+ ['^', PREC.XOR],
1196
+ ['|', PREC.OR],
1197
+ ['+', PREC.ADD],
1198
+ ['-', PREC.ADD],
1199
+ ['*', PREC.MULT],
1200
+ ['/', PREC.MULT],
1201
+ ['%', PREC.MULT],
1202
+ ['<', PREC.REL],
1203
+ ['<=', PREC.REL],
1204
+ ['==', PREC.EQUAL],
1205
+ ['!=', PREC.EQUAL],
1206
+ ['>=', PREC.REL],
1207
+ ['>', PREC.REL],
1208
+ ].map(([operator, precedence]) =>
1209
+ prec.left(
1210
+ precedence,
1211
+ seq(
1212
+ field('left', $.expression),
1213
+ // @ts-ignore
1214
+ field('operator', operator),
1215
+ field('right', $.expression)
1216
+ )
1217
+ )
1218
+ ),
1219
+ prec.right(
1220
+ PREC.COALESCING,
1221
+ seq(field('left', $.expression), field('operator', '??'), field('right', $.expression))
1222
+ )
1223
+ ),
1224
+
1225
+ postfix_unary_expression: ($) => prec(PREC.POSTFIX, seq($.expression, choice('++', '--', '!'))),
1226
+
1227
+ prefix_unary_expression: ($) =>
1228
+ prec(
1229
+ PREC.UNARY,
1230
+ seq(
1231
+ // `&` and `*` are intentionally NOT in this choice list:
1232
+ // * `&` → `_address_of_expression` (operand restricted to lvalue
1233
+ // — see comment on that rule for the #413 rationale)
1234
+ // * `*` → `_pointer_indirection_expression` and
1235
+ // `_value_indirection_expression`
1236
+ // They are aliased back to `prefix_unary_expression` so the
1237
+ // public AST is unaffected.
1238
+ choice('++', '--', '+', '-', '!', '~', '^'),
1239
+ $.expression
1240
+ )
1241
+ ),
1242
+
1243
+ // Pointer indirection is split by its operand. Dereferencing an lvalue
1244
+ // (`*p`, `*(p)`, `**pp`) yields an lvalue, so it is surfaced in
1245
+ // `lvalue_expression` and can be assigned to. Dereferencing any other
1246
+ // expression (`*(long*)&v`, `*(p + 1)`) is only read: surfacing it in
1247
+ // `lvalue_expression` too would let `=` follow every expression that can
1248
+ // be its operand, which grows the parser from 8,495 to 13,339 states.
1249
+ //
1250
+ // A parenthesized expression followed by `*` is a multiplication, not a
1251
+ // cast of a dereference (C# spec §12.9.8 Cast expressions: `(a) * b` is
1252
+ // a cast only when `a` cannot be an expression), so a dereference's
1253
+ // penalty outweighs the cast's +1. `*(p) + 1` is likewise the sum of a
1254
+ // dereference of `(p)` (-2), not a dereference of a cast of `+1`
1255
+ // (-4 + 1), so dereferencing a non-lvalue carries the larger penalty.
1256
+ _pointer_indirection_expression: ($) => prec.dynamic(-2, prec.right(PREC.UNARY, seq('*', $.lvalue_expression))),
1257
+
1258
+ _value_indirection_expression: ($) => prec.dynamic(-4, prec.right(PREC.UNARY, seq('*', $.non_lvalue_expression))),
1259
+
1260
+ // Address-of is split out from `prefix_unary_expression` so that
1261
+ // `&` can't act as a fallback when the lexer would otherwise
1262
+ // emit `&&`. Its operand is restricted to an lvalue (same shape
1263
+ // as the spec's `address-of-expression`). This is the fix for
1264
+ // tree-sitter#413: `(a) && (b > 0)` was misparsed as
1265
+ // `cast(a, &(&(b > 0)))` because the cast state accepted `&` as
1266
+ // a unary start and the lexer split `&&` into two `&` tokens.
1267
+ // With this split, `&` is only valid before an lvalue, which
1268
+ // `(b > 0)` is not — so the cast interpretation can no longer
1269
+ // consume the trailing parenthesized expression and `&&` must
1270
+ // be emitted as a single token for the binary path to succeed.
1271
+ _address_of_expression: ($) => prec.right(PREC.UNARY, seq('&', $.lvalue_expression)),
1272
+
1273
+ query_expression: ($) => seq($.from_clause, $._query_body),
1274
+
1275
+ from_clause: ($) => seq('from', optional(field('type', $.type)), field('name', $.identifier), 'in', $.expression),
1276
+
1277
+ _query_body: ($) =>
1278
+ prec.right(sep1(seq(repeat($._query_clause), $._select_or_group_clause), seq('into', $.identifier))),
1279
+
1280
+ _query_clause: ($) => choice($.from_clause, $.join_clause, $.let_clause, $.order_by_clause, $.where_clause),
1281
+
1282
+ join_clause: ($) => seq('join', $._join_header, $._join_body, optional($.join_into_clause)),
1283
+
1284
+ _join_header: ($) => seq(optional(field('type', $.type)), $.identifier, 'in', $.expression),
1285
+
1286
+ _join_body: ($) => seq('on', $.expression, 'equals', $.expression),
1287
+
1288
+ join_into_clause: ($) => seq('into', $.identifier),
1289
+
1290
+ let_clause: ($) => seq('let', $.identifier, '=', $.expression),
1291
+
1292
+ order_by_clause: ($) => seq('orderby', commaSep1($._ordering)),
1293
+
1294
+ _ordering: ($) => seq($.expression, optional(choice('ascending', 'descending'))),
1295
+
1296
+ where_clause: ($) => seq('where', $.expression),
1297
+
1298
+ _select_or_group_clause: ($) => choice($.group_clause, $.select_clause),
1299
+
1300
+ group_clause: ($) => seq('group', $.expression, 'by', $.expression),
1301
+
1302
+ select_clause: ($) => seq('select', $.expression),
1303
+
1304
+ conditional_expression: ($) =>
1305
+ prec.right(
1306
+ PREC.CONDITIONAL,
1307
+ seq(
1308
+ field('condition', $.expression),
1309
+ '?',
1310
+ field('consequence', $.expression),
1311
+ ':',
1312
+ field('alternative', $.expression)
1313
+ )
1314
+ ),
1315
+
1316
+ conditional_access_expression: ($) =>
1317
+ prec.right(
1318
+ PREC.CONDITIONAL,
1319
+ seq(
1320
+ field('condition', $.expression),
1321
+ '?',
1322
+ choice($.member_binding_expression, alias($.bracketed_argument_list, $.element_binding_expression))
1323
+ )
1324
+ ),
1325
+
1326
+ as_expression: ($) =>
1327
+ prec(PREC.REL, seq(field('left', $.expression), field('operator', 'as'), field('right', $.type))),
1328
+
1329
+ is_expression: ($) =>
1330
+ prec(PREC.REL, seq(field('left', $.expression), field('operator', 'is'), field('right', $.type))),
1331
+
1332
+ is_pattern_expression: ($) =>
1333
+ prec(PREC.REL, seq(field('expression', $.expression), 'is', field('pattern', $.pattern))),
1334
+
1335
+ cast_expression: ($) =>
1336
+ prec(
1337
+ PREC.CAST,
1338
+ prec.dynamic(
1339
+ 1,
1340
+ seq(
1341
+ // higher than invocation, lower than binary
1342
+ '(',
1343
+ field('type', $.type),
1344
+ ')',
1345
+ field('value', $.expression)
1346
+ )
1347
+ )
1348
+ ),
1349
+
1350
+ checked_expression: ($) => seq(choice('checked', 'unchecked'), '(', $.expression, ')'),
1351
+
1352
+ invocation_expression: ($) =>
1353
+ prec(PREC.INVOCATION, seq(field('function', $.expression), field('arguments', $.argument_list))),
1354
+
1355
+ switch_expression: ($) => prec(PREC.SWITCH, seq($.expression, 'switch', $._switch_expression_body)),
1356
+ _switch_expression_body: ($) => seq('{', commaSep($.switch_expression_arm), optional(','), '}'),
1357
+
1358
+ switch_expression_arm: ($) => seq($.pattern, optional($.when_clause), '=>', $.expression),
1359
+
1360
+ when_clause: ($) => seq('when', $.expression),
1361
+
1362
+ await_expression: ($) => prec.right(PREC.UNARY, seq('await', $.expression)),
1363
+
1364
+ throw_expression: ($) => seq('throw', $.expression),
1365
+
1366
+ element_access_expression: ($) =>
1367
+ prec(PREC.POSTFIX, seq(field('expression', $.expression), field('subscript', $.bracketed_argument_list))),
1368
+
1369
+ interpolated_string_expression: ($) =>
1370
+ choice(
1371
+ seq(
1372
+ alias($.interpolation_regular_start, $.interpolation_start),
1373
+ alias($.interpolation_start_quote, '"'),
1374
+ repeat($._interpolated_string_content),
1375
+ alias($.interpolation_end_quote, '"')
1376
+ ),
1377
+ seq(
1378
+ alias($.interpolation_verbatim_start, $.interpolation_start),
1379
+ alias($.interpolation_start_quote, '"'),
1380
+ repeat($._interpolated_verbatim_string_content),
1381
+ alias($.interpolation_end_quote, '"')
1382
+ ),
1383
+ seq(
1384
+ alias($.interpolation_raw_start, $.interpolation_start),
1385
+ alias($.interpolation_start_quote, $.interpolation_quote),
1386
+ repeat($._interpolated_raw_string_content),
1387
+ alias($.interpolation_end_quote, $.interpolation_quote)
1388
+ )
1389
+ ),
1390
+
1391
+ _interpolated_string_content: ($) =>
1392
+ choice(alias($.interpolation_string_content, $.string_content), $.escape_sequence, $.interpolation),
1393
+
1394
+ _interpolated_verbatim_string_content: ($) =>
1395
+ choice(alias($.interpolation_string_content, $.string_content), $.interpolation),
1396
+
1397
+ _interpolated_raw_string_content: ($) =>
1398
+ choice(alias($.interpolation_string_content, $.string_content), $.interpolation),
1399
+
1400
+ interpolation: ($) =>
1401
+ seq(
1402
+ alias($.interpolation_open_brace, $.interpolation_brace),
1403
+ $.expression,
1404
+ optional($.interpolation_alignment_clause),
1405
+ optional($.interpolation_format_clause),
1406
+ alias($.interpolation_close_brace, $.interpolation_brace)
1407
+ ),
1408
+
1409
+ interpolation_alignment_clause: ($) => seq(',', $.expression),
1410
+
1411
+ interpolation_format_clause: () => seq(':', /[^}"]+/),
1412
+
1413
+ member_access_expression: ($) =>
1414
+ prec(
1415
+ PREC.DOT,
1416
+ seq(
1417
+ field('expression', choice($.expression, $.predefined_type, $._name)),
1418
+ choice('.', '->'),
1419
+ field('name', $._simple_name)
1420
+ )
1421
+ ),
1422
+
1423
+ member_binding_expression: ($) => seq('.', field('name', $._simple_name)),
1424
+
1425
+ object_creation_expression: ($) =>
1426
+ prec.right(
1427
+ seq(
1428
+ 'new',
1429
+ field('type', $.type),
1430
+ field('arguments', optional($.argument_list)),
1431
+ field('initializer', optional($.initializer_expression))
1432
+ )
1433
+ ),
1434
+
1435
+ // inline
1436
+ _object_creation_type: ($) => choice($._name, $.nullable_type, $.predefined_type),
1437
+
1438
+ parenthesized_expression: ($) => seq('(', $.non_lvalue_expression, ')'),
1439
+
1440
+ _parenthesized_lvalue_expression: ($) => seq('(', $.lvalue_expression, ')'),
1441
+
1442
+ lambda_expression: ($) =>
1443
+ prec(-1, seq($._lambda_expression_init, '=>', field('body', choice($.block, $.expression)))),
1444
+
1445
+ _lambda_expression_init: ($) =>
1446
+ prec(
1447
+ -1,
1448
+ seq(
1449
+ repeat($._attribute_list),
1450
+ repeat(prec(-1, alias(choice('static', 'async'), $.modifier))),
1451
+ optional(field('type', $.type)),
1452
+ field('parameters', $._lambda_parameters)
1453
+ )
1454
+ ),
1455
+
1456
+ _lambda_parameters: ($) =>
1457
+ prec(
1458
+ -1,
1459
+ choice(
1460
+ $.parameter_list,
1461
+ alias($.identifier, $.implicit_parameter),
1462
+ // C# 14: `(ref x) => x`, `(out y) => ...`, `(text, out result) => ...`
1463
+ // The opening '(' is recognized via the external _lambda_paren_open
1464
+ // token, which the scanner only emits when it can confirm a closing
1465
+ // ')=>' follows a parameter list containing at least one modifier.
1466
+ $._implicit_parameter_list_with_modifiers
1467
+ )
1468
+ ),
1469
+
1470
+ // C# 14 simple-lambda parameter list with modifiers. Each element is
1471
+ // either a bare identifier or one or more modifiers (scoped/ref/out/in/
1472
+ // readonly) followed by an identifier. The opening token is the
1473
+ // external _lambda_paren_open; the closing ')' is the regular literal.
1474
+ _implicit_parameter_list_with_modifiers: ($) =>
1475
+ seq(
1476
+ $._lambda_paren_open,
1477
+ commaSep1(
1478
+ choice(
1479
+ seq(
1480
+ repeat1(alias(choice('scoped', 'ref', 'out', 'in', 'readonly'), $.modifier)),
1481
+ alias($.identifier, $.implicit_parameter)
1482
+ ),
1483
+ alias($.identifier, $.implicit_parameter)
1484
+ )
1485
+ ),
1486
+ ')'
1487
+ ),
1488
+
1489
+ array_creation_expression: ($) =>
1490
+ prec.dynamic(PREC.UNARY, seq('new', field('type', $.array_type), optional($.initializer_expression))),
1491
+
1492
+ anonymous_method_expression: ($) =>
1493
+ seq(
1494
+ repeat(prec(-1, alias(choice('static', 'async'), $.modifier))),
1495
+ 'delegate',
1496
+ optional(field('parameters', $.parameter_list)),
1497
+ $.block
1498
+ ),
1499
+
1500
+ anonymous_object_creation_expression: ($) =>
1501
+ seq('new', '{', commaSep($._anonymous_object_member_declarator), optional(','), '}'),
1502
+
1503
+ _anonymous_object_member_declarator: ($) => choice(seq($.identifier, '=', $.expression), $.expression),
1504
+
1505
+ implicit_array_creation_expression: ($) => seq('new', '[', repeat(','), ']', $.initializer_expression),
1506
+
1507
+ implicit_object_creation_expression: ($) =>
1508
+ prec.right(seq('new', $.argument_list, optional($.initializer_expression))),
1509
+
1510
+ implicit_stackalloc_expression: ($) => seq('stackalloc', '[', ']', $.initializer_expression),
1511
+
1512
+ collection_expression: ($) => seq('[', optional(seq(commaSep1($.collection_element), optional(','))), ']'),
1513
+
1514
+ collection_element: ($) => choice($.expression_element, $.spread_element),
1515
+
1516
+ expression_element: ($) => prec(1, $.expression),
1517
+
1518
+ spread_element: ($) => prec.dynamic(1, prec(PREC.RANGE, seq('..', $.expression))),
1519
+
1520
+ initializer_expression: ($) => seq('{', commaSep($.expression), optional(','), '}'),
1521
+
1522
+ declaration_expression: ($) => prec.dynamic(1, seq(field('type', $.type), field('name', $.identifier))),
1523
+
1524
+ default_expression: ($) => prec.right(seq('default', optional(seq('(', field('type', $.type), ')')))),
1525
+
1526
+ with_expression: ($) => prec.left(PREC.WITH, seq($.expression, 'with', $._with_body)),
1527
+ _with_body: ($) => seq('{', commaSep($.with_initializer), optional(','), '}'),
1528
+
1529
+ with_initializer: ($) => seq($.identifier, '=', $.expression),
1530
+
1531
+ sizeof_expression: ($) => seq('sizeof', '(', field('type', $.type), ')'),
1532
+
1533
+ typeof_expression: ($) => seq('typeof', '(', field('type', $.type), ')'),
1534
+
1535
+ makeref_expression: ($) => seq('__makeref', '(', $.expression, ')'),
1536
+
1537
+ ref_expression: ($) => seq('ref', $.expression),
1538
+
1539
+ reftype_expression: ($) => seq('__reftype', '(', $.expression, ')'),
1540
+
1541
+ refvalue_expression: ($) => seq('__refvalue', '(', field('value', $.expression), ',', field('type', $.type), ')'),
1542
+
1543
+ stackalloc_expression: ($) =>
1544
+ prec.left(seq('stackalloc', field('type', $.array_type), optional($.initializer_expression))),
1545
+
1546
+ range_expression: ($) => prec.right(PREC.RANGE, seq(optional($.expression), '..', optional($.expression))),
1547
+
1548
+ tuple_expression: ($) => seq('(', commaSep2($.argument), ')'),
1549
+
1550
+ literal: ($) =>
1551
+ choice(
1552
+ $.null_literal,
1553
+ $.character_literal,
1554
+ $.integer_literal,
1555
+ $.real_literal,
1556
+ $.boolean_literal,
1557
+ $.string_literal,
1558
+ $.verbatim_string_literal,
1559
+ $.raw_string_literal
1560
+ ),
1561
+
1562
+ null_literal: () => 'null',
1563
+
1564
+ character_literal: ($) => seq("'", choice($.character_literal_content, $.escape_sequence), "'"),
1565
+
1566
+ character_literal_content: () => token.immediate(/[^'\\]/),
1567
+
1568
+ integer_literal: () =>
1569
+ token(
1570
+ seq(
1571
+ choice(
1572
+ decimalDigitSequence, // Decimal
1573
+ /0[xX][0-9a-fA-F_]*[0-9a-fA-F]+/, // Hex
1574
+ /0[bB][01_]*[01]+/ // Binary
1575
+ ),
1576
+ optional(/([uU][lL]?|[lL][uU]?)/)
1577
+ )
1578
+ ),
1579
+
1580
+ real_literal: () => {
1581
+ const suffix = /[fFdDmM]/;
1582
+ const exponent = /[eE][+-]?[0-9][0-9_]*/;
1583
+ return token(
1584
+ choice(
1585
+ seq(decimalDigitSequence, '.', decimalDigitSequence, optional(exponent), optional(suffix)),
1586
+ seq('.', decimalDigitSequence, optional(exponent), optional(suffix)),
1587
+ seq(decimalDigitSequence, exponent, optional(suffix)),
1588
+ seq(decimalDigitSequence, suffix)
1589
+ )
1590
+ );
1591
+ },
1592
+
1593
+ string_literal: ($) =>
1594
+ seq('"', repeat(choice($.string_literal_content, $.escape_sequence)), '"', optional($.string_literal_encoding)),
1595
+
1596
+ string_literal_content: () => token.immediate(prec(1, /[^"\\\n]+/)),
1597
+
1598
+ escape_sequence: () =>
1599
+ token(choice(/\\x[0-9a-fA-F]{1,4}/, /\\u[0-9a-fA-F]{4}/, /\\U[0-9a-fA-F]{8}/, /\\[abefnrtv'"\\?0]/)),
1600
+
1601
+ string_literal_encoding: () => token.immediate(stringEncoding),
1602
+
1603
+ verbatim_string_literal: () => token(seq('@"', repeat(choice(/[^"]/, '""')), '"', optional(stringEncoding))),
1604
+
1605
+ raw_string_literal: ($) =>
1606
+ seq($.raw_string_start, $.raw_string_content, $.raw_string_end, optional(stringEncoding)),
1607
+
1608
+ boolean_literal: () => choice('true', 'false'),
1609
+
1610
+ _identifier_token: () =>
1611
+ token(
1612
+ seq(
1613
+ optional('@'),
1614
+ /(\p{XID_Start}|_|\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8})(\p{XID_Continue}|\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8})*/u
1615
+ )
1616
+ ),
1617
+ identifier: ($) => choice($._identifier_token, $._reserved_identifier),
1618
+
1619
+ _reserved_identifier: () =>
1620
+ choice(
1621
+ 'alias',
1622
+ 'ascending',
1623
+ 'by',
1624
+ 'descending',
1625
+ 'equals',
1626
+ // attribute_target_specifier keywords — contextual only when followed
1627
+ // by `:` in `[target: Attr]` position. Anywhere else they're
1628
+ // identifiers. Without listing them here the LR table preferred the
1629
+ // literal-keyword interpretation, breaking `[type]`, `[field]`, etc.
1630
+ // as collection_expression elements. Excludes `'event'` and `'return'`
1631
+ // from the attribute_target_specifier choice — those are real C#
1632
+ // keywords and must not be accepted as identifiers anywhere else.
1633
+ 'field',
1634
+ 'file',
1635
+ 'from',
1636
+ 'global',
1637
+ 'group',
1638
+ 'into',
1639
+ 'join',
1640
+ 'let',
1641
+ 'method',
1642
+ 'notnull',
1643
+ 'on',
1644
+ 'orderby',
1645
+ 'param',
1646
+ 'property',
1647
+ 'scoped',
1648
+ 'select',
1649
+ 'type',
1650
+ 'typevar',
1651
+ 'unmanaged',
1652
+ 'var',
1653
+ 'when',
1654
+ 'where',
1655
+ 'yield'
1656
+ ),
1657
+
1658
+ // Preprocessor
1659
+
1660
+ ...preprocIf('', ($) => $.declaration),
1661
+ ...preprocIf('_in_top_level', ($) => choice($._top_level_item_no_statement, $.statement)),
1662
+ ...preprocIf('_in_expression', ($) => $.expression, -2, false),
1663
+ ...preprocIf('_in_enum_member_declaration', ($) => $.enum_member_declaration, 0, false),
1664
+ ...preprocIf('_in_attribute_list', ($) => $.attribute_list, -1, false),
1665
+
1666
+ preproc_arg: () => token(prec(-1, /\S([^/\n]|\/[^*]|\\\r?\n)*/)),
1667
+ preproc_directive: () => /#[ \t]*[a-zA-Z0-9]\w*/,
1668
+
1669
+ _preproc_expression: ($) =>
1670
+ choice(
1671
+ $.identifier,
1672
+ $.boolean_literal,
1673
+ $.integer_literal,
1674
+ $.character_literal,
1675
+ alias($.preproc_unary_expression, $.unary_expression),
1676
+ alias($.preproc_binary_expression, $.binary_expression),
1677
+ alias($.preproc_parenthesized_expression, $.parenthesized_expression)
1678
+ ),
1679
+
1680
+ preproc_parenthesized_expression: ($) => seq('(', $._preproc_expression, ')'),
1681
+
1682
+ preproc_unary_expression: ($) =>
1683
+ prec.left(PREC.UNARY, seq(field('operator', '!'), field('argument', $._preproc_expression))),
1684
+
1685
+ preproc_binary_expression: ($) => {
1686
+ const table = [
1687
+ ['||', PREC.LOGICAL_OR],
1688
+ ['&&', PREC.LOGICAL_AND],
1689
+ ['==', PREC.EQUAL],
1690
+ ['!=', PREC.EQUAL],
1691
+ ];
1692
+
1693
+ return choice(
1694
+ ...table.map(([operator, precedence]) => {
1695
+ return prec.left(
1696
+ precedence,
1697
+ seq(
1698
+ field('left', $._preproc_expression),
1699
+ // @ts-ignore
1700
+ field('operator', operator),
1701
+ field('right', $._preproc_expression)
1702
+ )
1703
+ );
1704
+ })
1705
+ );
1706
+ },
1707
+
1708
+ preproc_region: ($) => seq(preprocessor('region'), optional(field('content', $.preproc_arg)), /\n/),
1709
+
1710
+ preproc_endregion: ($) => seq(preprocessor('endregion'), optional(field('content', $.preproc_arg)), /\n/),
1711
+
1712
+ preproc_line: ($) =>
1713
+ seq(
1714
+ preprocessor('line'),
1715
+ choice(
1716
+ 'default',
1717
+ 'hidden',
1718
+ seq($.integer_literal, optional($.string_literal)),
1719
+ seq(
1720
+ '(',
1721
+ $.integer_literal,
1722
+ ',',
1723
+ $.integer_literal,
1724
+ ')',
1725
+ '-',
1726
+ '(',
1727
+ $.integer_literal,
1728
+ ',',
1729
+ $.integer_literal,
1730
+ ')',
1731
+ optional($.integer_literal),
1732
+ $.string_literal
1733
+ )
1734
+ ),
1735
+ /\n/
1736
+ ),
1737
+
1738
+ preproc_pragma: ($) =>
1739
+ seq(
1740
+ preprocessor('pragma'),
1741
+ choice(
1742
+ seq('warning', choice('disable', 'restore'), commaSep(choice($.identifier, $.integer_literal))),
1743
+ seq('checksum', $.string_literal, $.string_literal, $.string_literal)
1744
+ ),
1745
+ /\n/
1746
+ ),
1747
+
1748
+ preproc_nullable: () =>
1749
+ seq(
1750
+ preprocessor('nullable'),
1751
+ choice('enable', 'disable', 'restore'),
1752
+ optional(choice('annotations', 'warnings')),
1753
+ /\n/
1754
+ ),
1755
+
1756
+ preproc_error: ($) => seq(preprocessor('error'), $.preproc_arg, /\n/),
1757
+
1758
+ preproc_warning: ($) => seq(preprocessor('warning'), $.preproc_arg, /\n/),
1759
+
1760
+ preproc_define: ($) => seq(preprocessor('define'), $.preproc_arg, /\n/),
1761
+
1762
+ preproc_undef: ($) => seq(preprocessor('undef'), $.preproc_arg, /\n/),
1763
+
1764
+ shebang_directive: () => token(seq('#!', /.*/)),
1765
+
1766
+ comment: () => token(choice(seq('//', /[^\n\r]*/), seq('/*', /[^*]*\*+([^/*][^*]*\*+)*/, '/'))),
1767
+ },
1768
+ });
1769
+
1770
+ /**
1771
+ * Creates a preprocessor regex rule
1772
+ *
1773
+ * @param {string} command
1774
+ *
1775
+ * @returns {AliasRule}
1776
+ */
1777
+ function preprocessor(command) {
1778
+ return alias(new RegExp('#[ \t]*' + command), '#' + command);
1779
+ }
1780
+
1781
+ /**
1782
+ *
1783
+ * @param {string} suffix
1784
+ *
1785
+ * @param {RuleBuilder<string>} content
1786
+ *
1787
+ * @param {number} precedence
1788
+ *
1789
+ * @param {boolean} rep
1790
+ *
1791
+ * @returns {RuleBuilders<string, string>}
1792
+ */
1793
+ function preprocIf(suffix, content, precedence = 0, rep = true) {
1794
+ /**
1795
+ *
1796
+ * @param {GrammarSymbols<string>} $
1797
+ *
1798
+ * @returns {ChoiceRule}
1799
+ */
1800
+ function alternativeBlock($) {
1801
+ return choice(
1802
+ suffix ? alias($['preproc_else' + suffix], $.preproc_else) : $.preproc_else,
1803
+ suffix ? alias($['preproc_elif' + suffix], $.preproc_elif) : $.preproc_elif
1804
+ );
1805
+ }
1806
+
1807
+ return {
1808
+ ['preproc_if' + suffix]: ($) =>
1809
+ prec(
1810
+ precedence,
1811
+ seq(
1812
+ preprocessor('if'),
1813
+ field('condition', $._preproc_expression),
1814
+ /\n/,
1815
+ rep ? repeat(content($)) : optional(content($)),
1816
+ field('alternative', optional(alternativeBlock($))),
1817
+ preprocessor('endif')
1818
+ )
1819
+ ),
1820
+
1821
+ ['preproc_else' + suffix]: ($) =>
1822
+ prec(precedence, seq(preprocessor('else'), rep ? repeat(content($)) : optional(content($)))),
1823
+
1824
+ ['preproc_elif' + suffix]: ($) =>
1825
+ prec(
1826
+ precedence,
1827
+ seq(
1828
+ preprocessor('elif'),
1829
+ field('condition', $._preproc_expression),
1830
+ /\n/,
1831
+ rep ? repeat(content($)) : optional(content($)),
1832
+ field('alternative', optional(alternativeBlock($)))
1833
+ )
1834
+ ),
1835
+ };
1836
+ }
1837
+
1838
+ /**
1839
+ * Creates a rule to match one or more of the rules separated by a comma
1840
+ *
1841
+ * @param {Rule} rule
1842
+ *
1843
+ * @returns {SeqRule}
1844
+ */
1845
+ function commaSep1(rule) {
1846
+ return seq(rule, repeat(seq(',', rule)));
1847
+ }
1848
+
1849
+ /**
1850
+ * Creates a rule to match two or more of the rules separated by a comma
1851
+ *
1852
+ * @param {Rule} rule
1853
+ *
1854
+ * @returns {SeqRule}
1855
+ */
1856
+ function commaSep2(rule) {
1857
+ return seq(rule, repeat1(seq(',', rule)));
1858
+ }
1859
+
1860
+ /**
1861
+ * Creates a rule to optionally match one or more of the rules separated by a comma
1862
+ *
1863
+ * @param {Rule} rule
1864
+ *
1865
+ * @returns {ChoiceRule}
1866
+ */
1867
+ function commaSep(rule) {
1868
+ return optional(commaSep1(rule));
1869
+ }
1870
+
1871
+ /**
1872
+ * Creates a rule to match one or more of the rules separated by `separator`
1873
+ *
1874
+ * @param {RuleOrLiteral} rule
1875
+ *
1876
+ * @param {RuleOrLiteral} separator
1877
+ *
1878
+ * @returns {SeqRule}
1879
+ */
1880
+ function sep1(rule, separator) {
1881
+ return seq(rule, repeat(seq(separator, rule)));
1882
+ }
1883
+
1884
+ /**
1885
+ * Creates a rule to optionally match one or more of the rules separated by `separator`
1886
+ *
1887
+ * @param {RuleOrLiteral} rule
1888
+ *
1889
+ * @param {RuleOrLiteral} separator
1890
+ *
1891
+ * @returns {ChoiceRule}
1892
+ */
1893
+ function sep(rule, separator) {
1894
+ return optional(sep1(rule, separator));
1895
+ }