@willbooster/tree-sitter-c-sharp 5.0.2 → 6.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 CHANGED
@@ -53,27 +53,140 @@ module.exports = grammar({
53
53
  name: 'c_sharp',
54
54
 
55
55
  conflicts: ($) => [
56
- [$._assignment_pointer_cast, $._lvalue_cast_expression],
57
- [$._assignment_pointer_expression, $._pointer_indirection_expression],
56
+ [$.list_pattern],
57
+ [$._conditional_binding_receiver, $._binding_generic_suppression_expression],
58
+ [$._member_conditional_binding_receiver, $._member_binding_generic_suppression_expression],
59
+ [$._binding_invocation_expression, $._binding_generic_suppression_expression],
60
+ [$._member_binding_invocation_expression, $._member_binding_generic_suppression_expression],
61
+ [$._simple_name, $._generic_alias_qualified_name],
62
+ [$._simple_name, $._generic_invocation_simple_name],
63
+ [$._pattern_declaration_type, $._assignment_target_await_expression, $.await_expression],
64
+ [$.recursive_pattern],
65
+ [$.type, $._pattern_type, $.recursive_pattern],
66
+ [$.implicit_type, $._pattern_identifier, $.var_pattern, $._reserved_identifier],
67
+ [$._pattern_primary_expression, $._pattern_non_name_primary_expression],
68
+ [$._pattern_type, $._pattern_array_type],
69
+ [$._pattern_type, $.recursive_pattern],
70
+ [$._pattern_type, $._pattern_array_type, $._array_base_type],
71
+ [$._pattern_identifier, $.var_pattern, $._reserved_identifier],
72
+ [
73
+ $._pattern_primary_expression,
74
+ $._pattern_non_name_primary_expression,
75
+ $._primary_no_conditional_access_expression,
76
+ ],
77
+ [
78
+ $._pattern_primary_expression,
79
+ $._primary_no_conditional_access_expression,
80
+ $.conditional_access_expression,
81
+ $._conditional_assignment_expression,
82
+ ],
83
+ [$._pattern_primary_expression, $.conditional_access_expression, $._conditional_assignment_expression],
84
+ [
85
+ $._primary_no_conditional_access_expression,
86
+ $.conditional_access_expression,
87
+ $._conditional_assignment_expression,
88
+ ],
89
+ [$._pattern_array_type, $._array_base_type],
90
+ [$._definite_cast_type, $._range_cast_type],
91
+ [$.type, $._definite_cast_type, $._range_cast_type],
92
+ [$._pattern_type, $._definite_cast_type, $._range_cast_type],
93
+ [$._definite_cast_name, $._range_cast_type],
94
+ [$._name, $._definite_cast_name, $._range_cast_type],
95
+ [$.array_rank_specifier, $._omitted_array_rank_specifier],
96
+ [$._pattern_parenthesized_expression, $.constant_pattern, $.expression],
97
+ [$._pattern_parenthesized_expression, $.constant_pattern],
98
+ [$._simple_name, $._pattern_simple_identifier_name, $._ambiguous_cast_qualified_name],
99
+ [$._simple_name, $._ambiguous_cast_qualified_name],
100
+ [$._simple_name, $._definite_cast_qualified_name],
101
+ [$.positional_pattern_clause, $._untyped_positional_pattern_clause],
102
+ [$._parenthesized_pattern_with_designation, $.subpattern],
103
+ [$._pattern_type, $._definite_cast_type],
104
+ [$.type, $._definite_cast_type],
105
+ [$.parameter, $._simple_name, $._ambiguous_cast_name],
106
+ [$._simple_name, $._ambiguous_cast_name],
107
+ [$._simple_name, $._definite_cast_name],
108
+ [$._name, $._definite_cast_name],
109
+ [$._object_initializer_expression, $.initializer_expression],
110
+ [
111
+ $._pattern_primary_expression,
112
+ $._primary_no_conditional_access_expression,
113
+ $._definite_conditional_access_receiver,
114
+ ],
115
+ [$._pattern_primary_expression, $._definite_conditional_access_receiver],
116
+ [$._primary_no_conditional_access_expression, $._definite_conditional_access_receiver],
117
+ [$._pattern_unary_expression, $._nonconditional_unary_expression],
118
+ [$._pattern_primary_expression, $._nonconditional_unary_expression],
119
+ [$._pattern_primary_expression, $._primary_no_conditional_access_expression, $._conditional_access_receiver],
120
+ [$.parameter, $._pattern_non_name_primary_expression, $._primary_no_conditional_access_expression],
121
+ [$._named_subpattern, $.subpattern],
122
+ [$.parameter_list, $._untyped_positional_pattern_clause],
123
+ [$.pattern, $._nonconstant_pattern],
124
+ [$.attribute, $._pattern_type],
125
+ [$.type, $._pattern_type],
126
+ [$.type, $._pattern_declaration_type],
127
+ [$._pattern_type, $._pattern_declaration_type],
128
+ [$._pattern_type, $.nullable_type],
129
+ [$._pattern_type, $._pattern_nullable_type, $.nullable_type],
130
+ [$._pattern_type, $._pattern_nullable_type],
131
+ [$._pattern_nullable_type, $.nullable_type],
132
+ [$._pattern_type, $._pointer_base_type],
133
+ [$._pattern_member_access_expression, $._pattern_generic_member_expression],
134
+ [$._simple_name, $._pattern_simple_generic_name],
135
+ [$._simple_name, $.generic_name, $._pattern_simple_identifier_name],
136
+ [$._simple_name, $._pattern_simple_identifier_name],
137
+ [$.generic_name, $._pattern_simple_identifier_name],
138
+ [$._pattern_non_name_member_access_expression, $.member_access_expression],
139
+ [$._pattern_unary_expression, $._unary_expression],
140
+ [$._pattern_primary_expression, $._primary_expression],
141
+ [$._pattern_primary_expression, $._primary_no_conditional_access_expression],
142
+ [$._pattern_identifier, $.from_clause, $._reserved_identifier],
143
+ [$.scoped_type, $._pattern_identifier, $._reserved_identifier],
144
+ [$._pattern_identifier, $._lambda_expression_init, $.anonymous_method_expression, $._reserved_identifier],
145
+ [$._pattern_identifier, $.identifier],
146
+ [$.implicit_type, $._pattern_identifier, $._reserved_identifier],
147
+ [$._pattern_primary_expression, $._conditional_access_receiver],
148
+ [$._pattern_non_name_primary_expression, $._primary_no_conditional_access_expression],
149
+ [$._pattern_identifier, $._reserved_identifier],
150
+ [$.var_pattern, $._reserved_identifier],
151
+ [$.anonymous_method_expression, $._reserved_identifier],
152
+ [$.attribute, $.type, $.recursive_pattern],
153
+ [$._initialized_stackalloc_expression, $.stackalloc_expression],
154
+ [$._member_conditional_binding_expression, $._member_conditional_binding_receiver],
155
+ [$.array_creation_expression, $._initialized_array_creation_expression],
156
+ [$.type, $.array_creation_expression, $._initialized_array_creation_expression],
157
+ [$._name, $._primary_no_conditional_access_expression, $._conditional_access_receiver],
158
+ [$._primary_no_conditional_access_expression, $._conditional_access_receiver],
159
+ [$._name, $._conditional_access_receiver],
160
+ [$.constant_pattern, $._nonconditional_unary_expression],
161
+ [$._unary_expression, $._nonconditional_unary_expression],
162
+ [$._primary_expression, $._nonconditional_unary_expression],
163
+ [$.constant_pattern, $._primary_no_conditional_access_expression],
164
+ [$._name, $.constant_pattern, $._primary_no_conditional_access_expression],
165
+ [$._conditional_binding_expression, $._conditional_binding_receiver],
166
+ [$.parameter, $._primary_no_conditional_access_expression],
167
+ [$._primary_expression, $.conditional_access_expression],
168
+ [$._name, $._primary_no_conditional_access_expression],
169
+ [$.constant_pattern, $._primary_expression],
170
+ [$._name, $.constant_pattern, $._primary_expression],
171
+ [$.parameter, $._primary_expression],
172
+ [$._unary_expression, $.conditional_access_expression],
173
+ [$._name, $._primary_expression],
174
+ [$.constant_pattern, $._unary_expression],
175
+ [$.constant_pattern, $.expression],
176
+ [$.tuple_element, $.declaration_expression],
177
+ [$.nullable_type, $.array_creation_expression],
178
+ [$._array_base_type, $.array_creation_expression],
179
+ [$.modifier, $.anonymous_method_expression, $._reserved_identifier],
180
+ [$.modifier, $.anonymous_method_expression],
58
181
  [$.modifier, $._constructor_declaration_initializer, $._reserved_identifier],
59
182
  [$._simple_name, $.generic_name],
60
183
  [$._simple_name, $.type_parameter],
61
184
  [$._simple_name, $.subpattern],
62
-
63
185
  [$.tuple_element, $.type_pattern],
64
186
  [$.type_pattern, $.declaration_pattern],
65
187
  [$.tuple_element, $.using_variable_declarator],
66
-
67
188
  [$.tuple_pattern, $.parameter],
68
189
  [$.tuple_pattern, $._simple_name],
69
-
70
- [$.lvalue_expression, $._name],
71
- [$.parameter, $.lvalue_expression],
72
- // C# 14 null-conditional assignment: `obj?.x = v` requires
73
- // `conditional_access_expression` to appear in both lvalue and
74
- // non-lvalue contexts. Tree-sitter needs GLR for the decision.
75
- [$.lvalue_expression, $.non_lvalue_expression],
76
-
77
190
  [$.type, $.attribute],
78
191
  [$.type, $.nullable_type],
79
192
  [$.type, $.nullable_type, $.array_creation_expression],
@@ -81,28 +194,18 @@ module.exports = grammar({
81
194
  [$.type, $._array_base_type, $.array_creation_expression],
82
195
  [$.type, $.array_creation_expression],
83
196
  [$.type, $._pointer_base_type],
84
-
85
197
  [$.qualified_name, $.member_access_expression],
86
198
  [$.qualified_name, $.explicit_interface_specifier],
87
-
88
199
  [$._array_base_type, $.stackalloc_expression],
89
-
90
- [$.constant_pattern, $.non_lvalue_expression],
91
200
  [$.constant_pattern, $._expression_statement_expression],
92
- [$.constant_pattern, $.lvalue_expression],
93
201
  [$.constant_pattern, $._name],
94
- [$.constant_pattern, $.lvalue_expression, $._name],
95
-
96
202
  [$.type, $._name_invocation_pattern, $.recursive_pattern],
97
203
  [$.type, $.recursive_pattern],
98
204
  [$.attribute, $.type, $._name_invocation_pattern, $.recursive_pattern],
99
-
100
205
  [$.parenthesized_pattern, $._parenthesized_pattern_with_designation],
101
-
102
206
  [$.expression_element, $.argument],
103
207
  [$.spread_element, $.range_expression],
104
208
  [$.collection_expression, $.list_pattern],
105
-
106
209
  [$._reserved_identifier, $.modifier],
107
210
  [$._reserved_identifier],
108
211
  [$._lambda_expression_init, $.anonymous_method_expression, $._reserved_identifier],
@@ -122,19 +225,11 @@ module.exports = grammar({
122
225
  [$.tuple_element, $.parameter, $.declaration_expression],
123
226
  [$.parameter, $.declaration_expression],
124
227
  [$.parameter, $.tuple_element],
125
-
126
228
  [$.event_declaration, $.variable_declarator],
127
-
128
229
  [$.base_list],
129
230
  [$.using_directive, $.modifier],
130
231
  [$.using_directive],
131
-
132
232
  [$._constructor_declaration_initializer, $._simple_name],
133
-
134
- // For C# 14 extension declarations: `extension(scoped X x)` —
135
- // `scoped` can be a parameter modifier, a scoped_type, or a
136
- // reserved identifier (when there's no further type). Keep all
137
- // three alive until later tokens disambiguate.
138
233
  [$.receiver_parameter, $.scoped_type, $._reserved_identifier],
139
234
  ],
140
235
 
@@ -168,6 +263,29 @@ module.exports = grammar({
168
263
  sym('file_directive_kind'),
169
264
  sym('_file_directive_literal_context'),
170
265
  sym('_file_directive_newline'),
266
+ sym('_question_unknown'),
267
+ sym('_question_ternary'),
268
+ sym('_question_member_access'),
269
+ sym('_question_element_access'),
270
+ sym('_question_nullable'),
271
+ sym('_case_label_colon'),
272
+ sym('_type_context_is'),
273
+ sym('_type_context_as'),
274
+ sym('_question_definite_access'),
275
+ sym('_object_index_start'),
276
+ sym('_slice_pattern_start'),
277
+ sym('_ambiguous_cast_operand_start'),
278
+ sym('_ambiguous_cast_type_end'),
279
+ sym('_definite_cast_type_end'),
280
+ sym('_range_cast_type_end'),
281
+ sym('_nonprimary_expression_end'),
282
+ sym('_pattern_paren_end'),
283
+ sym('_pattern_bracket_end'),
284
+ sym('_bang_operator'),
285
+ sym('_conditional_alternative_start'),
286
+ sym('_statement_end'),
287
+ sym('_block_end'),
288
+ sym('_ampersand_operator'),
171
289
  ],
172
290
 
173
291
  extras: ($) => [
@@ -186,6 +304,7 @@ module.exports = grammar({
186
304
  ],
187
305
 
188
306
  inline: ($) => [
307
+ $._postfix_receiver,
189
308
  $._namespace_member_declaration,
190
309
  $._object_creation_type,
191
310
  $._nullable_base_type,
@@ -201,13 +320,16 @@ module.exports = grammar({
201
320
  supertypes: ($) => [
202
321
  $.declaration,
203
322
  $.expression,
204
- $.non_lvalue_expression,
205
- $.lvalue_expression,
206
323
  $.literal,
207
324
  $.statement,
208
325
  $.type,
209
326
  $.type_declaration,
210
327
  $.pattern,
328
+ $._ambiguous_cast_type,
329
+ $._definite_cast_type,
330
+ $._range_cast_type,
331
+ $._is_pattern,
332
+ $._nonconstant_pattern,
211
333
  ],
212
334
 
213
335
  word: ($) => $._identifier_token,
@@ -229,7 +351,7 @@ module.exports = grammar({
229
351
 
230
352
  global_statement: ($) => prec(1, $.statement),
231
353
 
232
- extern_alias_directive: ($) => seq('extern', 'alias', field('name', $.identifier), ';'),
354
+ extern_alias_directive: ($) => seq('extern', 'alias', field('name', $.identifier), statementEnd()),
233
355
 
234
356
  using_directive: ($) =>
235
357
  seq(
@@ -239,7 +361,7 @@ module.exports = grammar({
239
361
  seq(optional('unsafe'), field('name', $.identifier), '=', $.type),
240
362
  seq(repeat(choice('static', 'unsafe')), $._name)
241
363
  ),
242
- ';'
364
+ statementEnd()
243
365
  ),
244
366
 
245
367
  global_attribute: ($) => seq('[', choice('assembly', 'module'), ':', commaSep1($.attribute), optional(','), ']'),
@@ -268,7 +390,7 @@ module.exports = grammar({
268
390
  namespace_declaration: ($) =>
269
391
  seq('namespace', field('name', $._name), field('body', $.declaration_list), sym('_optional_semi')),
270
392
 
271
- file_scoped_namespace_declaration: ($) => seq('namespace', field('name', $._name), ';'),
393
+ file_scoped_namespace_declaration: ($) => seq('namespace', field('name', $._name), statementEnd()),
272
394
 
273
395
  type_declaration: ($) =>
274
396
  choice(
@@ -308,7 +430,7 @@ module.exports = grammar({
308
430
  enum_declaration: ($) =>
309
431
  seq(
310
432
  $._enum_declaration_initializer,
311
- choice(seq(field('body', $.enum_member_declaration_list), sym('_optional_semi')), ';')
433
+ choice(seq(field('body', $.enum_member_declaration_list), sym('_optional_semi')), statementEnd())
312
434
  ),
313
435
 
314
436
  _enum_declaration_initializer: ($) =>
@@ -341,7 +463,7 @@ module.exports = grammar({
341
463
  ),
342
464
 
343
465
  delegate_declaration: ($) =>
344
- seq($._delegate_declaration_initializer, repeat($.type_parameter_constraints_clause), ';'),
466
+ seq($._delegate_declaration_initializer, repeat($.type_parameter_constraints_clause), statementEnd()),
345
467
 
346
468
  _delegate_declaration_initializer: ($) =>
347
469
  seq(
@@ -374,7 +496,8 @@ module.exports = grammar({
374
496
  seq(':', $.primary_constructor_base_type, optional(seq(',', commaSep1($._name))))
375
497
  ),
376
498
 
377
- _declaration_list_body: ($) => choice(seq(field('body', $.declaration_list), sym('_optional_semi')), ';'),
499
+ _declaration_list_body: ($) =>
500
+ choice(seq(field('body', $.declaration_list), sym('_optional_semi')), statementEnd()),
378
501
 
379
502
  primary_constructor_base_type: ($) => seq(field('type', $._name), $.argument_list),
380
503
 
@@ -416,7 +539,7 @@ module.exports = grammar({
416
539
 
417
540
  type_parameter_constraint: ($) =>
418
541
  choice(
419
- seq('class', optional('?')),
542
+ seq('class', optional(nullableQuestion())),
420
543
  'struct',
421
544
  'notnull',
422
545
  'unmanaged',
@@ -437,7 +560,7 @@ module.exports = grammar({
437
560
  field(
438
561
  'operator',
439
562
  choice(
440
- '!',
563
+ bangOperator(),
441
564
  '~',
442
565
  '++',
443
566
  '--',
@@ -450,7 +573,7 @@ module.exports = grammar({
450
573
  '%',
451
574
  '^',
452
575
  '|',
453
- '&',
576
+ ampersandOperator(),
454
577
  '<<',
455
578
  '>>',
456
579
  '>>>',
@@ -482,20 +605,13 @@ module.exports = grammar({
482
605
  repeat($._attribute_list),
483
606
  repeat($.modifier),
484
607
  choice('implicit', 'explicit'),
485
- repeat1(
486
- choice(
487
- // Intentionally structured this way for grammar size
488
- $.explicit_interface_specifier,
489
- 'operator',
490
- 'checked'
491
- )
492
- ),
608
+ repeat1(choice($.explicit_interface_specifier, 'operator', 'checked')),
493
609
  field('type', $.type),
494
610
  field('parameters', $.parameter_list),
495
611
  $._function_body
496
612
  ),
497
613
 
498
- declaration_list: ($) => seq('{', repeat($.declaration), '}'),
614
+ declaration_list: ($) => seq('{', repeat($.declaration), blockEnd()),
499
615
 
500
616
  declaration: ($) =>
501
617
  choice(
@@ -549,12 +665,13 @@ module.exports = grammar({
549
665
  receiver_parameter: ($) =>
550
666
  prec(1, seq(repeat($._attribute_list), $._parameter_type_with_modifiers, optional(field('name', $.identifier)))),
551
667
 
552
- extension_body: ($) => seq('{', repeat($._extension_member_declaration), '}', optional(';')),
668
+ extension_body: ($) => seq('{', repeat($._extension_member_declaration), '}', optional(statementEnd())),
553
669
 
554
670
  _extension_member_declaration: ($) =>
555
671
  choice($.method_declaration, $.conditional_method_declaration, $.property_declaration, $.operator_declaration),
556
672
 
557
- field_declaration: ($) => seq(repeat($._attribute_list), repeat($.modifier), $.variable_declaration, ';'),
673
+ field_declaration: ($) =>
674
+ seq(repeat($._attribute_list), repeat($.modifier), $.variable_declaration, statementEnd()),
558
675
 
559
676
  constructor_declaration: ($) => seq($._constructor_declaration_initializer, $._function_body),
560
677
 
@@ -607,11 +724,14 @@ module.exports = grammar({
607
724
  field('type', $.type),
608
725
  optional($.explicit_interface_specifier),
609
726
  field('name', $.identifier),
610
- choice(field('accessors', $.accessor_list), ';')
727
+ choice(field('accessors', $.accessor_list), statementEnd())
611
728
  ),
612
729
 
613
730
  event_field_declaration: ($) =>
614
- prec.dynamic(1, seq(repeat($._attribute_list), repeat($.modifier), 'event', $.variable_declaration, ';')),
731
+ prec.dynamic(
732
+ 1,
733
+ seq(repeat($._attribute_list), repeat($.modifier), 'event', $.variable_declaration, statementEnd())
734
+ ),
615
735
 
616
736
  accessor_list: ($) => seq('{', repeat($.accessor_declaration), '}'),
617
737
 
@@ -631,7 +751,7 @@ module.exports = grammar({
631
751
  optional($.explicit_interface_specifier),
632
752
  'this',
633
753
  field('parameters', $.bracketed_parameter_list),
634
- choice(field('accessors', $.accessor_list), seq(field('value', $.arrow_expression_clause), ';'))
754
+ choice(field('accessors', $.accessor_list), seq(field('value', $.arrow_expression_clause), statementEnd()))
635
755
  ),
636
756
 
637
757
  bracketed_parameter_list: ($) => seq('[', sep(choice($.parameter, $._parameter_array), ','), ']'),
@@ -644,8 +764,8 @@ module.exports = grammar({
644
764
  optional($.explicit_interface_specifier),
645
765
  field('name', $.identifier),
646
766
  choice(
647
- seq(field('accessors', $.accessor_list), optional(seq('=', field('value', $.expression), ';'))),
648
- seq(field('value', $.arrow_expression_clause), ';')
767
+ seq(field('accessors', $.accessor_list), optional(seq('=', field('value', $.expression), statementEnd()))),
768
+ seq(field('value', $.arrow_expression_clause), statementEnd())
649
769
  )
650
770
  ),
651
771
 
@@ -694,11 +814,12 @@ module.exports = grammar({
694
814
  )
695
815
  ),
696
816
 
697
- block: ($) => seq('{', repeat($.statement), '}'),
817
+ block: ($) => seq('{', repeat($.statement), blockEnd()),
698
818
 
699
819
  arrow_expression_clause: ($) => seq('=>', $.expression),
700
820
 
701
- _function_body: ($) => choice(field('body', $.block), seq(field('body', $.arrow_expression_clause), ';'), ';'),
821
+ _function_body: ($) =>
822
+ choice(field('body', $.block), seq(field('body', $.arrow_expression_clause), statementEnd()), statementEnd()),
702
823
 
703
824
  variable_declaration: ($) => seq(field('type', $.type), commaSep1($.variable_declarator)),
704
825
 
@@ -707,14 +828,14 @@ module.exports = grammar({
707
828
 
708
829
  variable_declarator: ($) =>
709
830
  seq(
710
- choice(field('name', $.identifier), $.tuple_pattern),
831
+ choice(field('name', $.identifier), prec.dynamic(-1, $.tuple_pattern)),
711
832
  optional($.bracketed_argument_list),
712
833
  optional(seq('=', $.expression))
713
834
  ),
714
835
 
715
836
  using_variable_declarator: ($) => seq(field('name', $.identifier), optional(seq('=', $.expression))),
716
837
 
717
- bracketed_argument_list: ($) => seq('[', commaSep1($.argument), optional(','), ']'),
838
+ bracketed_argument_list: ($) => bracketedArgumentList($, '['),
718
839
 
719
840
  qualified_identifier: ($) => sep1($.identifier, '.'),
720
841
 
@@ -730,16 +851,51 @@ module.exports = grammar({
730
851
 
731
852
  type_argument_list: ($) => seq('<', choice(repeat(','), commaSep1($.type)), '>'),
732
853
 
733
- type: ($) =>
854
+ type: ($) => typeAlternatives($),
855
+
856
+ _pattern_type: ($) =>
857
+ choice(
858
+ prec.dynamic(2, alias($._pattern_array_type, $.array_type)),
859
+ $._name,
860
+ alias($._pattern_nullable_type, $.nullable_type),
861
+ $.function_pointer_type,
862
+ $.predefined_type,
863
+ $.ref_type,
864
+ $.scoped_type
865
+ ),
866
+
867
+ _pattern_array_type: ($) =>
868
+ seq(
869
+ field(
870
+ 'type',
871
+ choice(
872
+ alias($._pattern_array_type, $.array_type),
873
+ $._name,
874
+ alias($._pattern_nullable_type, $.nullable_type),
875
+ $.pointer_type,
876
+ $.function_pointer_type,
877
+ $.predefined_type,
878
+ $.tuple_type
879
+ )
880
+ ),
881
+ field('rank', $.array_rank_specifier)
882
+ ),
883
+
884
+ _pattern_nullable_type: ($) =>
885
+ seq(
886
+ field('type', choice(alias($._pattern_array_type, $.array_type), $._name, $.predefined_type)),
887
+ nullableQuestion()
888
+ ),
889
+
890
+ _pattern_declaration_type: ($) =>
734
891
  choice(
735
892
  $.implicit_type,
736
- $.array_type,
893
+ prec(PREC.UNARY, alias('await', $.identifier)),
894
+ alias($._pattern_array_type, $.array_type),
737
895
  $._name,
738
- $.nullable_type,
739
- $.pointer_type,
896
+ alias($._pattern_nullable_type, $.nullable_type),
740
897
  $.function_pointer_type,
741
898
  $.predefined_type,
742
- $.tuple_type,
743
899
  $.ref_type,
744
900
  $.scoped_type
745
901
  ),
@@ -761,7 +917,7 @@ module.exports = grammar({
761
917
 
762
918
  array_rank_specifier: ($) => seq('[', commaSep(optional($.expression)), ']'),
763
919
 
764
- nullable_type: ($) => seq(field('type', $._nullable_base_type), '?'),
920
+ nullable_type: ($) => seq(field('type', $._nullable_base_type), nullableQuestion()),
765
921
 
766
922
  _nullable_base_type: ($) => choice($.array_type, $._name, $.predefined_type, $.tuple_type),
767
923
 
@@ -810,8 +966,6 @@ module.exports = grammar({
810
966
  'uint',
811
967
  'ulong',
812
968
  'ushort',
813
- 'nint',
814
- 'nuint',
815
969
  'void'
816
970
  )
817
971
  ),
@@ -871,18 +1025,18 @@ module.exports = grammar({
871
1025
  )
872
1026
  ),
873
1027
 
874
- break_statement: () => seq('break', ';'),
1028
+ break_statement: () => seq('break', statementEnd()),
875
1029
 
876
1030
  checked_statement: ($) => seq(choice('checked', 'unchecked'), $.block),
877
1031
 
878
- continue_statement: () => seq('continue', ';'),
1032
+ continue_statement: () => seq('continue', statementEnd()),
879
1033
 
880
1034
  do_statement: ($) =>
881
- seq('do', field('body', $.statement), 'while', '(', field('condition', $.expression), ')', ';'),
1035
+ seq('do', field('body', $.statement), 'while', '(', field('condition', $.expression), ')', statementEnd()),
882
1036
 
883
- empty_statement: () => ';',
1037
+ empty_statement: () => statementEnd(),
884
1038
 
885
- expression_statement: ($) => seq($._expression_statement_expression, ';'),
1039
+ expression_statement: ($) => seq($._expression_statement_expression, statementEnd()),
886
1040
 
887
1041
  fixed_statement: ($) => seq('fixed', '(', $.variable_declaration, ')', $.statement),
888
1042
 
@@ -892,18 +1046,18 @@ module.exports = grammar({
892
1046
  seq(
893
1047
  '(',
894
1048
  field('initializer', optional(choice($.variable_declaration, commaSep1($.expression)))),
895
- ';',
1049
+ statementEnd(),
896
1050
  field('condition', optional($.expression)),
897
- ';',
1051
+ statementEnd(),
898
1052
  field('update', optional(commaSep1($.expression))),
899
1053
  ')'
900
1054
  ),
901
1055
 
902
- return_statement: ($) => seq('return', optional($.expression), ';'),
1056
+ return_statement: ($) => seq('return', optional($.expression), statementEnd()),
903
1057
 
904
1058
  lock_statement: ($) => seq('lock', '(', $.expression, ')', $.statement),
905
1059
 
906
- yield_statement: ($) => seq('yield', choice(seq('return', $.expression), 'break'), ';'),
1060
+ yield_statement: ($) => seq('yield', choice(seq('return', $.expression), 'break'), statementEnd()),
907
1061
 
908
1062
  switch_statement: ($) =>
909
1063
  seq(
@@ -912,18 +1066,18 @@ module.exports = grammar({
912
1066
  field('body', $.switch_body)
913
1067
  ),
914
1068
 
915
- switch_body: ($) => seq('{', repeat($.switch_section), '}'),
1069
+ switch_body: ($) => seq('{', repeat($.switch_section), blockEnd()),
916
1070
 
917
1071
  switch_section: ($) =>
918
1072
  prec.left(
919
1073
  seq(
920
1074
  choice(seq('case', choice($.expression, seq($.pattern, optional($.when_clause)))), 'default'),
921
- ':',
1075
+ alias(sym('_case_label_colon'), ':'),
922
1076
  repeat($.statement)
923
1077
  )
924
1078
  ),
925
1079
 
926
- throw_statement: ($) => seq('throw', optional($.expression), ';'),
1080
+ throw_statement: ($) => seq('throw', optional($.expression), statementEnd()),
927
1081
 
928
1082
  try_statement: ($) => seq('try', field('body', $.block), repeat($.catch_clause), optional($.finally_clause)),
929
1083
 
@@ -964,7 +1118,7 @@ module.exports = grammar({
964
1118
  ')'
965
1119
  ),
966
1120
 
967
- goto_statement: ($) => seq('goto', optional(choice('case', 'default')), optional($.expression), ';'),
1121
+ goto_statement: ($) => seq('goto', optional(choice('case', 'default')), optional($.expression), statementEnd()),
968
1122
 
969
1123
  labeled_statement: ($) => seq($.identifier, ':', $.statement),
970
1124
 
@@ -983,7 +1137,7 @@ module.exports = grammar({
983
1137
  while_statement: ($) => seq('while', '(', field('condition', $.expression), ')', field('body', $.statement)),
984
1138
 
985
1139
  local_declaration_statement: ($) =>
986
- seq(optional('await'), optional('using'), repeat($.modifier), $.variable_declaration, ';'),
1140
+ seq(optional('await'), optional('using'), repeat($.modifier), $.variable_declaration, statementEnd()),
987
1141
 
988
1142
  local_function_statement: ($) =>
989
1143
  seq($._local_function_declaration, repeat($.type_parameter_constraints_clause), $._function_body),
@@ -998,50 +1152,195 @@ module.exports = grammar({
998
1152
  field('parameters', $.parameter_list)
999
1153
  ),
1000
1154
 
1001
- pattern: ($) =>
1155
+ _is_pattern: ($) =>
1002
1156
  choice(
1003
- $.constant_pattern,
1157
+ alias($._is_constant_pattern, $.constant_pattern),
1004
1158
  $.declaration_pattern,
1005
1159
  $.discard,
1006
1160
  $.recursive_pattern,
1007
1161
  $.var_pattern,
1008
- $.negated_pattern,
1009
- // This must come before plain parenthesized_pattern to create GLR conflict
1010
- prec.dynamic(1, alias($._parenthesized_pattern_with_designation, $.recursive_pattern)),
1162
+ alias($._is_negated_pattern, $.negated_pattern),
1163
+ alias($._parenthesized_pattern_with_designation, $.recursive_pattern),
1011
1164
  $.parenthesized_pattern,
1012
1165
  $.relational_pattern,
1013
- $.or_pattern,
1014
- $.and_pattern,
1166
+ alias($._is_or_pattern, $.or_pattern),
1167
+ alias($._is_and_pattern, $.and_pattern),
1015
1168
  $.list_pattern,
1169
+ $.slice_pattern,
1016
1170
  $.type_pattern
1017
1171
  ),
1018
1172
 
1019
- // Uses '(' pattern ')' to create direct conflict with parenthesized_pattern
1020
- _parenthesized_pattern_with_designation: ($) => seq('(', $.pattern, ')', $._simple_designation),
1173
+ _is_constant_pattern: ($) => prec(PREC.REL, choice(...constantExpressionRoots($))),
1174
+
1175
+ _is_negated_pattern: ($) => seq('not', alias($._is_pattern, $.pattern)),
1176
+
1177
+ _is_or_pattern: ($) =>
1178
+ prec.dynamic(
1179
+ 2,
1180
+ prec.left(
1181
+ PREC.OR,
1182
+ seq(
1183
+ field('left', alias($._is_pattern, $.pattern)),
1184
+ field('operator', 'or'),
1185
+ field('right', alias($._is_pattern, $.pattern))
1186
+ )
1187
+ )
1188
+ ),
1189
+
1190
+ _is_and_pattern: ($) =>
1191
+ prec.dynamic(
1192
+ 2,
1193
+ prec.left(
1194
+ PREC.AND,
1195
+ seq(
1196
+ field('left', alias($._is_pattern, $.pattern)),
1197
+ field('operator', 'and'),
1198
+ field('right', alias($._is_pattern, $.pattern))
1199
+ )
1200
+ )
1201
+ ),
1202
+
1203
+ _pattern_unary_expression: ($) =>
1204
+ choice($._pattern_primary_expression, $.prefix_unary_expression, $.cast_expression),
1205
+
1206
+ _pattern_parenthesized_expression: ($) =>
1207
+ seq('(', choice(...nestedConstantExpressionRoots($)), choice(')', alias(sym('_pattern_paren_end'), ')'))),
1021
1208
 
1022
- constant_pattern: ($) =>
1209
+ _pattern_primary_expression: ($) =>
1023
1210
  choice(
1024
- $.binary_expression,
1025
- $.default_expression,
1026
- $.interpolated_string_expression,
1027
- $.parenthesized_expression,
1028
- $.postfix_unary_expression,
1029
- $.prefix_unary_expression,
1030
- $.sizeof_expression,
1031
- $.tuple_expression,
1032
- $.typeof_expression,
1033
- $.member_access_expression,
1034
- alias($._name_invocation_pattern, $.invocation_expression),
1035
- alias($._complex_invocation_expression, $.invocation_expression),
1036
- $.cast_expression,
1037
- $._simple_name,
1038
- $.literal
1039
- ),
1040
-
1041
- // Invocation with name - creates conflict with recursive_pattern's Name(positional_pattern_clause)
1211
+ primaryAtoms($, {
1212
+ name: alias($._pattern_identifier, $.identifier),
1213
+ member: alias($._pattern_member_access_expression, $.member_access_expression),
1214
+ collection: false,
1215
+ element: alias($._pattern_element_access_expression, $.element_access_expression),
1216
+ invocation: alias($._pattern_invocation_expression, $.invocation_expression),
1217
+ tuple: false,
1218
+ parenthesized: alias($._pattern_parenthesized_expression, $.parenthesized_expression),
1219
+ }),
1220
+ $.conditional_access_expression,
1221
+ alias($._conditional_suppression_expression, $.postfix_unary_expression)
1222
+ ),
1223
+
1224
+ _pattern_identifier: ($) => choice($._identifier_token, ...reservedIdentifiers().slice(1)),
1225
+
1226
+ _pattern_simple_identifier_name: ($) => $.identifier,
1227
+
1228
+ _pattern_simple_generic_name: ($) => $.generic_name,
1229
+
1230
+ _pattern_member_access_expression: ($) =>
1231
+ choice(
1232
+ memberAccessExpression(
1233
+ $,
1234
+ choice($._primary_no_conditional_access_expression, $.predefined_type, $._name),
1235
+ $._pattern_simple_identifier_name
1236
+ ),
1237
+ memberAccessExpression(
1238
+ $,
1239
+ choice($._pattern_non_name_primary_expression, $.predefined_type),
1240
+ $._pattern_simple_generic_name,
1241
+ '.'
1242
+ ),
1243
+ memberAccessExpression(
1244
+ $,
1245
+ choice($._primary_no_conditional_access_expression, $.predefined_type, $._name),
1246
+ $._pattern_simple_generic_name,
1247
+ '->'
1248
+ )
1249
+ ),
1250
+
1251
+ _pattern_non_name_primary_expression: ($) =>
1252
+ choice(
1253
+ primaryAtoms($, {
1254
+ member: alias($._pattern_non_name_member_access_expression, $.member_access_expression),
1255
+ collection: true,
1256
+ parenthesized: alias($._pattern_parenthesized_expression, $.parenthesized_expression),
1257
+ })
1258
+ ),
1259
+
1260
+ _pattern_non_name_member_access_expression: ($) =>
1261
+ choice(
1262
+ memberAccessExpression(
1263
+ $,
1264
+ choice($._pattern_non_name_primary_expression, $.predefined_type),
1265
+ $._simple_name,
1266
+ '.'
1267
+ ),
1268
+ memberAccessExpression(
1269
+ $,
1270
+ choice($._primary_no_conditional_access_expression, $.predefined_type, $._name),
1271
+ $._simple_name,
1272
+ '->'
1273
+ )
1274
+ ),
1275
+
1276
+ _pattern_element_access_expression: ($) => elementAccessExpression($, $._pattern_non_name_primary_expression),
1277
+
1278
+ _pattern_invocation_expression: ($) => invocationExpression($, $._pattern_non_name_primary_expression),
1279
+
1280
+ _nameof_expression: ($) => invocationExpression($, alias('nameof', $.identifier)),
1281
+
1282
+ _pattern_generic_member_expression: ($) =>
1283
+ memberAccessExpression(
1284
+ $,
1285
+ choice($._primary_no_conditional_access_expression, $.predefined_type, $._name),
1286
+ $._pattern_simple_generic_name
1287
+ ),
1288
+
1289
+ _is_arithmetic_start_expression: ($) =>
1290
+ prec(
1291
+ PREC.SHIFT,
1292
+ choice(
1293
+ ...constantExpressionRoots($),
1294
+ $.generic_name,
1295
+ $.element_access_expression,
1296
+ alias($._pattern_generic_member_expression, $.member_access_expression)
1297
+ )
1298
+ ),
1299
+
1300
+ _is_arithmetic_expression: ($) =>
1301
+ prec(
1302
+ PREC.SHIFT,
1303
+ choice(
1304
+ $._unary_expression,
1305
+ alias($._is_arithmetic_operand_binary_expression, $.binary_expression),
1306
+ alias($._is_operand_range_expression, $.range_expression),
1307
+ alias($._is_operand_switch_expression, $.switch_expression),
1308
+ alias($._is_operand_with_expression, $.with_expression)
1309
+ )
1310
+ ),
1311
+
1312
+ _is_constant_receiver_expression: ($) => prec(PREC.SHIFT, choice(...constantExpressionRoots($))),
1313
+
1314
+ _is_range_expression: ($) => rangeExpression($._is_arithmetic_start_expression, $._is_arithmetic_expression, false),
1315
+
1316
+ _is_operand_range_expression: ($) => rangeExpression($._is_arithmetic_expression, $._is_arithmetic_expression),
1317
+
1318
+ _is_switch_expression: ($) => switchExpression($, $._is_constant_receiver_expression),
1319
+
1320
+ _is_operand_switch_expression: ($) => switchExpression($, $._is_arithmetic_expression),
1321
+
1322
+ _is_with_expression: ($) => withExpression($, $._is_constant_receiver_expression),
1323
+
1324
+ _is_operand_with_expression: ($) => withExpression($, $._is_arithmetic_expression),
1325
+
1326
+ _is_arithmetic_binary_expression: ($) =>
1327
+ arithmeticBinaryExpression($._is_arithmetic_start_expression, $._is_arithmetic_expression, true),
1328
+
1329
+ _is_arithmetic_operand_binary_expression: ($) =>
1330
+ arithmeticBinaryExpression($._is_arithmetic_expression, $._is_arithmetic_expression),
1331
+
1332
+ pattern: ($) => choice($.constant_pattern, nonconstantPatterns($)),
1333
+
1334
+ _nonconstant_pattern: ($) => nonconstantPatterns($),
1335
+
1336
+ // Uses '(' pattern ')' to create direct conflict with parenthesized_pattern
1337
+ _parenthesized_pattern_with_designation: ($) =>
1338
+ seq('(', $.pattern, choice(')', alias(sym('_pattern_paren_end'), ')')), $._simple_designation),
1339
+
1340
+ constant_pattern: ($) => choice(...nestedConstantExpressionRoots($)),
1341
+
1042
1342
  _name_invocation_pattern: ($) => seq(field('function', $._name), field('arguments', $.argument_list)),
1043
1343
 
1044
- // One above `invocation_expression`, which reads the same tokens where both fit.
1045
1344
  _complex_invocation_expression: ($) =>
1046
1345
  prec(
1047
1346
  PREC.INVOCATION + 1,
@@ -1063,11 +1362,10 @@ module.exports = grammar({
1063
1362
 
1064
1363
  discard: () => '_',
1065
1364
 
1066
- parenthesized_pattern: ($) => seq('(', $.pattern, ')'),
1365
+ parenthesized_pattern: ($) =>
1366
+ seq('(', alias($._nonconstant_pattern, $.pattern), choice(')', alias(sym('_pattern_paren_end'), ')'))),
1067
1367
 
1068
- // `var x` parses as a declaration_pattern with an implicit_type. `var (x, y)` also reads as a positional pattern
1069
- // of type `var` or, after `is`, as an invocation of `o is var`; each of those carries the implicit_type's dynamic
1070
- // precedence of 1, so this needs more.
1368
+ // The implicit_type reading of `var` contributes dynamic precedence 1; its parenthesized designation needs more.
1071
1369
  var_pattern: ($) => prec.dynamic(2, seq('var', $.parenthesized_variable_designation)),
1072
1370
 
1073
1371
  // No associativity: tree-sitter 0.27 resolves a precedence tie with a right-associative reduce as a shift, which
@@ -1075,243 +1373,225 @@ module.exports = grammar({
1075
1373
  // A name such as `A.B` in `R(A.B or C)` also parses as a constant pattern. Without the negative dynamic
1076
1374
  // precedence, the reading depends on the other GLR stack versions alive at that point, so an incremental
1077
1375
  // reparse can switch it without reporting a changed range.
1078
- type_pattern: ($) => prec.dynamic(-1, field('type', $.type)),
1376
+ type_pattern: ($) => prec.dynamic(-1, field('type', $._pattern_type)),
1079
1377
 
1080
- // Left-associative so that a contextual keyword after `]` (`when` in a switch arm or section, `select` in a query)
1081
- // ends the pattern instead of becoming its designation.
1082
1378
  list_pattern: ($) =>
1083
- prec.left(
1084
- seq(
1085
- '[',
1086
- optional(seq(commaSep1(choice($.pattern, $.slice_pattern)), optional(','))),
1087
- ']',
1088
- optional($._simple_designation)
1089
- )
1379
+ seq(
1380
+ '[',
1381
+ optional(seq(commaSep1($.pattern), optional(','))),
1382
+ choice(']', alias(sym('_pattern_bracket_end'), ']')),
1383
+ optional($._simple_designation)
1090
1384
  ),
1091
1385
 
1092
- slice_pattern: ($) => prec.right(seq('..', optional($.pattern))),
1386
+ slice_pattern: ($) => prec.right(seq(alias(sym('_slice_pattern_start'), '..'), optional($.pattern))),
1093
1387
 
1094
1388
  recursive_pattern: ($) =>
1095
- prec.left(
1096
- choice(
1097
- prec.dynamic(
1098
- 1,
1099
- seq(
1100
- field('type', $._name),
1101
- $.positional_pattern_clause,
1102
- optional($.property_pattern_clause),
1103
- $._simple_designation
1104
- )
1105
- ),
1106
- prec.dynamic(
1107
- -1,
1108
- seq(field('type', $._name), $.positional_pattern_clause, optional($.property_pattern_clause))
1109
- ),
1110
- prec.dynamic(1, seq($.positional_pattern_clause, $._simple_designation)),
1111
- $.positional_pattern_clause,
1112
- seq(field('type', $.type), $.property_pattern_clause, optional($._simple_designation)),
1113
- // A positional clause follows only a name (above), a predefined type, or an array type. Letting any type take
1114
- // one reads `Name(A.B)` once more, through `type`; after a syntax error, the extra GLR versions then exceed
1115
- // the runtime's limit, and which reading survives depends on the versions alive, not on dynamic precedence.
1389
+ choice(
1390
+ prec.dynamic(
1391
+ 2,
1116
1392
  seq(
1117
- field('type', choice($.predefined_type, $.array_type)),
1393
+ field('type', $._name),
1118
1394
  $.positional_pattern_clause,
1119
1395
  optional($.property_pattern_clause),
1120
- optional($._simple_designation)
1121
- ),
1122
- // no type, just pattern clauses (no variable designation to avoid conflict with above)
1123
- seq(
1124
- choice(seq($.positional_pattern_clause, $.property_pattern_clause), $.property_pattern_clause),
1125
- optional($._simple_designation)
1396
+ $._simple_designation
1126
1397
  )
1398
+ ),
1399
+ prec.dynamic(2, seq(field('type', $._name), $.positional_pattern_clause, optional($.property_pattern_clause))),
1400
+ prec.dynamic(1, seq($.positional_pattern_clause, $._simple_designation)),
1401
+ alias($._untyped_positional_pattern_clause, $.positional_pattern_clause),
1402
+ seq(
1403
+ field('type', typeAlternatives($, true, true, false)),
1404
+ $.property_pattern_clause,
1405
+ optional($._simple_designation)
1406
+ ),
1407
+ // Names already use the branch above. Admitting them again through type duplicates Name(A.B)
1408
+ // and can evict viable GLR versions during recovery.
1409
+ seq(
1410
+ field(
1411
+ 'type',
1412
+ choice(
1413
+ $.predefined_type,
1414
+ $.function_pointer_type,
1415
+ prec.dynamic(1, alias($._pattern_array_type, $.array_type))
1416
+ )
1417
+ ),
1418
+ $.positional_pattern_clause,
1419
+ optional($.property_pattern_clause),
1420
+ optional($._simple_designation)
1421
+ ),
1422
+ seq(
1423
+ choice(seq($.positional_pattern_clause, $.property_pattern_clause), $.property_pattern_clause),
1424
+ optional($._simple_designation)
1425
+ )
1426
+ ),
1427
+
1428
+ positional_pattern_clause: ($) =>
1429
+ prec(1, seq('(', optional(commaSep($.subpattern)), choice(')', alias(sym('_pattern_paren_end'), ')')))),
1430
+
1431
+ _untyped_positional_pattern_clause: ($) =>
1432
+ prec(
1433
+ 1,
1434
+ seq(
1435
+ '(',
1436
+ optional(choice(commaSep2($.subpattern), alias($._named_subpattern, $.subpattern))),
1437
+ choice(')', alias(sym('_pattern_paren_end'), ')'))
1127
1438
  )
1128
1439
  ),
1129
1440
 
1130
- positional_pattern_clause: ($) => prec(1, seq('(', optional(commaSep($.subpattern)), ')')),
1441
+ _named_subpattern: ($) => subpattern($, true),
1131
1442
 
1132
- property_pattern_clause: ($) => prec(1, seq('{', commaSep($.subpattern), optional(','), '}')),
1443
+ property_pattern_clause: ($) =>
1444
+ prec(
1445
+ 1,
1446
+ seq('{', commaSep($.subpattern), optional(','), choice('}', alias(sym('_nonprimary_expression_end'), '}')))
1447
+ ),
1133
1448
 
1134
- subpattern: ($) => prec.right(seq(optional(choice(seq($.expression, ':'), seq($.identifier, ':'))), $.pattern)),
1449
+ subpattern: ($) => subpattern($),
1135
1450
 
1136
- relational_pattern: ($) =>
1137
- choice(seq('<', $.expression), seq('<=', $.expression), seq('>', $.expression), seq('>=', $.expression)),
1451
+ relational_pattern: ($) => prec.left(PREC.REL, seq(choice('<', '<=', '>', '>='), $.expression)),
1138
1452
 
1139
1453
  negated_pattern: ($) => seq('not', $.pattern),
1140
1454
 
1141
1455
  and_pattern: ($) =>
1142
- prec.left(PREC.AND, seq(field('left', $.pattern), field('operator', 'and'), field('right', $.pattern))),
1456
+ prec.dynamic(
1457
+ 2,
1458
+ prec.left(PREC.AND, seq(field('left', $.pattern), field('operator', 'and'), field('right', $.pattern)))
1459
+ ),
1143
1460
 
1144
1461
  or_pattern: ($) =>
1145
- prec.left(PREC.OR, seq(field('left', $.pattern), field('operator', 'or'), field('right', $.pattern))),
1462
+ prec.dynamic(
1463
+ 2,
1464
+ prec.left(PREC.OR, seq(field('left', $.pattern), field('operator', 'or'), field('right', $.pattern)))
1465
+ ),
1146
1466
 
1147
- declaration_pattern: ($) => seq(field('type', $.type), $._simple_designation),
1467
+ declaration_pattern: ($) => seq(field('type', $._pattern_declaration_type), $._simple_designation),
1148
1468
 
1149
1469
  _variable_designation: ($) => choice($._simple_designation, $.parenthesized_variable_designation),
1150
1470
 
1151
1471
  // C# admits a parenthesized designation in a pattern only after `var`; elsewhere `T (x)` and `nameof(x)` are
1152
1472
  // positional patterns or invocations.
1153
- _simple_designation: ($) => prec(1, choice($.discard, field('name', $.identifier))),
1473
+ _simple_designation: ($) =>
1474
+ prec(
1475
+ 1,
1476
+ choice(
1477
+ $.discard,
1478
+ field('name', $.identifier),
1479
+ prec.dynamic(-2, field('name', alias(choice('and', 'or'), $.identifier)))
1480
+ )
1481
+ ),
1154
1482
 
1155
1483
  parenthesized_variable_designation: ($) => seq('(', commaSep($._variable_designation), ')'),
1156
1484
 
1157
- expression: ($) => choice($.non_lvalue_expression, $.lvalue_expression),
1158
-
1159
- non_lvalue_expression: ($) =>
1485
+ expression: ($) =>
1160
1486
  choice(
1161
- 'base',
1487
+ $._unary_expression,
1488
+ $.assignment_expression,
1162
1489
  $.binary_expression,
1163
- $.interpolated_string_expression,
1164
1490
  $.conditional_expression,
1165
- $.conditional_access_expression,
1166
- $.literal,
1167
- $._expression_statement_expression,
1168
- $.is_expression,
1169
1491
  $.is_pattern_expression,
1170
1492
  $.as_expression,
1171
- $.cast_expression,
1172
- $.checked_expression,
1173
- $.collection_expression,
1174
1493
  $.switch_expression,
1175
1494
  $.throw_expression,
1176
- $.default_expression,
1177
1495
  $.lambda_expression,
1178
1496
  $.with_expression,
1179
- $.sizeof_expression,
1180
- $.typeof_expression,
1181
- $.makeref_expression,
1182
1497
  $.ref_expression,
1183
- alias($._address_of_expression, $.prefix_unary_expression),
1184
- alias($._value_indirection_expression, $.prefix_unary_expression),
1185
- $.reftype_expression,
1186
- $.refvalue_expression,
1187
- $.stackalloc_expression,
1188
1498
  $.range_expression,
1189
- $.array_creation_expression,
1190
- $.anonymous_method_expression,
1191
- $.anonymous_object_creation_expression,
1192
- $.implicit_array_creation_expression,
1193
- $.implicit_object_creation_expression,
1194
- $.implicit_stackalloc_expression,
1195
1499
  $.initializer_expression,
1196
- $.query_expression,
1197
- alias(sym('preproc_if_in_expression'), sym('preproc_if'))
1500
+ $.query_expression
1198
1501
  ),
1199
1502
 
1200
- lvalue_expression: ($) =>
1503
+ _unary_expression: ($) =>
1504
+ choice($._primary_expression, $.prefix_unary_expression, $.cast_expression, $.await_expression),
1505
+
1506
+ _primary_expression: ($) =>
1201
1507
  choice(
1202
- 'this',
1203
- $.member_access_expression,
1204
- $.tuple_expression,
1205
- $._simple_name,
1206
- $.element_access_expression,
1207
- alias($.bracketed_argument_list, sym('element_binding_expression')),
1208
- alias($._pointer_indirection_expression, $.prefix_unary_expression),
1209
- alias($._parenthesized_lvalue_expression, $.parenthesized_expression),
1210
- // C# 14 null-conditional assignment: `obj?.x = v`, `obj?[i] = v`.
1211
- // https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-14#null-conditional-assignment
1212
- $.conditional_access_expression
1508
+ $._primary_no_conditional_access_expression,
1509
+ $.conditional_access_expression,
1510
+ alias($._conditional_suppression_expression, $.postfix_unary_expression)
1213
1511
  ),
1214
1512
 
1215
- // Covers error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
1216
- _expression_statement_expression: ($) =>
1513
+ _nonconditional_unary_expression: ($) =>
1217
1514
  choice(
1218
- $.assignment_expression,
1219
- $.invocation_expression,
1220
- $.postfix_unary_expression,
1221
- $.prefix_unary_expression,
1222
- $.await_expression,
1223
- $.object_creation_expression,
1224
- $.parenthesized_expression
1515
+ $._primary_no_conditional_access_expression,
1516
+ alias($._assignment_target_prefix_unary_expression, $.prefix_unary_expression),
1517
+ alias($._assignment_target_cast_expression, $.cast_expression),
1518
+ alias($._assignment_target_await_expression, $.await_expression)
1225
1519
  ),
1226
1520
 
1227
- assignment_expression: ($) =>
1228
- seq(
1229
- // An invocation can return a reference (`Unsafe.Add(ref x, i) = v`). It ends with `)`, so `=` after it adds few
1230
- // parse states, unlike making any expression assignable.
1231
- field(
1232
- 'left',
1233
- choice(
1234
- $.lvalue_expression,
1235
- $.invocation_expression,
1236
- alias($._assignment_pointer_expression, $.prefix_unary_expression)
1237
- )
1238
- ),
1239
- field('operator', choice('=', '+=', '-=', '*=', '/=', '%=', '&=', '^=', '|=', '<<=', '>>=', '>>>=', '??=')),
1240
- field('right', $.expression)
1521
+ _assignment_target_unary_operand: ($) =>
1522
+ choice(
1523
+ $._nonconditional_unary_expression,
1524
+ alias($._assignment_target_prefix_range_expression, $.range_expression)
1241
1525
  ),
1242
1526
 
1243
- // Keep this alternative confined to assignment targets: sharing it with ordinary dereferences changes hidden
1244
- // expression-supertype captures in nested reads. -3 prefers the existing lvalue path (-2) when both fit.
1245
- _assignment_pointer_expression: ($) =>
1246
- prec.dynamic(
1247
- -3,
1248
- prec.right(
1249
- PREC.UNARY,
1250
- seq(
1251
- '*',
1252
- choice(
1253
- $.lvalue_expression,
1254
- $.parenthesized_expression,
1255
- $.invocation_expression,
1256
- $.postfix_unary_expression,
1257
- alias($._assignment_pointer_expression, $.prefix_unary_expression),
1258
- alias($._pointer_prefix_update, $.prefix_unary_expression),
1259
- alias($._assignment_pointer_cast, $.cast_expression)
1260
- )
1261
- )
1262
- )
1263
- ),
1527
+ _assignment_target_prefix_unary_expression: ($) => prefixUnaryExpression($._assignment_target_unary_operand),
1264
1528
 
1265
- _pointer_prefix_update: ($) =>
1266
- prec(
1267
- PREC.UNARY,
1268
- seq(choice('++', '--'), choice($.lvalue_expression, $.invocation_expression, $.parenthesized_expression))
1529
+ _assignment_target_cast_expression: ($) =>
1530
+ castExpression(
1531
+ $,
1532
+ $._nonconditional_unary_expression,
1533
+ alias($._assignment_target_prefix_range_expression, $.range_expression)
1269
1534
  ),
1270
1535
 
1271
- _assignment_pointer_cast: ($) =>
1272
- prec(
1273
- PREC.CAST,
1274
- seq(
1275
- '(',
1276
- field('type', $.type),
1277
- ')',
1278
- field(
1279
- 'value',
1280
- choice(
1281
- $.lvalue_expression,
1282
- $.parenthesized_expression,
1283
- $.invocation_expression,
1284
- $.postfix_unary_expression,
1285
- alias($._assignment_pointer_expression, $.prefix_unary_expression),
1286
- alias($._pointer_prefix_update, $.prefix_unary_expression)
1287
- )
1288
- )
1289
- )
1536
+ _assignment_target_prefix_range_expression: ($) => prefixRangeExpression($._assignment_target_unary_operand),
1537
+
1538
+ _assignment_target_await_expression: ($) =>
1539
+ prec.right(PREC.UNARY, seq('await', $._assignment_target_unary_operand)),
1540
+
1541
+ _conditional_suppression_expression: ($) =>
1542
+ postfixExpression(
1543
+ choice(
1544
+ $.conditional_access_expression,
1545
+ alias($._conditional_suppression_expression, $.postfix_unary_expression)
1546
+ ),
1547
+ bangOperator()
1290
1548
  ),
1291
1549
 
1550
+ _conditional_update_expression: ($) =>
1551
+ postfixExpression(
1552
+ choice(
1553
+ $.conditional_access_expression,
1554
+ alias($._conditional_suppression_expression, $.postfix_unary_expression)
1555
+ ),
1556
+ choice('++', '--')
1557
+ ),
1558
+
1559
+ _primary_no_conditional_access_expression: ($) =>
1560
+ primaryAtoms($, { name: $._simple_name, member: $.member_access_expression, collection: true }),
1561
+
1562
+ _conditional_access_receiver: ($) =>
1563
+ primaryAtoms($, {
1564
+ name: $._simple_name,
1565
+ member: $.member_access_expression,
1566
+ collection: true,
1567
+ element: $.element_access_expression,
1568
+ invocation: $.invocation_expression,
1569
+ tuple: true,
1570
+ array: alias($._initialized_array_creation_expression, $.array_creation_expression),
1571
+ stackalloc: alias($._initialized_stackalloc_expression, $.stackalloc_expression),
1572
+ definite: false,
1573
+ }),
1574
+
1575
+ _definite_conditional_access_receiver: ($) =>
1576
+ primaryAtoms($, {
1577
+ name: $._simple_name,
1578
+ member: $.member_access_expression,
1579
+ collection: true,
1580
+ element: $.element_access_expression,
1581
+ invocation: $.invocation_expression,
1582
+ tuple: true,
1583
+ array: alias($._initialized_array_creation_expression, $.array_creation_expression),
1584
+ stackalloc: alias($._initialized_stackalloc_expression, $.stackalloc_expression),
1585
+ definite: true,
1586
+ }),
1587
+
1588
+ _expression_statement_expression: ($) => choice($._unary_expression, $.assignment_expression),
1589
+
1590
+ assignment_expression: ($) => assignmentExpression($, $._nonconditional_unary_expression),
1591
+
1292
1592
  binary_expression: ($) =>
1293
1593
  choice(
1294
- .../** @type {[string, number][]} */ ([
1295
- ['&&', PREC.LOGICAL_AND],
1296
- ['||', PREC.LOGICAL_OR],
1297
- ['>>', PREC.SHIFT],
1298
- ['>>>', PREC.SHIFT],
1299
- ['<<', PREC.SHIFT],
1300
- ['&', PREC.AND],
1301
- ['^', PREC.XOR],
1302
- ['|', PREC.OR],
1303
- ['+', PREC.ADD],
1304
- ['-', PREC.ADD],
1305
- ['*', PREC.MULT],
1306
- ['/', PREC.MULT],
1307
- ['%', PREC.MULT],
1308
- ['<', PREC.REL],
1309
- ['<=', PREC.REL],
1310
- ['==', PREC.EQUAL],
1311
- ['!=', PREC.EQUAL],
1312
- ['>=', PREC.REL],
1313
- ['>', PREC.REL],
1314
- ]).map(([operator, precedence]) =>
1594
+ ...binaryOperators().map(([operator, precedence]) =>
1315
1595
  prec.left(
1316
1596
  precedence,
1317
1597
  seq(field('left', $.expression), field('operator', operator), field('right', $.expression))
@@ -1323,80 +1603,13 @@ module.exports = grammar({
1323
1603
  )
1324
1604
  ),
1325
1605
 
1326
- postfix_unary_expression: ($) => prec(PREC.POSTFIX, seq(postfixOperand($), choice('++', '--', '!'))),
1327
-
1328
- // `&` and `*` have rules of their own (`_address_of_expression`, `_pointer_indirection_expression`, and
1329
- // `_value_indirection_expression`), aliased to this node. The dynamic precedence of `+`, `-`, and `^` is explained
1330
- // at `_pointer_indirection_expression`.
1331
- prefix_unary_expression: ($) =>
1332
- prec(
1333
- PREC.UNARY,
1334
- choice(
1335
- seq(choice('++', '--', '!', '~'), $.expression),
1336
- prec.dynamic(-2, seq(choice('+', '-', '^'), $.expression))
1337
- )
1338
- ),
1339
-
1340
- // Keep the lvalue operand set restricted: a general expression also permits assignment after every operand,
1341
- // substantially increasing parser states. Additional call and prefix-update operands use the assignment-only
1342
- // `_assignment_pointer_expression` path to preserve the shared read derivations and their query captures.
1343
- // Dynamic precedences: an assignable dereference -2, a read-only one -4, a read-only cast +1, an assignable cast -1,
1344
- // and a unary `+`, `-`, `^`, or `&` -2. C# reads a parenthesized name as a cast only when the token after `)` is
1345
- // `~`, `!`, `(`, an identifier, a literal, or a keyword (C# spec §12.9.8 Cast expressions), and these values keep
1346
- // that reading: `(a) * b`, `(a) - b`, and `(a) & b` are binary expressions (0), not casts of `*b`, `-b`, or `&b`
1347
- // (+1 - 2); `*(p) + 1` and `*(p) & x` apply to a dereference of `(p)` (-2), not to a dereference of a cast of `+1`
1348
- // or `&x` (-5); `*(b)[0]` dereferences an element access (-2), not a cast of `[0]` (-3). Where both casts fit, they
1349
- // give the same tree.
1350
- _pointer_indirection_expression: ($) =>
1351
- prec.dynamic(
1352
- -2,
1353
- prec.right(
1354
- PREC.UNARY,
1355
- seq(
1356
- '*',
1357
- choice(
1358
- $.lvalue_expression,
1359
- $.parenthesized_expression,
1360
- alias($._address_of_expression, $.prefix_unary_expression),
1361
- alias($._lvalue_cast_expression, $.cast_expression),
1362
- $.postfix_unary_expression
1363
- )
1364
- )
1365
- )
1366
- ),
1367
-
1368
- _lvalue_cast_expression: ($) =>
1369
- prec(
1370
- PREC.CAST,
1371
- prec.dynamic(
1372
- -1,
1373
- seq(
1374
- '(',
1375
- field('type', $.type),
1376
- ')',
1377
- field(
1378
- 'value',
1379
- choice(
1380
- $.lvalue_expression,
1381
- $.parenthesized_expression,
1382
- alias($._address_of_expression, $.prefix_unary_expression),
1383
- $.postfix_unary_expression,
1384
- $.invocation_expression
1385
- )
1386
- )
1387
- )
1388
- )
1606
+ postfix_unary_expression: ($) =>
1607
+ choice(
1608
+ postfixExpression($._primary_no_conditional_access_expression, choice('++', '--', bangOperator())),
1609
+ $._generic_invocation_suppression_expression
1389
1610
  ),
1390
1611
 
1391
- _value_indirection_expression: ($) => prec.dynamic(-4, prec.right(PREC.UNARY, seq('*', $.non_lvalue_expression))),
1392
-
1393
- // Address-of is split out from `prefix_unary_expression` and takes only a variable: an lvalue, or an invocation,
1394
- // which can return a reference (`&span.GetPinnableReference()`). If a cast could take `&` before any expression,
1395
- // the lexer would split `&&` into two `&` tokens and `(a) && (b > 0)` would read as a cast of `&(&(b > 0))`; as
1396
- // `(b > 0)` is not a variable, that reading fails and `&&` stays one token. The dynamic precedence is explained at
1397
- // `_pointer_indirection_expression`.
1398
- _address_of_expression: ($) =>
1399
- prec.dynamic(-2, prec.right(PREC.UNARY, seq('&', choice($.lvalue_expression, $.invocation_expression)))),
1612
+ prefix_unary_expression: ($) => prefixUnaryExpression($._unary_operand),
1400
1613
 
1401
1614
  query_expression: ($) => seq($.from_clause, $._query_body),
1402
1615
 
@@ -1434,65 +1647,352 @@ module.exports = grammar({
1434
1647
  PREC.CONDITIONAL,
1435
1648
  seq(
1436
1649
  field('condition', $.expression),
1437
- '?',
1650
+ ternaryQuestion(),
1438
1651
  field('consequence', $.expression),
1439
1652
  ':',
1653
+ sym('_conditional_alternative_start'),
1440
1654
  field('alternative', $.expression)
1441
1655
  )
1442
1656
  ),
1443
1657
 
1444
1658
  conditional_access_expression: ($) =>
1445
- prec.right(
1446
- PREC.CONDITIONAL,
1659
+ choice(
1660
+ $._conditional_assignment_expression,
1661
+ conditionalAccessExpression($, $._conditional_access_receiver),
1447
1662
  seq(
1448
- field('condition', $.expression),
1449
- '?',
1450
- choice($.member_binding_expression, alias($.bracketed_argument_list, sym('element_binding_expression')))
1663
+ field('condition', $._definite_conditional_access_receiver),
1664
+ definiteAccessQuestion(),
1665
+ field('consequence', $._conditional_access_consequence)
1666
+ ),
1667
+ seq(
1668
+ field('condition', $.array_creation_expression),
1669
+ memberAccessQuestion(),
1670
+ field('consequence', $._member_conditional_access_consequence)
1451
1671
  )
1452
1672
  ),
1453
1673
 
1454
- as_expression: ($) =>
1455
- prec(PREC.REL, seq(field('left', $.expression), field('operator', 'as'), field('right', $.type))),
1456
-
1457
- is_expression: ($) =>
1458
- prec(PREC.REL, seq(field('left', $.expression), field('operator', 'is'), field('right', $.type))),
1674
+ _member_conditional_access_consequence: ($) => $._member_conditional_binding_expression,
1459
1675
 
1460
- is_pattern_expression: ($) =>
1461
- prec(PREC.REL, seq(field('expression', $.expression), 'is', field('pattern', $.pattern))),
1676
+ _member_conditional_binding_expression: ($) =>
1677
+ choice(
1678
+ $._member_nonconditional_binding_expression,
1679
+ alias($._member_binding_conditional_access_expression, $.conditional_access_expression)
1680
+ ),
1462
1681
 
1463
- cast_expression: ($) =>
1464
- prec(
1465
- PREC.CAST,
1466
- prec.dynamic(
1467
- 1,
1468
- seq(
1469
- // higher than invocation, lower than binary
1470
- '(',
1471
- field('type', $.type),
1472
- ')',
1473
- field('value', $.expression)
1474
- )
1475
- )
1682
+ _member_nonconditional_binding_expression: ($) =>
1683
+ choice(
1684
+ $.member_binding_expression,
1685
+ alias($._member_binding_member_access_expression, $.member_access_expression),
1686
+ alias($._member_binding_element_access_expression, $.element_access_expression),
1687
+ alias($._member_binding_invocation_expression, $.invocation_expression)
1476
1688
  ),
1477
1689
 
1690
+ _member_conditional_binding_receiver: ($) =>
1691
+ choice(
1692
+ $._member_nonconditional_binding_expression,
1693
+ alias($._member_binding_suppression_expression, $.postfix_unary_expression),
1694
+ alias($._member_binding_generic_suppression_expression, $.postfix_unary_expression)
1695
+ ),
1696
+
1697
+ _member_binding_suppression_expression: ($) =>
1698
+ postfixExpression($._member_conditional_binding_receiver, bangOperator()),
1699
+
1700
+ _member_binding_member_access_expression: ($) => memberAccessExpression($, $._member_conditional_binding_receiver),
1701
+
1702
+ _member_binding_element_access_expression: ($) =>
1703
+ elementAccessExpression($, $._member_conditional_binding_receiver),
1704
+
1705
+ _member_binding_invocation_expression: ($) =>
1706
+ choice(
1707
+ invocationExpression($, $._member_conditional_binding_receiver),
1708
+ $._member_binding_generic_invocation_expression
1709
+ ),
1710
+
1711
+ _member_binding_generic_invocation_expression: ($) =>
1712
+ genericInvocationExpression(
1713
+ $,
1714
+ choice(
1715
+ alias($._generic_member_binding_expression, $.member_binding_expression),
1716
+ alias($._member_binding_generic_member_expression, $.member_access_expression)
1717
+ ),
1718
+ $._member_binding_generic_invocation_expression,
1719
+ $._member_binding_generic_suppression_expression
1720
+ ),
1721
+
1722
+ _member_binding_generic_member_expression: ($) =>
1723
+ memberAccessExpression($, $._member_conditional_binding_receiver, $._generic_invocation_simple_name),
1724
+
1725
+ _member_binding_generic_suppression_expression: ($) =>
1726
+ seq(
1727
+ genericInvocationReceiver(
1728
+ $,
1729
+ $._member_binding_generic_invocation_expression,
1730
+ $._member_binding_generic_suppression_expression
1731
+ ),
1732
+ bangOperator()
1733
+ ),
1734
+
1735
+ _member_binding_conditional_access_expression: ($) =>
1736
+ conditionalAccessExpression($, $._member_conditional_binding_receiver),
1737
+
1738
+ _member_conditional_binding_assignment_expression: ($) =>
1739
+ assignmentExpression($, $._member_conditional_binding_receiver),
1740
+
1741
+ _conditional_access_consequence: ($) => $._conditional_binding_expression,
1742
+
1743
+ _conditional_binding_expression: ($) =>
1744
+ choice(
1745
+ $._nonconditional_binding_expression,
1746
+ alias($._binding_conditional_access_expression, $.conditional_access_expression)
1747
+ ),
1748
+
1749
+ _nonconditional_binding_expression: ($) =>
1750
+ choice(
1751
+ $.member_binding_expression,
1752
+ alias($.bracketed_argument_list, sym('element_binding_expression')),
1753
+ alias($._binding_member_access_expression, $.member_access_expression),
1754
+ alias($._binding_element_access_expression, $.element_access_expression),
1755
+ alias($._binding_invocation_expression, $.invocation_expression)
1756
+ ),
1757
+
1758
+ _conditional_binding_receiver: ($) =>
1759
+ choice(
1760
+ $._nonconditional_binding_expression,
1761
+ alias($._binding_suppression_expression, $.postfix_unary_expression),
1762
+ alias($._binding_generic_suppression_expression, $.postfix_unary_expression)
1763
+ ),
1764
+
1765
+ _binding_suppression_expression: ($) => postfixExpression($._conditional_binding_receiver, bangOperator()),
1766
+
1767
+ _binding_member_access_expression: ($) => memberAccessExpression($, $._conditional_binding_receiver),
1768
+
1769
+ _binding_element_access_expression: ($) => elementAccessExpression($, $._conditional_binding_receiver),
1770
+
1771
+ _binding_invocation_expression: ($) =>
1772
+ choice(invocationExpression($, $._conditional_binding_receiver), $._binding_generic_invocation_expression),
1773
+
1774
+ _binding_generic_invocation_expression: ($) =>
1775
+ genericInvocationExpression(
1776
+ $,
1777
+ choice(
1778
+ alias($._generic_member_binding_expression, $.member_binding_expression),
1779
+ alias($._binding_generic_member_expression, $.member_access_expression)
1780
+ ),
1781
+ $._binding_generic_invocation_expression,
1782
+ $._binding_generic_suppression_expression
1783
+ ),
1784
+
1785
+ _binding_generic_member_expression: ($) =>
1786
+ memberAccessExpression($, $._conditional_binding_receiver, $._generic_invocation_simple_name),
1787
+
1788
+ _binding_generic_suppression_expression: ($) =>
1789
+ seq(
1790
+ genericInvocationReceiver(
1791
+ $,
1792
+ $._binding_generic_invocation_expression,
1793
+ $._binding_generic_suppression_expression
1794
+ ),
1795
+ bangOperator()
1796
+ ),
1797
+
1798
+ _binding_conditional_access_expression: ($) => conditionalAccessExpression($, $._conditional_binding_receiver),
1799
+
1800
+ _conditional_binding_assignment_expression: ($) => assignmentExpression($, $._conditional_binding_receiver),
1801
+
1802
+ _conditional_assignment_expression: ($) =>
1803
+ choice(
1804
+ seq(
1805
+ field('condition', $._conditional_access_receiver),
1806
+ accessQuestion(),
1807
+ field('consequence', $._conditional_assignment_consequence)
1808
+ ),
1809
+ seq(
1810
+ field('condition', $._definite_conditional_access_receiver),
1811
+ definiteAccessQuestion(),
1812
+ field('consequence', $._conditional_assignment_consequence)
1813
+ ),
1814
+ seq(
1815
+ field('condition', $.array_creation_expression),
1816
+ memberAccessQuestion(),
1817
+ field('consequence', $._member_conditional_assignment_consequence)
1818
+ )
1819
+ ),
1820
+
1821
+ _conditional_assignment_consequence: ($) =>
1822
+ choice(
1823
+ alias($._conditional_binding_assignment_expression, $.assignment_expression),
1824
+ alias($._binding_conditional_assignment_expression, $.conditional_access_expression)
1825
+ ),
1826
+
1827
+ _member_conditional_assignment_consequence: ($) =>
1828
+ choice(
1829
+ alias($._member_conditional_binding_assignment_expression, $.assignment_expression),
1830
+ alias($._member_binding_conditional_assignment_expression, $.conditional_access_expression)
1831
+ ),
1832
+
1833
+ _binding_conditional_assignment_expression: ($) =>
1834
+ seq(
1835
+ field('condition', $._conditional_binding_receiver),
1836
+ accessQuestion(),
1837
+ field('consequence', $._conditional_assignment_consequence)
1838
+ ),
1839
+
1840
+ _member_binding_conditional_assignment_expression: ($) =>
1841
+ seq(
1842
+ field('condition', $._member_conditional_binding_receiver),
1843
+ accessQuestion(),
1844
+ field('consequence', $._conditional_assignment_consequence)
1845
+ ),
1846
+
1847
+ _postfix_receiver: ($) =>
1848
+ choice(
1849
+ $._primary_no_conditional_access_expression,
1850
+ alias($._conditional_assignment_expression, $.conditional_access_expression)
1851
+ ),
1852
+
1853
+ _conditional_assignment_suppression_expression: ($) =>
1854
+ postfixExpression(
1855
+ choice(
1856
+ alias($._conditional_assignment_expression, $.conditional_access_expression),
1857
+ alias($._conditional_assignment_suppression_expression, $.postfix_unary_expression)
1858
+ ),
1859
+ bangOperator()
1860
+ ),
1861
+
1862
+ as_expression: ($) =>
1863
+ prec(
1864
+ PREC.REL,
1865
+ seq(
1866
+ field('left', $.expression),
1867
+ field('operator', alias(sym('_type_context_as'), 'as')),
1868
+ field('right', $.type)
1869
+ )
1870
+ ),
1871
+
1872
+ is_pattern_expression: ($) =>
1873
+ prec(
1874
+ PREC.REL,
1875
+ seq(
1876
+ field('expression', $.expression),
1877
+ alias(sym('_type_context_is'), 'is'),
1878
+ field('pattern', alias($._is_pattern, $.pattern))
1879
+ )
1880
+ ),
1881
+
1882
+ // C# treats a non-generic terminal name followed by a nonempty collection as parenthesized indexing.
1883
+ cast_expression: ($) =>
1884
+ castExpression($, $._non_range_unary_operand, alias($._prefix_range_expression, $.range_expression)),
1885
+
1886
+ _non_range_unary_operand: ($) => choice($._unary_expression, $.query_expression),
1887
+
1888
+ _unary_operand: ($) => choice($._non_range_unary_operand, alias($._prefix_range_expression, $.range_expression)),
1889
+
1890
+ _prefix_range_expression: ($) => prefixRangeExpression($._unary_operand),
1891
+
1892
+ _range_cast_type: ($) =>
1893
+ choice(
1894
+ typeAlternatives($, false, true, false, false, $.alias_qualified_name),
1895
+ alias($._omitted_cast_array_type, $.array_type)
1896
+ ),
1897
+
1898
+ _omitted_cast_array_type: ($) =>
1899
+ seq(
1900
+ field('type', $._array_base_type),
1901
+ field('rank', alias($._omitted_array_rank_specifier, $.array_rank_specifier))
1902
+ ),
1903
+
1904
+ _omitted_array_rank_specifier: () => seq('[', repeat(','), ']'),
1905
+
1906
+ _ambiguous_cast_type: ($) => $._ambiguous_cast_name,
1907
+
1908
+ _definite_cast_type: ($) =>
1909
+ choice(
1910
+ typeAlternatives($, false, true, true, false, $._definite_cast_name),
1911
+ alias($._omitted_cast_array_type, $.array_type)
1912
+ ),
1913
+
1914
+ _preferred_cast_head: ($) =>
1915
+ choice(
1916
+ prec.dynamic(
1917
+ 2,
1918
+ seq('(', field('type', alias($._ambiguous_cast_type, $.type)), alias(sym('_ambiguous_cast_type_end'), ')'))
1919
+ ),
1920
+ prec.dynamic(
1921
+ 3,
1922
+ seq(
1923
+ '(',
1924
+ field('type', alias($._omitted_cast_array_type, $.array_type)),
1925
+ alias(sym('_definite_cast_type_end'), ')')
1926
+ )
1927
+ )
1928
+ ),
1929
+
1930
+ _preferred_range_cast_head: ($) =>
1931
+ prec.dynamic(
1932
+ 3,
1933
+ seq(
1934
+ '(',
1935
+ field('type', alias($._omitted_cast_array_type, $.array_type)),
1936
+ alias(sym('_range_cast_type_end'), ')')
1937
+ )
1938
+ ),
1939
+
1940
+ _ambiguous_cast_name: ($) => choice($.identifier, alias($._ambiguous_cast_qualified_name, $.qualified_name)),
1941
+
1942
+ _ambiguous_cast_qualified_name: ($) => seq(field('qualifier', $._name), '.', field('name', $.identifier)),
1943
+
1944
+ _definite_cast_name: ($) =>
1945
+ choice($.generic_name, $.alias_qualified_name, alias($._definite_cast_qualified_name, $.qualified_name)),
1946
+
1947
+ _definite_cast_qualified_name: ($) => seq(field('qualifier', $._name), '.', field('name', $.generic_name)),
1948
+
1478
1949
  checked_expression: ($) => seq(choice('checked', 'unchecked'), '(', $.expression, ')'),
1479
1950
 
1480
1951
  invocation_expression: ($) =>
1481
- prec(PREC.INVOCATION, seq(field('function', postfixOperand($)), field('arguments', $.argument_list))),
1952
+ choice(invocationExpression($, $._postfix_receiver), $._generic_invocation_expression),
1953
+
1954
+ _generic_invocation_expression: ($) =>
1955
+ genericInvocationExpression(
1956
+ $,
1957
+ choice(
1958
+ $._generic_invocation_simple_name,
1959
+ alias($._pattern_generic_member_expression, $.member_access_expression),
1960
+ alias($._generic_alias_qualified_name, $.alias_qualified_name)
1961
+ ),
1962
+ $._generic_invocation_expression,
1963
+ $._generic_invocation_suppression_expression
1964
+ ),
1482
1965
 
1483
- switch_expression: ($) => prec(PREC.SWITCH, seq($.expression, 'switch', $._switch_expression_body)),
1484
- _switch_expression_body: ($) => seq('{', commaSep($.switch_expression_arm), optional(','), '}'),
1966
+ _generic_member_binding_expression: ($) => seq('.', field('name', $._generic_invocation_simple_name)),
1967
+
1968
+ _generic_invocation_simple_name: ($) => $.generic_name,
1969
+
1970
+ _generic_alias_qualified_name: ($) => seq(field('alias', $.identifier), '::', field('name', $.generic_name)),
1971
+
1972
+ _generic_invocation_suppression_expression: ($) =>
1973
+ postfixExpression(
1974
+ genericInvocationReceiver($, $._generic_invocation_expression, $._generic_invocation_suppression_expression),
1975
+ bangOperator()
1976
+ ),
1977
+
1978
+ switch_expression: ($) => switchExpression($, $.expression),
1979
+ _switch_expression_body: ($) =>
1980
+ seq(
1981
+ '{',
1982
+ commaSep($.switch_expression_arm),
1983
+ optional(','),
1984
+ choice('}', alias(sym('_nonprimary_expression_end'), '}'))
1985
+ ),
1485
1986
 
1486
1987
  switch_expression_arm: ($) => seq($.pattern, optional($.when_clause), '=>', $.expression),
1487
1988
 
1488
1989
  when_clause: ($) => seq('when', $.expression),
1489
1990
 
1490
- await_expression: ($) => prec.right(PREC.UNARY, seq('await', $.expression)),
1991
+ await_expression: ($) => prec.right(PREC.UNARY, seq('await', $._unary_operand)),
1491
1992
 
1492
1993
  throw_expression: ($) => seq('throw', $.expression),
1493
1994
 
1494
- element_access_expression: ($) =>
1495
- prec(PREC.POSTFIX, seq(field('expression', postfixOperand($)), field('subscript', $.bracketed_argument_list))),
1995
+ element_access_expression: ($) => elementAccessExpression($, $._postfix_receiver),
1496
1996
 
1497
1997
  interpolated_string_expression: ($) =>
1498
1998
  choice(
@@ -1545,7 +2045,10 @@ module.exports = grammar({
1545
2045
  interpolation_alignment_clause: ($) => seq(',', $.expression),
1546
2046
 
1547
2047
  interpolation_format_clause: () =>
1548
- seq(':', optional(sym('_file_directive_literal_context')), token.immediate(/[^}"\n\r\u0085\u2028\u2029]+/)),
2048
+ prec.dynamic(
2049
+ 1,
2050
+ seq(':', optional(sym('_file_directive_literal_context')), token.immediate(/[^}"\n\r\u0085\u2028\u2029]+/))
2051
+ ),
1549
2052
 
1550
2053
  _multiline_interpolation: ($) =>
1551
2054
  seq(
@@ -1556,17 +2059,10 @@ module.exports = grammar({
1556
2059
  alias(sym('interpolation_close_brace'), sym('interpolation_brace'))
1557
2060
  ),
1558
2061
 
1559
- _multiline_interpolation_format_clause: () => seq(':', optional(sym('_file_directive_literal_context')), /[^}"]+/),
2062
+ _multiline_interpolation_format_clause: () =>
2063
+ prec.dynamic(1, seq(':', optional(sym('_file_directive_literal_context')), /[^}"]+/)),
1560
2064
 
1561
- member_access_expression: ($) =>
1562
- prec(
1563
- PREC.DOT,
1564
- seq(
1565
- field('expression', choice(postfixOperand($), $.predefined_type, $._name)),
1566
- choice('.', '->'),
1567
- field('name', $._simple_name)
1568
- )
1569
- ),
2065
+ member_access_expression: ($) => memberAccessExpression($, choice($._postfix_receiver, $.predefined_type, $._name)),
1570
2066
 
1571
2067
  member_binding_expression: ($) => seq('.', field('name', $._simple_name)),
1572
2068
 
@@ -1574,17 +2070,20 @@ module.exports = grammar({
1574
2070
  prec.right(
1575
2071
  seq(
1576
2072
  'new',
1577
- field('type', $.type),
1578
- field('arguments', optional($.argument_list)),
1579
- field('initializer', optional($.initializer_expression))
2073
+ field('type', $._object_creation_type),
2074
+ choice(
2075
+ seq(
2076
+ field('arguments', $.argument_list),
2077
+ field('initializer', optional(alias($._object_initializer_expression, $.initializer_expression)))
2078
+ ),
2079
+ field('initializer', alias($._object_initializer_expression, $.initializer_expression))
2080
+ )
1580
2081
  )
1581
2082
  ),
1582
2083
 
1583
- _object_creation_type: ($) => choice($._name, $.nullable_type, $.predefined_type),
1584
-
1585
- parenthesized_expression: ($) => seq('(', $.non_lvalue_expression, ')'),
2084
+ _object_creation_type: ($) => typeAlternatives($, true, true, true, false),
1586
2085
 
1587
- _parenthesized_lvalue_expression: ($) => seq('(', $.lvalue_expression, ')'),
2086
+ parenthesized_expression: ($) => seq('(', $.expression, ')'),
1588
2087
 
1589
2088
  lambda_expression: ($) =>
1590
2089
  prec(-1, seq($._lambda_expression_init, '=>', field('body', choice($.block, $.expression)))),
@@ -1634,8 +2133,11 @@ module.exports = grammar({
1634
2133
  ')'
1635
2134
  ),
1636
2135
 
1637
- array_creation_expression: ($) =>
1638
- prec.dynamic(PREC.UNARY, seq('new', field('type', $.array_type), optional($.initializer_expression))),
2136
+ array_creation_expression: ($) => arrayCreationExpression($, optional($.initializer_expression)),
2137
+
2138
+ _initialized_array_creation_expression: ($) => arrayCreationExpression($, $.initializer_expression),
2139
+
2140
+ _initialized_stackalloc_expression: ($) => stackallocExpression($, $.initializer_expression),
1639
2141
 
1640
2142
  anonymous_method_expression: ($) =>
1641
2143
  seq(
@@ -1653,7 +2155,9 @@ module.exports = grammar({
1653
2155
  implicit_array_creation_expression: ($) => seq('new', '[', repeat(','), ']', $.initializer_expression),
1654
2156
 
1655
2157
  implicit_object_creation_expression: ($) =>
1656
- prec.right(seq('new', $.argument_list, optional($.initializer_expression))),
2158
+ prec.right(
2159
+ seq('new', $.argument_list, optional(alias($._object_initializer_expression, $.initializer_expression)))
2160
+ ),
1657
2161
 
1658
2162
  implicit_stackalloc_expression: ($) => seq('stackalloc', '[', ']', $.initializer_expression),
1659
2163
 
@@ -1665,14 +2169,44 @@ module.exports = grammar({
1665
2169
 
1666
2170
  spread_element: ($) => prec.dynamic(1, prec(PREC.RANGE, seq('..', $.expression))),
1667
2171
 
2172
+ _object_initializer_expression: ($) =>
2173
+ seq(
2174
+ '{',
2175
+ commaSep(
2176
+ choice(
2177
+ alias($._object_index_initializer, $.assignment_expression),
2178
+ alias($._object_member_initializer, $.assignment_expression),
2179
+ $.expression
2180
+ )
2181
+ ),
2182
+ optional(','),
2183
+ '}'
2184
+ ),
2185
+
2186
+ _object_initializer_value: ($) =>
2187
+ choice($.expression, alias($._object_initializer_expression, $.initializer_expression)),
2188
+
2189
+ _object_index_initializer: ($) =>
2190
+ assignmentExpression(
2191
+ $,
2192
+ alias($._object_index_target, sym('element_binding_expression')),
2193
+ '=',
2194
+ $._object_initializer_value
2195
+ ),
2196
+
2197
+ _object_index_target: ($) => bracketedArgumentList($, alias(sym('_object_index_start'), '[')),
2198
+
2199
+ _object_member_initializer: ($) => assignmentExpression($, $.identifier, '=', $._object_initializer_value),
2200
+
1668
2201
  initializer_expression: ($) => seq('{', commaSep($.expression), optional(','), '}'),
1669
2202
 
1670
2203
  declaration_expression: ($) => prec.dynamic(1, seq(field('type', $.type), field('name', $.identifier))),
1671
2204
 
1672
2205
  default_expression: ($) => prec.right(seq('default', optional(seq('(', field('type', $.type), ')')))),
1673
2206
 
1674
- with_expression: ($) => prec.left(PREC.WITH, seq($.expression, 'with', $._with_body)),
1675
- _with_body: ($) => seq('{', commaSep($.with_initializer), optional(','), '}'),
2207
+ with_expression: ($) => withExpression($, $.expression),
2208
+ _with_body: ($) =>
2209
+ seq('{', commaSep($.with_initializer), optional(','), choice('}', alias(sym('_nonprimary_expression_end'), '}'))),
1676
2210
 
1677
2211
  with_initializer: ($) => seq($.identifier, '=', $.expression),
1678
2212
 
@@ -1688,10 +2222,9 @@ module.exports = grammar({
1688
2222
 
1689
2223
  refvalue_expression: ($) => seq('__refvalue', '(', field('value', $.expression), ',', field('type', $.type), ')'),
1690
2224
 
1691
- stackalloc_expression: ($) =>
1692
- prec.left(seq('stackalloc', field('type', $.array_type), optional($.initializer_expression))),
2225
+ stackalloc_expression: ($) => stackallocExpression($, optional($.initializer_expression)),
1693
2226
 
1694
- range_expression: ($) => prec.right(PREC.RANGE, seq(optional($.expression), '..', optional($.expression))),
2227
+ range_expression: ($) => rangeExpression($.expression, $.expression),
1695
2228
 
1696
2229
  tuple_expression: ($) => seq('(', commaSep2(alias($._tuple_argument, $.argument)), ')'),
1697
2230
 
@@ -1779,47 +2312,7 @@ module.exports = grammar({
1779
2312
  ),
1780
2313
  identifier: ($) => choice($._identifier_token, $._reserved_identifier),
1781
2314
 
1782
- _reserved_identifier: () =>
1783
- choice(
1784
- prec(-1, '_'),
1785
- 'alias',
1786
- 'async',
1787
- 'ascending',
1788
- 'by',
1789
- 'descending',
1790
- 'equals',
1791
- // attribute_target_specifier keywords — contextual only when followed
1792
- // by `:` in `[target: Attr]` position. Anywhere else they're
1793
- // identifiers. Without listing them here the LR table preferred the
1794
- // literal-keyword interpretation, breaking `[type]`, `[field]`, etc.
1795
- // as collection_expression elements. Excludes `'event'` and `'return'`
1796
- // from the attribute_target_specifier choice — those are real C#
1797
- // keywords and must not be accepted as identifiers anywhere else.
1798
- 'field',
1799
- 'file',
1800
- 'from',
1801
- 'global',
1802
- 'group',
1803
- 'into',
1804
- 'join',
1805
- 'let',
1806
- 'method',
1807
- 'notnull',
1808
- 'on',
1809
- 'orderby',
1810
- 'param',
1811
- 'partial',
1812
- 'property',
1813
- 'scoped',
1814
- 'select',
1815
- 'type',
1816
- 'typevar',
1817
- 'unmanaged',
1818
- 'var',
1819
- 'when',
1820
- 'where',
1821
- 'yield'
1822
- ),
2315
+ _reserved_identifier: () => choice(...reservedIdentifiers()),
1823
2316
 
1824
2317
  ...preprocIf(
1825
2318
  '_in_method_signature',
@@ -1857,7 +2350,7 @@ module.exports = grammar({
1857
2350
  preproc_parenthesized_expression: ($) => seq('(', $._preproc_expression, ')'),
1858
2351
 
1859
2352
  preproc_unary_expression: ($) =>
1860
- prec.left(PREC.UNARY, seq(field('operator', '!'), field('argument', $._preproc_expression))),
2353
+ prec.left(PREC.UNARY, seq(field('operator', bangOperator()), field('argument', $._preproc_expression))),
1861
2354
 
1862
2355
  preproc_binary_expression: ($) => {
1863
2356
  /** @type {[string, number][]} */
@@ -2163,25 +2656,192 @@ function preprocIf(suffix, content, precedence = 0, rep = true, required = false
2163
2656
  }
2164
2657
 
2165
2658
  /**
2166
- * The operand of a postfix operator, an invocation, an element access, or a member access. Besides `expression`, it
2167
- * lists the forms that are operands of `&`, of the assignable `*`, or of the assignable cast: reaching them only
2168
- * through `expression` would reduce the unary operator or the cast (precedence UNARY or CAST) before `expression`
2169
- * (precedence 0) lets the postfix operator apply, reading `&a[0]` as `(&a)[0]` and `*(T*)f()[0]` as `(*(T*)f())[0]`.
2170
- *
2171
- * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'expression' | 'invocation_expression' | 'lvalue_expression' | 'parenthesized_expression' | 'postfix_unary_expression'>} $
2172
- *
2173
- * @returns {import('@willbooster/web-tree-sitter/dsl').ChoiceRule}
2659
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_simple_name'>} $
2660
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
2661
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} [name]
2662
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral} [operator]
2663
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2174
2664
  */
2175
- function postfixOperand($) {
2665
+ function memberAccessExpression($, receiver, name = $._simple_name, operator = choice('.', '->')) {
2666
+ return prec(PREC.DOT, seq(field('expression', receiver), operator, field('name', name)));
2667
+ }
2668
+
2669
+ /**
2670
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'bracketed_argument_list'>} $
2671
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
2672
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2673
+ */
2674
+ function elementAccessExpression($, receiver) {
2675
+ return prec(PREC.DOT, seq(field('expression', receiver), field('subscript', $.bracketed_argument_list)));
2676
+ }
2677
+
2678
+ /**
2679
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'argument_list'>} $
2680
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
2681
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2682
+ */
2683
+ function invocationExpression($, receiver) {
2684
+ return prec(PREC.INVOCATION, seq(field('function', receiver), field('arguments', $.argument_list)));
2685
+ }
2686
+
2687
+ /**
2688
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'argument_list' | 'invocation_expression' | 'postfix_unary_expression'>} $
2689
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} first
2690
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} call
2691
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} suppression
2692
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2693
+ */
2694
+ function genericInvocationExpression($, first, call, suppression) {
2176
2695
  return choice(
2177
- $.expression,
2178
- $.lvalue_expression,
2179
- $.invocation_expression,
2180
- $.postfix_unary_expression,
2181
- $.parenthesized_expression
2696
+ prec.dynamic(1, invocationExpression($, first)),
2697
+ prec.dynamic(3, invocationExpression($, genericInvocationReceiver($, call, suppression)))
2698
+ );
2699
+ }
2700
+
2701
+ /**
2702
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'invocation_expression' | 'postfix_unary_expression'>} $
2703
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} call
2704
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} suppression
2705
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2706
+ */
2707
+ function genericInvocationReceiver($, call, suppression) {
2708
+ return choice(alias(call, $.invocation_expression), alias(suppression, $.postfix_unary_expression));
2709
+ }
2710
+
2711
+ /**
2712
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} operand
2713
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2714
+ */
2715
+ function prefixUnaryExpression(operand) {
2716
+ return prec.right(
2717
+ PREC.UNARY,
2718
+ choice(
2719
+ seq(choice('++', '--', bangOperator(), '~'), operand),
2720
+ prec.dynamic(-2, seq(choice('+', '-', '^', '*', ampersandOperator()), operand))
2721
+ )
2722
+ );
2723
+ }
2724
+
2725
+ /**
2726
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_ambiguous_cast_type' | '_definite_cast_type' | '_preferred_cast_head' | '_preferred_range_cast_head' | '_range_cast_type' | 'type'>} $
2727
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} operand
2728
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} [rangeOperand]
2729
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2730
+ */
2731
+ function castExpression($, operand, rangeOperand) {
2732
+ return prec(
2733
+ PREC.CAST,
2734
+ prec.dynamic(
2735
+ 1,
2736
+ choice(
2737
+ seq(
2738
+ '(',
2739
+ field('type', alias($._ambiguous_cast_type, $.type)),
2740
+ ')',
2741
+ sym('_ambiguous_cast_operand_start'),
2742
+ field('value', operand)
2743
+ ),
2744
+ seq('(', field('type', alias($._definite_cast_type, $.type)), ')', field('value', operand)),
2745
+ seq($._preferred_cast_head, field('value', operand)),
2746
+ ...(rangeOperand
2747
+ ? [
2748
+ seq('(', field('type', alias($._range_cast_type, $.type)), ')', field('value', rangeOperand)),
2749
+ seq($._preferred_range_cast_head, field('value', rangeOperand)),
2750
+ ]
2751
+ : [])
2752
+ )
2753
+ )
2754
+ );
2755
+ }
2756
+
2757
+ /**
2758
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_conditional_access_consequence'>} $
2759
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
2760
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2761
+ */
2762
+ function conditionalAccessExpression($, receiver) {
2763
+ return seq(field('condition', receiver), accessQuestion(), field('consequence', $._conditional_access_consequence));
2764
+ }
2765
+
2766
+ /**
2767
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
2768
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral} operator
2769
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2770
+ */
2771
+ function postfixExpression(receiver, operator) {
2772
+ return prec(PREC.POSTFIX, seq(receiver, operator));
2773
+ }
2774
+
2775
+ /**
2776
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'expression'>} $
2777
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
2778
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral} [operator]
2779
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} [value]
2780
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2781
+ */
2782
+ function assignmentExpression(
2783
+ $,
2784
+ receiver,
2785
+ operator = choice('=', '+=', '-=', '*=', '/=', '%=', '&=', '^=', '|=', '<<=', '>>=', '>>>=', '??='),
2786
+ value = $.expression
2787
+ ) {
2788
+ return prec.right(PREC.ASSIGN, seq(field('left', receiver), field('operator', operator), field('right', value)));
2789
+ }
2790
+
2791
+ /**
2792
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'array_type'>} $
2793
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} initializer
2794
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2795
+ */
2796
+ function arrayCreationExpression($, initializer) {
2797
+ return prec.dynamic(PREC.UNARY, seq('new', field('type', $.array_type), initializer));
2798
+ }
2799
+
2800
+ /**
2801
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'type'>} $
2802
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} initializer
2803
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2804
+ */
2805
+ function stackallocExpression($, initializer) {
2806
+ return prec.left(seq('stackalloc', field('type', $.type), initializer));
2807
+ }
2808
+
2809
+ /**
2810
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'argument'>} $
2811
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral} opener
2812
+ */
2813
+ function bracketedArgumentList($, opener) {
2814
+ return seq(opener, commaSep1($.argument), optional(','), ']');
2815
+ }
2816
+
2817
+ function bangOperator() {
2818
+ return alias(sym('_bang_operator'), '!');
2819
+ }
2820
+
2821
+ function definiteAccessQuestion() {
2822
+ return choice(alias(sym('_question_definite_access'), '?'), alias(sym('_question_unknown'), '?'));
2823
+ }
2824
+
2825
+ function accessQuestion() {
2826
+ return choice(
2827
+ alias(sym('_question_member_access'), '?'),
2828
+ alias(sym('_question_element_access'), '?'),
2829
+ alias(sym('_question_unknown'), '?')
2182
2830
  );
2183
2831
  }
2184
2832
 
2833
+ function memberAccessQuestion() {
2834
+ return choice(alias(sym('_question_member_access'), '?'), alias(sym('_question_unknown'), '?'));
2835
+ }
2836
+
2837
+ function ternaryQuestion() {
2838
+ return choice(alias(sym('_question_ternary'), '?'), alias(sym('_question_unknown'), '?'));
2839
+ }
2840
+
2841
+ function nullableQuestion() {
2842
+ return choice(alias(sym('_question_nullable'), '?'), alias(sym('_question_unknown'), '?'));
2843
+ }
2844
+
2185
2845
  /**
2186
2846
  * @param {import('@willbooster/web-tree-sitter/dsl').Rule} rule
2187
2847
  *
@@ -2230,3 +2890,276 @@ function sep1(rule, separator) {
2230
2890
  function sep(rule, separator) {
2231
2891
  return optional(sep1(rule, separator));
2232
2892
  }
2893
+
2894
+ function binaryOperators() {
2895
+ /** @type {[import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral, number][]} */
2896
+ const operators = [
2897
+ ['&&', PREC.LOGICAL_AND],
2898
+ ['||', PREC.LOGICAL_OR],
2899
+ ['>>', PREC.SHIFT],
2900
+ ['>>>', PREC.SHIFT],
2901
+ ['<<', PREC.SHIFT],
2902
+ [ampersandOperator(), PREC.AND],
2903
+ ['^', PREC.XOR],
2904
+ ['|', PREC.OR],
2905
+ ['+', PREC.ADD],
2906
+ ['-', PREC.ADD],
2907
+ ['*', PREC.MULT],
2908
+ ['/', PREC.MULT],
2909
+ ['%', PREC.MULT],
2910
+ ['<', PREC.REL],
2911
+ ['<=', PREC.REL],
2912
+ ['==', PREC.EQUAL],
2913
+ ['!=', PREC.EQUAL],
2914
+ ['>=', PREC.REL],
2915
+ ['>', PREC.REL],
2916
+ ];
2917
+ return operators;
2918
+ }
2919
+
2920
+ /**
2921
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_conditional_assignment_suppression_expression' | '_conditional_update_expression' | '_nameof_expression' | 'anonymous_method_expression' | 'anonymous_object_creation_expression' | 'array_creation_expression' | 'checked_expression' | 'collection_expression' | 'default_expression' | 'element_access_expression' | 'implicit_array_creation_expression' | 'implicit_object_creation_expression' | 'implicit_stackalloc_expression' | 'interpolated_string_expression' | 'invocation_expression' | 'literal' | 'makeref_expression' | 'object_creation_expression' | 'parenthesized_expression' | 'postfix_unary_expression' | 'reftype_expression' | 'refvalue_expression' | 'sizeof_expression' | 'stackalloc_expression' | 'tuple_expression' | 'typeof_expression'>} $
2922
+ * @param {{name?: import('@willbooster/web-tree-sitter/dsl').Rule, member: import('@willbooster/web-tree-sitter/dsl').Rule, collection: boolean, element?: import('@willbooster/web-tree-sitter/dsl').Rule, invocation?: import('@willbooster/web-tree-sitter/dsl').Rule, parenthesized?: import('@willbooster/web-tree-sitter/dsl').Rule, tuple?: boolean, array?: import('@willbooster/web-tree-sitter/dsl').Rule, stackalloc?: import('@willbooster/web-tree-sitter/dsl').Rule, definite?: boolean}} options
2923
+ */
2924
+ function primaryAtoms(
2925
+ $,
2926
+ {
2927
+ name,
2928
+ member,
2929
+ collection,
2930
+ element = $.element_access_expression,
2931
+ invocation = $.invocation_expression,
2932
+ parenthesized = $.parenthesized_expression,
2933
+ tuple = true,
2934
+ array = $.array_creation_expression,
2935
+ stackalloc = $.stackalloc_expression,
2936
+ definite,
2937
+ }
2938
+ ) {
2939
+ const uncertain = [
2940
+ ...(name ? [name] : []),
2941
+ member,
2942
+ element,
2943
+ invocation,
2944
+ ...(tuple ? [$.tuple_expression] : []),
2945
+ parenthesized,
2946
+ ...(collection ? [$.collection_expression] : []),
2947
+ alias(sym('preproc_if_in_expression'), sym('preproc_if')),
2948
+ ];
2949
+ const completed = [
2950
+ alias($._nameof_expression, $.invocation_expression),
2951
+ alias($._conditional_update_expression, $.postfix_unary_expression),
2952
+ alias($._conditional_assignment_suppression_expression, $.postfix_unary_expression),
2953
+ 'this',
2954
+ 'base',
2955
+ $.postfix_unary_expression,
2956
+ $.literal,
2957
+ $.interpolated_string_expression,
2958
+ $.checked_expression,
2959
+ $.default_expression,
2960
+ $.sizeof_expression,
2961
+ $.typeof_expression,
2962
+ $.makeref_expression,
2963
+ $.reftype_expression,
2964
+ $.refvalue_expression,
2965
+ stackalloc,
2966
+ array,
2967
+ $.object_creation_expression,
2968
+ $.anonymous_method_expression,
2969
+ $.anonymous_object_creation_expression,
2970
+ $.implicit_array_creation_expression,
2971
+ $.implicit_object_creation_expression,
2972
+ $.implicit_stackalloc_expression,
2973
+ ];
2974
+ return choice(...(definite === true ? [] : uncertain), ...(definite === false ? [] : completed));
2975
+ }
2976
+
2977
+ function reservedIdentifiers() {
2978
+ return [
2979
+ prec(-1, '_'),
2980
+ 'alias',
2981
+ 'async',
2982
+ 'ascending',
2983
+ 'by',
2984
+ 'descending',
2985
+ 'equals',
2986
+ // attribute_target_specifier keywords — contextual only when followed
2987
+ // by `:` in `[target: Attr]` position. Anywhere else they're
2988
+ // identifiers. Without listing them here the LR table preferred the
2989
+ // literal-keyword interpretation, breaking `[type]`, `[field]`, etc.
2990
+ // as collection_expression elements. Excludes `'event'` and `'return'`
2991
+ // from the attribute_target_specifier choice — those are real C#
2992
+ // keywords and must not be accepted as identifiers anywhere else.
2993
+ 'field',
2994
+ 'file',
2995
+ 'from',
2996
+ 'global',
2997
+ 'group',
2998
+ 'into',
2999
+ 'join',
3000
+ 'let',
3001
+ 'method',
3002
+ 'nameof',
3003
+ 'nint',
3004
+ 'nuint',
3005
+ 'notnull',
3006
+ 'on',
3007
+ 'orderby',
3008
+ 'param',
3009
+ 'partial',
3010
+ 'property',
3011
+ 'scoped',
3012
+ 'select',
3013
+ 'type',
3014
+ 'typevar',
3015
+ 'unmanaged',
3016
+ 'var',
3017
+ 'when',
3018
+ 'where',
3019
+ 'yield',
3020
+ ];
3021
+ }
3022
+
3023
+ /**
3024
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} left
3025
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} right
3026
+ * @param {boolean} [preferArithmetic]
3027
+ */
3028
+ function arithmeticBinaryExpression(left, right, preferArithmetic = false) {
3029
+ return choice(
3030
+ ...binaryOperators()
3031
+ .filter(([, precedence]) => precedence >= PREC.SHIFT)
3032
+ .map(([operator, precedence]) => {
3033
+ const rule = prec.left(
3034
+ precedence,
3035
+ seq(field('left', left), field('operator', operator), field('right', right))
3036
+ );
3037
+ return preferArithmetic && operator !== '>>' && operator !== '>>>' ? prec.dynamic(2, rule) : rule;
3038
+ })
3039
+ );
3040
+ }
3041
+
3042
+ /**
3043
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_name' | 'array_type' | 'function_pointer_type' | 'implicit_type' | 'nullable_type' | 'pointer_type' | 'predefined_type' | 'ref_type' | 'scoped_type' | 'tuple_type'>} $
3044
+ * @param {boolean} [implicit]
3045
+ * @param {boolean} [pointer]
3046
+ * @param {boolean} [tuple]
3047
+ * @param {boolean} [array]
3048
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} [name]
3049
+ */
3050
+ function typeAlternatives($, implicit = true, pointer = true, tuple = true, array = true, name = $._name) {
3051
+ return choice(
3052
+ ...(implicit ? [$.implicit_type] : []),
3053
+ ...(array ? [$.array_type] : []),
3054
+ name,
3055
+ $.nullable_type,
3056
+ ...(pointer ? [$.pointer_type] : []),
3057
+ $.function_pointer_type,
3058
+ $.predefined_type,
3059
+ ...(tuple ? [$.tuple_type] : []),
3060
+ $.ref_type,
3061
+ $.scoped_type
3062
+ );
3063
+ }
3064
+
3065
+ /**
3066
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_parenthesized_pattern_with_designation' | 'and_pattern' | 'declaration_pattern' | 'discard' | 'list_pattern' | 'negated_pattern' | 'or_pattern' | 'parenthesized_pattern' | 'recursive_pattern' | 'relational_pattern' | 'slice_pattern' | 'type_pattern' | 'var_pattern'>} $
3067
+ */
3068
+ function nonconstantPatterns($) {
3069
+ return choice(
3070
+ $.declaration_pattern,
3071
+ $.discard,
3072
+ $.recursive_pattern,
3073
+ $.var_pattern,
3074
+ $.negated_pattern,
3075
+ prec.dynamic(1, alias($._parenthesized_pattern_with_designation, $.recursive_pattern)),
3076
+ $.parenthesized_pattern,
3077
+ $.relational_pattern,
3078
+ $.or_pattern,
3079
+ $.and_pattern,
3080
+ $.list_pattern,
3081
+ $.slice_pattern,
3082
+ $.type_pattern
3083
+ );
3084
+ }
3085
+
3086
+ /**
3087
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'expression' | 'identifier' | 'pattern'>} $
3088
+ * @param {boolean} [named]
3089
+ */
3090
+ function subpattern($, named = false) {
3091
+ const name = choice(seq($.expression, ':'), seq($.identifier, ':'));
3092
+ return seq(named ? name : optional(name), $.pattern);
3093
+ }
3094
+
3095
+ /**
3096
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_pattern_unary_expression' | 'binary_expression' | 'conditional_expression' | 'is_pattern_expression' | 'as_expression' | 'switch_expression' | 'throw_expression' | 'range_expression' | 'with_expression'>} $
3097
+ */
3098
+ function nestedConstantExpressionRoots($) {
3099
+ return [
3100
+ $._pattern_unary_expression,
3101
+ $.binary_expression,
3102
+ $.conditional_expression,
3103
+ $.is_pattern_expression,
3104
+ $.as_expression,
3105
+ $.switch_expression,
3106
+ $.throw_expression,
3107
+ $.range_expression,
3108
+ $.with_expression,
3109
+ ];
3110
+ }
3111
+
3112
+ /**
3113
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_is_arithmetic_binary_expression' | '_is_range_expression' | '_is_switch_expression' | '_is_with_expression' | '_pattern_unary_expression' | 'binary_expression' | 'range_expression' | 'switch_expression' | 'with_expression'>} $
3114
+ */
3115
+ function constantExpressionRoots($) {
3116
+ return [
3117
+ $._pattern_unary_expression,
3118
+ alias($._is_arithmetic_binary_expression, $.binary_expression),
3119
+ alias($._is_range_expression, $.range_expression),
3120
+ alias($._is_switch_expression, $.switch_expression),
3121
+ alias($._is_with_expression, $.with_expression),
3122
+ ];
3123
+ }
3124
+
3125
+ /**
3126
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_switch_expression_body'>} $
3127
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
3128
+ */
3129
+ function switchExpression($, receiver) {
3130
+ return prec(PREC.SWITCH, seq(receiver, 'switch', $._switch_expression_body));
3131
+ }
3132
+
3133
+ /**
3134
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_with_body'>} $
3135
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
3136
+ */
3137
+ function withExpression($, receiver) {
3138
+ return prec.left(PREC.WITH, seq(receiver, 'with', $._with_body));
3139
+ }
3140
+
3141
+ /**
3142
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} left
3143
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} right
3144
+ * @param {boolean} [prefix]
3145
+ */
3146
+ function rangeExpression(left, right, prefix = true) {
3147
+ return prec.right(PREC.RANGE, seq(prefix ? optional(left) : left, '..', optional(right)));
3148
+ }
3149
+
3150
+ /** @param {import('@willbooster/web-tree-sitter/dsl').Rule} operand */
3151
+ function prefixRangeExpression(operand) {
3152
+ return prec.right(PREC.RANGE, seq('..', optional(operand)));
3153
+ }
3154
+
3155
+ function statementEnd() {
3156
+ return choice(';', alias(sym('_statement_end'), ';'));
3157
+ }
3158
+
3159
+ function blockEnd() {
3160
+ return choice('}', alias(sym('_block_end'), '}'));
3161
+ }
3162
+
3163
+ function ampersandOperator() {
3164
+ return alias(sym('_ampersand_operator'), '&');
3165
+ }