@willbooster/tree-sitter-c-sharp 5.0.2 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/grammar.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,63 +1373,80 @@ 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
1451
  relational_pattern: ($) =>
1137
1452
  choice(seq('<', $.expression), seq('<=', $.expression), seq('>', $.expression), seq('>=', $.expression)),
@@ -1139,179 +1454,145 @@ module.exports = grammar({
1139
1454
  negated_pattern: ($) => seq('not', $.pattern),
1140
1455
 
1141
1456
  and_pattern: ($) =>
1142
- prec.left(PREC.AND, seq(field('left', $.pattern), field('operator', 'and'), field('right', $.pattern))),
1457
+ prec.dynamic(
1458
+ 2,
1459
+ prec.left(PREC.AND, seq(field('left', $.pattern), field('operator', 'and'), field('right', $.pattern)))
1460
+ ),
1143
1461
 
1144
1462
  or_pattern: ($) =>
1145
- prec.left(PREC.OR, seq(field('left', $.pattern), field('operator', 'or'), field('right', $.pattern))),
1463
+ prec.dynamic(
1464
+ 2,
1465
+ prec.left(PREC.OR, seq(field('left', $.pattern), field('operator', 'or'), field('right', $.pattern)))
1466
+ ),
1146
1467
 
1147
- declaration_pattern: ($) => seq(field('type', $.type), $._simple_designation),
1468
+ declaration_pattern: ($) => seq(field('type', $._pattern_declaration_type), $._simple_designation),
1148
1469
 
1149
1470
  _variable_designation: ($) => choice($._simple_designation, $.parenthesized_variable_designation),
1150
1471
 
1151
1472
  // C# admits a parenthesized designation in a pattern only after `var`; elsewhere `T (x)` and `nameof(x)` are
1152
1473
  // positional patterns or invocations.
1153
- _simple_designation: ($) => prec(1, choice($.discard, field('name', $.identifier))),
1474
+ _simple_designation: ($) =>
1475
+ prec(
1476
+ 1,
1477
+ choice(
1478
+ $.discard,
1479
+ field('name', $.identifier),
1480
+ prec.dynamic(-2, field('name', alias(choice('and', 'or'), $.identifier)))
1481
+ )
1482
+ ),
1154
1483
 
1155
1484
  parenthesized_variable_designation: ($) => seq('(', commaSep($._variable_designation), ')'),
1156
1485
 
1157
- expression: ($) => choice($.non_lvalue_expression, $.lvalue_expression),
1158
-
1159
- non_lvalue_expression: ($) =>
1486
+ expression: ($) =>
1160
1487
  choice(
1161
- 'base',
1488
+ $._unary_expression,
1489
+ $.assignment_expression,
1162
1490
  $.binary_expression,
1163
- $.interpolated_string_expression,
1164
1491
  $.conditional_expression,
1165
- $.conditional_access_expression,
1166
- $.literal,
1167
- $._expression_statement_expression,
1168
- $.is_expression,
1169
1492
  $.is_pattern_expression,
1170
1493
  $.as_expression,
1171
- $.cast_expression,
1172
- $.checked_expression,
1173
- $.collection_expression,
1174
1494
  $.switch_expression,
1175
1495
  $.throw_expression,
1176
- $.default_expression,
1177
1496
  $.lambda_expression,
1178
1497
  $.with_expression,
1179
- $.sizeof_expression,
1180
- $.typeof_expression,
1181
- $.makeref_expression,
1182
1498
  $.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
1499
  $.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
1500
  $.initializer_expression,
1196
- $.query_expression,
1197
- alias(sym('preproc_if_in_expression'), sym('preproc_if'))
1501
+ $.query_expression
1198
1502
  ),
1199
1503
 
1200
- lvalue_expression: ($) =>
1504
+ _unary_expression: ($) =>
1505
+ choice($._primary_expression, $.prefix_unary_expression, $.cast_expression, $.await_expression),
1506
+
1507
+ _primary_expression: ($) =>
1201
1508
  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
1509
+ $._primary_no_conditional_access_expression,
1510
+ $.conditional_access_expression,
1511
+ alias($._conditional_suppression_expression, $.postfix_unary_expression)
1213
1512
  ),
1214
1513
 
1215
- // Covers error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement
1216
- _expression_statement_expression: ($) =>
1514
+ _nonconditional_unary_expression: ($) =>
1217
1515
  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
1516
+ $._primary_no_conditional_access_expression,
1517
+ alias($._assignment_target_prefix_unary_expression, $.prefix_unary_expression),
1518
+ alias($._assignment_target_cast_expression, $.cast_expression),
1519
+ alias($._assignment_target_await_expression, $.await_expression)
1225
1520
  ),
1226
1521
 
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)
1522
+ _assignment_target_unary_operand: ($) =>
1523
+ choice(
1524
+ $._nonconditional_unary_expression,
1525
+ alias($._assignment_target_prefix_range_expression, $.range_expression)
1241
1526
  ),
1242
1527
 
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
- ),
1528
+ _assignment_target_prefix_unary_expression: ($) => prefixUnaryExpression($._assignment_target_unary_operand),
1264
1529
 
1265
- _pointer_prefix_update: ($) =>
1266
- prec(
1267
- PREC.UNARY,
1268
- seq(choice('++', '--'), choice($.lvalue_expression, $.invocation_expression, $.parenthesized_expression))
1530
+ _assignment_target_cast_expression: ($) =>
1531
+ castExpression(
1532
+ $,
1533
+ $._nonconditional_unary_expression,
1534
+ alias($._assignment_target_prefix_range_expression, $.range_expression)
1269
1535
  ),
1270
1536
 
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
- )
1537
+ _assignment_target_prefix_range_expression: ($) => prefixRangeExpression($._assignment_target_unary_operand),
1538
+
1539
+ _assignment_target_await_expression: ($) =>
1540
+ prec.right(PREC.UNARY, seq('await', $._assignment_target_unary_operand)),
1541
+
1542
+ _conditional_suppression_expression: ($) =>
1543
+ postfixExpression(
1544
+ choice(
1545
+ $.conditional_access_expression,
1546
+ alias($._conditional_suppression_expression, $.postfix_unary_expression)
1547
+ ),
1548
+ bangOperator()
1290
1549
  ),
1291
1550
 
1551
+ _conditional_update_expression: ($) =>
1552
+ postfixExpression(
1553
+ choice(
1554
+ $.conditional_access_expression,
1555
+ alias($._conditional_suppression_expression, $.postfix_unary_expression)
1556
+ ),
1557
+ choice('++', '--')
1558
+ ),
1559
+
1560
+ _primary_no_conditional_access_expression: ($) =>
1561
+ primaryAtoms($, { name: $._simple_name, member: $.member_access_expression, collection: true }),
1562
+
1563
+ _conditional_access_receiver: ($) =>
1564
+ primaryAtoms($, {
1565
+ name: $._simple_name,
1566
+ member: $.member_access_expression,
1567
+ collection: true,
1568
+ element: $.element_access_expression,
1569
+ invocation: $.invocation_expression,
1570
+ tuple: true,
1571
+ array: alias($._initialized_array_creation_expression, $.array_creation_expression),
1572
+ stackalloc: alias($._initialized_stackalloc_expression, $.stackalloc_expression),
1573
+ definite: false,
1574
+ }),
1575
+
1576
+ _definite_conditional_access_receiver: ($) =>
1577
+ primaryAtoms($, {
1578
+ name: $._simple_name,
1579
+ member: $.member_access_expression,
1580
+ collection: true,
1581
+ element: $.element_access_expression,
1582
+ invocation: $.invocation_expression,
1583
+ tuple: true,
1584
+ array: alias($._initialized_array_creation_expression, $.array_creation_expression),
1585
+ stackalloc: alias($._initialized_stackalloc_expression, $.stackalloc_expression),
1586
+ definite: true,
1587
+ }),
1588
+
1589
+ _expression_statement_expression: ($) => choice($._unary_expression, $.assignment_expression),
1590
+
1591
+ assignment_expression: ($) => assignmentExpression($, $._nonconditional_unary_expression),
1592
+
1292
1593
  binary_expression: ($) =>
1293
1594
  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]) =>
1595
+ ...binaryOperators().map(([operator, precedence]) =>
1315
1596
  prec.left(
1316
1597
  precedence,
1317
1598
  seq(field('left', $.expression), field('operator', operator), field('right', $.expression))
@@ -1323,80 +1604,13 @@ module.exports = grammar({
1323
1604
  )
1324
1605
  ),
1325
1606
 
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
- )
1607
+ postfix_unary_expression: ($) =>
1608
+ choice(
1609
+ postfixExpression($._primary_no_conditional_access_expression, choice('++', '--', bangOperator())),
1610
+ $._generic_invocation_suppression_expression
1389
1611
  ),
1390
1612
 
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)))),
1613
+ prefix_unary_expression: ($) => prefixUnaryExpression($._unary_operand),
1400
1614
 
1401
1615
  query_expression: ($) => seq($.from_clause, $._query_body),
1402
1616
 
@@ -1434,65 +1648,352 @@ module.exports = grammar({
1434
1648
  PREC.CONDITIONAL,
1435
1649
  seq(
1436
1650
  field('condition', $.expression),
1437
- '?',
1651
+ ternaryQuestion(),
1438
1652
  field('consequence', $.expression),
1439
1653
  ':',
1654
+ sym('_conditional_alternative_start'),
1440
1655
  field('alternative', $.expression)
1441
1656
  )
1442
1657
  ),
1443
1658
 
1444
1659
  conditional_access_expression: ($) =>
1445
- prec.right(
1446
- PREC.CONDITIONAL,
1660
+ choice(
1661
+ $._conditional_assignment_expression,
1662
+ conditionalAccessExpression($, $._conditional_access_receiver),
1447
1663
  seq(
1448
- field('condition', $.expression),
1449
- '?',
1450
- choice($.member_binding_expression, alias($.bracketed_argument_list, sym('element_binding_expression')))
1664
+ field('condition', $._definite_conditional_access_receiver),
1665
+ definiteAccessQuestion(),
1666
+ field('consequence', $._conditional_access_consequence)
1667
+ ),
1668
+ seq(
1669
+ field('condition', $.array_creation_expression),
1670
+ memberAccessQuestion(),
1671
+ field('consequence', $._member_conditional_access_consequence)
1451
1672
  )
1452
1673
  ),
1453
1674
 
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))),
1675
+ _member_conditional_access_consequence: ($) => $._member_conditional_binding_expression,
1459
1676
 
1460
- is_pattern_expression: ($) =>
1461
- prec(PREC.REL, seq(field('expression', $.expression), 'is', field('pattern', $.pattern))),
1677
+ _member_conditional_binding_expression: ($) =>
1678
+ choice(
1679
+ $._member_nonconditional_binding_expression,
1680
+ alias($._member_binding_conditional_access_expression, $.conditional_access_expression)
1681
+ ),
1462
1682
 
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
- )
1683
+ _member_nonconditional_binding_expression: ($) =>
1684
+ choice(
1685
+ $.member_binding_expression,
1686
+ alias($._member_binding_member_access_expression, $.member_access_expression),
1687
+ alias($._member_binding_element_access_expression, $.element_access_expression),
1688
+ alias($._member_binding_invocation_expression, $.invocation_expression)
1476
1689
  ),
1477
1690
 
1691
+ _member_conditional_binding_receiver: ($) =>
1692
+ choice(
1693
+ $._member_nonconditional_binding_expression,
1694
+ alias($._member_binding_suppression_expression, $.postfix_unary_expression),
1695
+ alias($._member_binding_generic_suppression_expression, $.postfix_unary_expression)
1696
+ ),
1697
+
1698
+ _member_binding_suppression_expression: ($) =>
1699
+ postfixExpression($._member_conditional_binding_receiver, bangOperator()),
1700
+
1701
+ _member_binding_member_access_expression: ($) => memberAccessExpression($, $._member_conditional_binding_receiver),
1702
+
1703
+ _member_binding_element_access_expression: ($) =>
1704
+ elementAccessExpression($, $._member_conditional_binding_receiver),
1705
+
1706
+ _member_binding_invocation_expression: ($) =>
1707
+ choice(
1708
+ invocationExpression($, $._member_conditional_binding_receiver),
1709
+ $._member_binding_generic_invocation_expression
1710
+ ),
1711
+
1712
+ _member_binding_generic_invocation_expression: ($) =>
1713
+ genericInvocationExpression(
1714
+ $,
1715
+ choice(
1716
+ alias($._generic_member_binding_expression, $.member_binding_expression),
1717
+ alias($._member_binding_generic_member_expression, $.member_access_expression)
1718
+ ),
1719
+ $._member_binding_generic_invocation_expression,
1720
+ $._member_binding_generic_suppression_expression
1721
+ ),
1722
+
1723
+ _member_binding_generic_member_expression: ($) =>
1724
+ memberAccessExpression($, $._member_conditional_binding_receiver, $._generic_invocation_simple_name),
1725
+
1726
+ _member_binding_generic_suppression_expression: ($) =>
1727
+ seq(
1728
+ genericInvocationReceiver(
1729
+ $,
1730
+ $._member_binding_generic_invocation_expression,
1731
+ $._member_binding_generic_suppression_expression
1732
+ ),
1733
+ bangOperator()
1734
+ ),
1735
+
1736
+ _member_binding_conditional_access_expression: ($) =>
1737
+ conditionalAccessExpression($, $._member_conditional_binding_receiver),
1738
+
1739
+ _member_conditional_binding_assignment_expression: ($) =>
1740
+ assignmentExpression($, $._member_conditional_binding_receiver),
1741
+
1742
+ _conditional_access_consequence: ($) => $._conditional_binding_expression,
1743
+
1744
+ _conditional_binding_expression: ($) =>
1745
+ choice(
1746
+ $._nonconditional_binding_expression,
1747
+ alias($._binding_conditional_access_expression, $.conditional_access_expression)
1748
+ ),
1749
+
1750
+ _nonconditional_binding_expression: ($) =>
1751
+ choice(
1752
+ $.member_binding_expression,
1753
+ alias($.bracketed_argument_list, sym('element_binding_expression')),
1754
+ alias($._binding_member_access_expression, $.member_access_expression),
1755
+ alias($._binding_element_access_expression, $.element_access_expression),
1756
+ alias($._binding_invocation_expression, $.invocation_expression)
1757
+ ),
1758
+
1759
+ _conditional_binding_receiver: ($) =>
1760
+ choice(
1761
+ $._nonconditional_binding_expression,
1762
+ alias($._binding_suppression_expression, $.postfix_unary_expression),
1763
+ alias($._binding_generic_suppression_expression, $.postfix_unary_expression)
1764
+ ),
1765
+
1766
+ _binding_suppression_expression: ($) => postfixExpression($._conditional_binding_receiver, bangOperator()),
1767
+
1768
+ _binding_member_access_expression: ($) => memberAccessExpression($, $._conditional_binding_receiver),
1769
+
1770
+ _binding_element_access_expression: ($) => elementAccessExpression($, $._conditional_binding_receiver),
1771
+
1772
+ _binding_invocation_expression: ($) =>
1773
+ choice(invocationExpression($, $._conditional_binding_receiver), $._binding_generic_invocation_expression),
1774
+
1775
+ _binding_generic_invocation_expression: ($) =>
1776
+ genericInvocationExpression(
1777
+ $,
1778
+ choice(
1779
+ alias($._generic_member_binding_expression, $.member_binding_expression),
1780
+ alias($._binding_generic_member_expression, $.member_access_expression)
1781
+ ),
1782
+ $._binding_generic_invocation_expression,
1783
+ $._binding_generic_suppression_expression
1784
+ ),
1785
+
1786
+ _binding_generic_member_expression: ($) =>
1787
+ memberAccessExpression($, $._conditional_binding_receiver, $._generic_invocation_simple_name),
1788
+
1789
+ _binding_generic_suppression_expression: ($) =>
1790
+ seq(
1791
+ genericInvocationReceiver(
1792
+ $,
1793
+ $._binding_generic_invocation_expression,
1794
+ $._binding_generic_suppression_expression
1795
+ ),
1796
+ bangOperator()
1797
+ ),
1798
+
1799
+ _binding_conditional_access_expression: ($) => conditionalAccessExpression($, $._conditional_binding_receiver),
1800
+
1801
+ _conditional_binding_assignment_expression: ($) => assignmentExpression($, $._conditional_binding_receiver),
1802
+
1803
+ _conditional_assignment_expression: ($) =>
1804
+ choice(
1805
+ seq(
1806
+ field('condition', $._conditional_access_receiver),
1807
+ accessQuestion(),
1808
+ field('consequence', $._conditional_assignment_consequence)
1809
+ ),
1810
+ seq(
1811
+ field('condition', $._definite_conditional_access_receiver),
1812
+ definiteAccessQuestion(),
1813
+ field('consequence', $._conditional_assignment_consequence)
1814
+ ),
1815
+ seq(
1816
+ field('condition', $.array_creation_expression),
1817
+ memberAccessQuestion(),
1818
+ field('consequence', $._member_conditional_assignment_consequence)
1819
+ )
1820
+ ),
1821
+
1822
+ _conditional_assignment_consequence: ($) =>
1823
+ choice(
1824
+ alias($._conditional_binding_assignment_expression, $.assignment_expression),
1825
+ alias($._binding_conditional_assignment_expression, $.conditional_access_expression)
1826
+ ),
1827
+
1828
+ _member_conditional_assignment_consequence: ($) =>
1829
+ choice(
1830
+ alias($._member_conditional_binding_assignment_expression, $.assignment_expression),
1831
+ alias($._member_binding_conditional_assignment_expression, $.conditional_access_expression)
1832
+ ),
1833
+
1834
+ _binding_conditional_assignment_expression: ($) =>
1835
+ seq(
1836
+ field('condition', $._conditional_binding_receiver),
1837
+ accessQuestion(),
1838
+ field('consequence', $._conditional_assignment_consequence)
1839
+ ),
1840
+
1841
+ _member_binding_conditional_assignment_expression: ($) =>
1842
+ seq(
1843
+ field('condition', $._member_conditional_binding_receiver),
1844
+ accessQuestion(),
1845
+ field('consequence', $._conditional_assignment_consequence)
1846
+ ),
1847
+
1848
+ _postfix_receiver: ($) =>
1849
+ choice(
1850
+ $._primary_no_conditional_access_expression,
1851
+ alias($._conditional_assignment_expression, $.conditional_access_expression)
1852
+ ),
1853
+
1854
+ _conditional_assignment_suppression_expression: ($) =>
1855
+ postfixExpression(
1856
+ choice(
1857
+ alias($._conditional_assignment_expression, $.conditional_access_expression),
1858
+ alias($._conditional_assignment_suppression_expression, $.postfix_unary_expression)
1859
+ ),
1860
+ bangOperator()
1861
+ ),
1862
+
1863
+ as_expression: ($) =>
1864
+ prec(
1865
+ PREC.REL,
1866
+ seq(
1867
+ field('left', $.expression),
1868
+ field('operator', alias(sym('_type_context_as'), 'as')),
1869
+ field('right', $.type)
1870
+ )
1871
+ ),
1872
+
1873
+ is_pattern_expression: ($) =>
1874
+ prec(
1875
+ PREC.REL,
1876
+ seq(
1877
+ field('expression', $.expression),
1878
+ alias(sym('_type_context_is'), 'is'),
1879
+ field('pattern', alias($._is_pattern, $.pattern))
1880
+ )
1881
+ ),
1882
+
1883
+ // C# treats a non-generic terminal name followed by a nonempty collection as parenthesized indexing.
1884
+ cast_expression: ($) =>
1885
+ castExpression($, $._non_range_unary_operand, alias($._prefix_range_expression, $.range_expression)),
1886
+
1887
+ _non_range_unary_operand: ($) => choice($._unary_expression, $.query_expression),
1888
+
1889
+ _unary_operand: ($) => choice($._non_range_unary_operand, alias($._prefix_range_expression, $.range_expression)),
1890
+
1891
+ _prefix_range_expression: ($) => prefixRangeExpression($._unary_operand),
1892
+
1893
+ _range_cast_type: ($) =>
1894
+ choice(
1895
+ typeAlternatives($, false, true, false, false, $.alias_qualified_name),
1896
+ alias($._omitted_cast_array_type, $.array_type)
1897
+ ),
1898
+
1899
+ _omitted_cast_array_type: ($) =>
1900
+ seq(
1901
+ field('type', $._array_base_type),
1902
+ field('rank', alias($._omitted_array_rank_specifier, $.array_rank_specifier))
1903
+ ),
1904
+
1905
+ _omitted_array_rank_specifier: () => seq('[', repeat(','), ']'),
1906
+
1907
+ _ambiguous_cast_type: ($) => $._ambiguous_cast_name,
1908
+
1909
+ _definite_cast_type: ($) =>
1910
+ choice(
1911
+ typeAlternatives($, false, true, true, false, $._definite_cast_name),
1912
+ alias($._omitted_cast_array_type, $.array_type)
1913
+ ),
1914
+
1915
+ _preferred_cast_head: ($) =>
1916
+ choice(
1917
+ prec.dynamic(
1918
+ 2,
1919
+ seq('(', field('type', alias($._ambiguous_cast_type, $.type)), alias(sym('_ambiguous_cast_type_end'), ')'))
1920
+ ),
1921
+ prec.dynamic(
1922
+ 3,
1923
+ seq(
1924
+ '(',
1925
+ field('type', alias($._omitted_cast_array_type, $.array_type)),
1926
+ alias(sym('_definite_cast_type_end'), ')')
1927
+ )
1928
+ )
1929
+ ),
1930
+
1931
+ _preferred_range_cast_head: ($) =>
1932
+ prec.dynamic(
1933
+ 3,
1934
+ seq(
1935
+ '(',
1936
+ field('type', alias($._omitted_cast_array_type, $.array_type)),
1937
+ alias(sym('_range_cast_type_end'), ')')
1938
+ )
1939
+ ),
1940
+
1941
+ _ambiguous_cast_name: ($) => choice($.identifier, alias($._ambiguous_cast_qualified_name, $.qualified_name)),
1942
+
1943
+ _ambiguous_cast_qualified_name: ($) => seq(field('qualifier', $._name), '.', field('name', $.identifier)),
1944
+
1945
+ _definite_cast_name: ($) =>
1946
+ choice($.generic_name, $.alias_qualified_name, alias($._definite_cast_qualified_name, $.qualified_name)),
1947
+
1948
+ _definite_cast_qualified_name: ($) => seq(field('qualifier', $._name), '.', field('name', $.generic_name)),
1949
+
1478
1950
  checked_expression: ($) => seq(choice('checked', 'unchecked'), '(', $.expression, ')'),
1479
1951
 
1480
1952
  invocation_expression: ($) =>
1481
- prec(PREC.INVOCATION, seq(field('function', postfixOperand($)), field('arguments', $.argument_list))),
1953
+ choice(invocationExpression($, $._postfix_receiver), $._generic_invocation_expression),
1954
+
1955
+ _generic_invocation_expression: ($) =>
1956
+ genericInvocationExpression(
1957
+ $,
1958
+ choice(
1959
+ $._generic_invocation_simple_name,
1960
+ alias($._pattern_generic_member_expression, $.member_access_expression),
1961
+ alias($._generic_alias_qualified_name, $.alias_qualified_name)
1962
+ ),
1963
+ $._generic_invocation_expression,
1964
+ $._generic_invocation_suppression_expression
1965
+ ),
1482
1966
 
1483
- switch_expression: ($) => prec(PREC.SWITCH, seq($.expression, 'switch', $._switch_expression_body)),
1484
- _switch_expression_body: ($) => seq('{', commaSep($.switch_expression_arm), optional(','), '}'),
1967
+ _generic_member_binding_expression: ($) => seq('.', field('name', $._generic_invocation_simple_name)),
1968
+
1969
+ _generic_invocation_simple_name: ($) => $.generic_name,
1970
+
1971
+ _generic_alias_qualified_name: ($) => seq(field('alias', $.identifier), '::', field('name', $.generic_name)),
1972
+
1973
+ _generic_invocation_suppression_expression: ($) =>
1974
+ postfixExpression(
1975
+ genericInvocationReceiver($, $._generic_invocation_expression, $._generic_invocation_suppression_expression),
1976
+ bangOperator()
1977
+ ),
1978
+
1979
+ switch_expression: ($) => switchExpression($, $.expression),
1980
+ _switch_expression_body: ($) =>
1981
+ seq(
1982
+ '{',
1983
+ commaSep($.switch_expression_arm),
1984
+ optional(','),
1985
+ choice('}', alias(sym('_nonprimary_expression_end'), '}'))
1986
+ ),
1485
1987
 
1486
1988
  switch_expression_arm: ($) => seq($.pattern, optional($.when_clause), '=>', $.expression),
1487
1989
 
1488
1990
  when_clause: ($) => seq('when', $.expression),
1489
1991
 
1490
- await_expression: ($) => prec.right(PREC.UNARY, seq('await', $.expression)),
1992
+ await_expression: ($) => prec.right(PREC.UNARY, seq('await', $._unary_operand)),
1491
1993
 
1492
1994
  throw_expression: ($) => seq('throw', $.expression),
1493
1995
 
1494
- element_access_expression: ($) =>
1495
- prec(PREC.POSTFIX, seq(field('expression', postfixOperand($)), field('subscript', $.bracketed_argument_list))),
1996
+ element_access_expression: ($) => elementAccessExpression($, $._postfix_receiver),
1496
1997
 
1497
1998
  interpolated_string_expression: ($) =>
1498
1999
  choice(
@@ -1545,7 +2046,10 @@ module.exports = grammar({
1545
2046
  interpolation_alignment_clause: ($) => seq(',', $.expression),
1546
2047
 
1547
2048
  interpolation_format_clause: () =>
1548
- seq(':', optional(sym('_file_directive_literal_context')), token.immediate(/[^}"\n\r\u0085\u2028\u2029]+/)),
2049
+ prec.dynamic(
2050
+ 1,
2051
+ seq(':', optional(sym('_file_directive_literal_context')), token.immediate(/[^}"\n\r\u0085\u2028\u2029]+/))
2052
+ ),
1549
2053
 
1550
2054
  _multiline_interpolation: ($) =>
1551
2055
  seq(
@@ -1556,17 +2060,10 @@ module.exports = grammar({
1556
2060
  alias(sym('interpolation_close_brace'), sym('interpolation_brace'))
1557
2061
  ),
1558
2062
 
1559
- _multiline_interpolation_format_clause: () => seq(':', optional(sym('_file_directive_literal_context')), /[^}"]+/),
2063
+ _multiline_interpolation_format_clause: () =>
2064
+ prec.dynamic(1, seq(':', optional(sym('_file_directive_literal_context')), /[^}"]+/)),
1560
2065
 
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
- ),
2066
+ member_access_expression: ($) => memberAccessExpression($, choice($._postfix_receiver, $.predefined_type, $._name)),
1570
2067
 
1571
2068
  member_binding_expression: ($) => seq('.', field('name', $._simple_name)),
1572
2069
 
@@ -1574,17 +2071,20 @@ module.exports = grammar({
1574
2071
  prec.right(
1575
2072
  seq(
1576
2073
  'new',
1577
- field('type', $.type),
1578
- field('arguments', optional($.argument_list)),
1579
- field('initializer', optional($.initializer_expression))
2074
+ field('type', $._object_creation_type),
2075
+ choice(
2076
+ seq(
2077
+ field('arguments', $.argument_list),
2078
+ field('initializer', optional(alias($._object_initializer_expression, $.initializer_expression)))
2079
+ ),
2080
+ field('initializer', alias($._object_initializer_expression, $.initializer_expression))
2081
+ )
1580
2082
  )
1581
2083
  ),
1582
2084
 
1583
- _object_creation_type: ($) => choice($._name, $.nullable_type, $.predefined_type),
1584
-
1585
- parenthesized_expression: ($) => seq('(', $.non_lvalue_expression, ')'),
2085
+ _object_creation_type: ($) => typeAlternatives($, true, true, true, false),
1586
2086
 
1587
- _parenthesized_lvalue_expression: ($) => seq('(', $.lvalue_expression, ')'),
2087
+ parenthesized_expression: ($) => seq('(', $.expression, ')'),
1588
2088
 
1589
2089
  lambda_expression: ($) =>
1590
2090
  prec(-1, seq($._lambda_expression_init, '=>', field('body', choice($.block, $.expression)))),
@@ -1634,8 +2134,11 @@ module.exports = grammar({
1634
2134
  ')'
1635
2135
  ),
1636
2136
 
1637
- array_creation_expression: ($) =>
1638
- prec.dynamic(PREC.UNARY, seq('new', field('type', $.array_type), optional($.initializer_expression))),
2137
+ array_creation_expression: ($) => arrayCreationExpression($, optional($.initializer_expression)),
2138
+
2139
+ _initialized_array_creation_expression: ($) => arrayCreationExpression($, $.initializer_expression),
2140
+
2141
+ _initialized_stackalloc_expression: ($) => stackallocExpression($, $.initializer_expression),
1639
2142
 
1640
2143
  anonymous_method_expression: ($) =>
1641
2144
  seq(
@@ -1653,7 +2156,9 @@ module.exports = grammar({
1653
2156
  implicit_array_creation_expression: ($) => seq('new', '[', repeat(','), ']', $.initializer_expression),
1654
2157
 
1655
2158
  implicit_object_creation_expression: ($) =>
1656
- prec.right(seq('new', $.argument_list, optional($.initializer_expression))),
2159
+ prec.right(
2160
+ seq('new', $.argument_list, optional(alias($._object_initializer_expression, $.initializer_expression)))
2161
+ ),
1657
2162
 
1658
2163
  implicit_stackalloc_expression: ($) => seq('stackalloc', '[', ']', $.initializer_expression),
1659
2164
 
@@ -1665,14 +2170,44 @@ module.exports = grammar({
1665
2170
 
1666
2171
  spread_element: ($) => prec.dynamic(1, prec(PREC.RANGE, seq('..', $.expression))),
1667
2172
 
2173
+ _object_initializer_expression: ($) =>
2174
+ seq(
2175
+ '{',
2176
+ commaSep(
2177
+ choice(
2178
+ alias($._object_index_initializer, $.assignment_expression),
2179
+ alias($._object_member_initializer, $.assignment_expression),
2180
+ $.expression
2181
+ )
2182
+ ),
2183
+ optional(','),
2184
+ '}'
2185
+ ),
2186
+
2187
+ _object_initializer_value: ($) =>
2188
+ choice($.expression, alias($._object_initializer_expression, $.initializer_expression)),
2189
+
2190
+ _object_index_initializer: ($) =>
2191
+ assignmentExpression(
2192
+ $,
2193
+ alias($._object_index_target, sym('element_binding_expression')),
2194
+ '=',
2195
+ $._object_initializer_value
2196
+ ),
2197
+
2198
+ _object_index_target: ($) => bracketedArgumentList($, alias(sym('_object_index_start'), '[')),
2199
+
2200
+ _object_member_initializer: ($) => assignmentExpression($, $.identifier, '=', $._object_initializer_value),
2201
+
1668
2202
  initializer_expression: ($) => seq('{', commaSep($.expression), optional(','), '}'),
1669
2203
 
1670
2204
  declaration_expression: ($) => prec.dynamic(1, seq(field('type', $.type), field('name', $.identifier))),
1671
2205
 
1672
2206
  default_expression: ($) => prec.right(seq('default', optional(seq('(', field('type', $.type), ')')))),
1673
2207
 
1674
- with_expression: ($) => prec.left(PREC.WITH, seq($.expression, 'with', $._with_body)),
1675
- _with_body: ($) => seq('{', commaSep($.with_initializer), optional(','), '}'),
2208
+ with_expression: ($) => withExpression($, $.expression),
2209
+ _with_body: ($) =>
2210
+ seq('{', commaSep($.with_initializer), optional(','), choice('}', alias(sym('_nonprimary_expression_end'), '}'))),
1676
2211
 
1677
2212
  with_initializer: ($) => seq($.identifier, '=', $.expression),
1678
2213
 
@@ -1688,10 +2223,9 @@ module.exports = grammar({
1688
2223
 
1689
2224
  refvalue_expression: ($) => seq('__refvalue', '(', field('value', $.expression), ',', field('type', $.type), ')'),
1690
2225
 
1691
- stackalloc_expression: ($) =>
1692
- prec.left(seq('stackalloc', field('type', $.array_type), optional($.initializer_expression))),
2226
+ stackalloc_expression: ($) => stackallocExpression($, optional($.initializer_expression)),
1693
2227
 
1694
- range_expression: ($) => prec.right(PREC.RANGE, seq(optional($.expression), '..', optional($.expression))),
2228
+ range_expression: ($) => rangeExpression($.expression, $.expression),
1695
2229
 
1696
2230
  tuple_expression: ($) => seq('(', commaSep2(alias($._tuple_argument, $.argument)), ')'),
1697
2231
 
@@ -1779,47 +2313,7 @@ module.exports = grammar({
1779
2313
  ),
1780
2314
  identifier: ($) => choice($._identifier_token, $._reserved_identifier),
1781
2315
 
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
- ),
2316
+ _reserved_identifier: () => choice(...reservedIdentifiers()),
1823
2317
 
1824
2318
  ...preprocIf(
1825
2319
  '_in_method_signature',
@@ -1857,7 +2351,7 @@ module.exports = grammar({
1857
2351
  preproc_parenthesized_expression: ($) => seq('(', $._preproc_expression, ')'),
1858
2352
 
1859
2353
  preproc_unary_expression: ($) =>
1860
- prec.left(PREC.UNARY, seq(field('operator', '!'), field('argument', $._preproc_expression))),
2354
+ prec.left(PREC.UNARY, seq(field('operator', bangOperator()), field('argument', $._preproc_expression))),
1861
2355
 
1862
2356
  preproc_binary_expression: ($) => {
1863
2357
  /** @type {[string, number][]} */
@@ -2163,25 +2657,192 @@ function preprocIf(suffix, content, precedence = 0, rep = true, required = false
2163
2657
  }
2164
2658
 
2165
2659
  /**
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}
2660
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_simple_name'>} $
2661
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
2662
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} [name]
2663
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral} [operator]
2664
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2174
2665
  */
2175
- function postfixOperand($) {
2666
+ function memberAccessExpression($, receiver, name = $._simple_name, operator = choice('.', '->')) {
2667
+ return prec(PREC.DOT, seq(field('expression', receiver), operator, field('name', name)));
2668
+ }
2669
+
2670
+ /**
2671
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'bracketed_argument_list'>} $
2672
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
2673
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2674
+ */
2675
+ function elementAccessExpression($, receiver) {
2676
+ return prec(PREC.DOT, seq(field('expression', receiver), field('subscript', $.bracketed_argument_list)));
2677
+ }
2678
+
2679
+ /**
2680
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'argument_list'>} $
2681
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
2682
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2683
+ */
2684
+ function invocationExpression($, receiver) {
2685
+ return prec(PREC.INVOCATION, seq(field('function', receiver), field('arguments', $.argument_list)));
2686
+ }
2687
+
2688
+ /**
2689
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'argument_list' | 'invocation_expression' | 'postfix_unary_expression'>} $
2690
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} first
2691
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} call
2692
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} suppression
2693
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2694
+ */
2695
+ function genericInvocationExpression($, first, call, suppression) {
2176
2696
  return choice(
2177
- $.expression,
2178
- $.lvalue_expression,
2179
- $.invocation_expression,
2180
- $.postfix_unary_expression,
2181
- $.parenthesized_expression
2697
+ prec.dynamic(1, invocationExpression($, first)),
2698
+ prec.dynamic(3, invocationExpression($, genericInvocationReceiver($, call, suppression)))
2699
+ );
2700
+ }
2701
+
2702
+ /**
2703
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'invocation_expression' | 'postfix_unary_expression'>} $
2704
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} call
2705
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} suppression
2706
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2707
+ */
2708
+ function genericInvocationReceiver($, call, suppression) {
2709
+ return choice(alias(call, $.invocation_expression), alias(suppression, $.postfix_unary_expression));
2710
+ }
2711
+
2712
+ /**
2713
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} operand
2714
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2715
+ */
2716
+ function prefixUnaryExpression(operand) {
2717
+ return prec.right(
2718
+ PREC.UNARY,
2719
+ choice(
2720
+ seq(choice('++', '--', bangOperator(), '~'), operand),
2721
+ prec.dynamic(-2, seq(choice('+', '-', '^', '*', ampersandOperator()), operand))
2722
+ )
2723
+ );
2724
+ }
2725
+
2726
+ /**
2727
+ * @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'>} $
2728
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} operand
2729
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} [rangeOperand]
2730
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2731
+ */
2732
+ function castExpression($, operand, rangeOperand) {
2733
+ return prec(
2734
+ PREC.CAST,
2735
+ prec.dynamic(
2736
+ 1,
2737
+ choice(
2738
+ seq(
2739
+ '(',
2740
+ field('type', alias($._ambiguous_cast_type, $.type)),
2741
+ ')',
2742
+ sym('_ambiguous_cast_operand_start'),
2743
+ field('value', operand)
2744
+ ),
2745
+ seq('(', field('type', alias($._definite_cast_type, $.type)), ')', field('value', operand)),
2746
+ seq($._preferred_cast_head, field('value', operand)),
2747
+ ...(rangeOperand
2748
+ ? [
2749
+ seq('(', field('type', alias($._range_cast_type, $.type)), ')', field('value', rangeOperand)),
2750
+ seq($._preferred_range_cast_head, field('value', rangeOperand)),
2751
+ ]
2752
+ : [])
2753
+ )
2754
+ )
2755
+ );
2756
+ }
2757
+
2758
+ /**
2759
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_conditional_access_consequence'>} $
2760
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
2761
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2762
+ */
2763
+ function conditionalAccessExpression($, receiver) {
2764
+ return seq(field('condition', receiver), accessQuestion(), field('consequence', $._conditional_access_consequence));
2765
+ }
2766
+
2767
+ /**
2768
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
2769
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral} operator
2770
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2771
+ */
2772
+ function postfixExpression(receiver, operator) {
2773
+ return prec(PREC.POSTFIX, seq(receiver, operator));
2774
+ }
2775
+
2776
+ /**
2777
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'expression'>} $
2778
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
2779
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral} [operator]
2780
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} [value]
2781
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2782
+ */
2783
+ function assignmentExpression(
2784
+ $,
2785
+ receiver,
2786
+ operator = choice('=', '+=', '-=', '*=', '/=', '%=', '&=', '^=', '|=', '<<=', '>>=', '>>>=', '??='),
2787
+ value = $.expression
2788
+ ) {
2789
+ return prec.right(PREC.ASSIGN, seq(field('left', receiver), field('operator', operator), field('right', value)));
2790
+ }
2791
+
2792
+ /**
2793
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'array_type'>} $
2794
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} initializer
2795
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2796
+ */
2797
+ function arrayCreationExpression($, initializer) {
2798
+ return prec.dynamic(PREC.UNARY, seq('new', field('type', $.array_type), initializer));
2799
+ }
2800
+
2801
+ /**
2802
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'type'>} $
2803
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} initializer
2804
+ * @returns {import('@willbooster/web-tree-sitter/dsl').Rule}
2805
+ */
2806
+ function stackallocExpression($, initializer) {
2807
+ return prec.left(seq('stackalloc', field('type', $.type), initializer));
2808
+ }
2809
+
2810
+ /**
2811
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'argument'>} $
2812
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral} opener
2813
+ */
2814
+ function bracketedArgumentList($, opener) {
2815
+ return seq(opener, commaSep1($.argument), optional(','), ']');
2816
+ }
2817
+
2818
+ function bangOperator() {
2819
+ return alias(sym('_bang_operator'), '!');
2820
+ }
2821
+
2822
+ function definiteAccessQuestion() {
2823
+ return choice(alias(sym('_question_definite_access'), '?'), alias(sym('_question_unknown'), '?'));
2824
+ }
2825
+
2826
+ function accessQuestion() {
2827
+ return choice(
2828
+ alias(sym('_question_member_access'), '?'),
2829
+ alias(sym('_question_element_access'), '?'),
2830
+ alias(sym('_question_unknown'), '?')
2182
2831
  );
2183
2832
  }
2184
2833
 
2834
+ function memberAccessQuestion() {
2835
+ return choice(alias(sym('_question_member_access'), '?'), alias(sym('_question_unknown'), '?'));
2836
+ }
2837
+
2838
+ function ternaryQuestion() {
2839
+ return choice(alias(sym('_question_ternary'), '?'), alias(sym('_question_unknown'), '?'));
2840
+ }
2841
+
2842
+ function nullableQuestion() {
2843
+ return choice(alias(sym('_question_nullable'), '?'), alias(sym('_question_unknown'), '?'));
2844
+ }
2845
+
2185
2846
  /**
2186
2847
  * @param {import('@willbooster/web-tree-sitter/dsl').Rule} rule
2187
2848
  *
@@ -2230,3 +2891,276 @@ function sep1(rule, separator) {
2230
2891
  function sep(rule, separator) {
2231
2892
  return optional(sep1(rule, separator));
2232
2893
  }
2894
+
2895
+ function binaryOperators() {
2896
+ /** @type {[import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral, number][]} */
2897
+ const operators = [
2898
+ ['&&', PREC.LOGICAL_AND],
2899
+ ['||', PREC.LOGICAL_OR],
2900
+ ['>>', PREC.SHIFT],
2901
+ ['>>>', PREC.SHIFT],
2902
+ ['<<', PREC.SHIFT],
2903
+ [ampersandOperator(), PREC.AND],
2904
+ ['^', PREC.XOR],
2905
+ ['|', PREC.OR],
2906
+ ['+', PREC.ADD],
2907
+ ['-', PREC.ADD],
2908
+ ['*', PREC.MULT],
2909
+ ['/', PREC.MULT],
2910
+ ['%', PREC.MULT],
2911
+ ['<', PREC.REL],
2912
+ ['<=', PREC.REL],
2913
+ ['==', PREC.EQUAL],
2914
+ ['!=', PREC.EQUAL],
2915
+ ['>=', PREC.REL],
2916
+ ['>', PREC.REL],
2917
+ ];
2918
+ return operators;
2919
+ }
2920
+
2921
+ /**
2922
+ * @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'>} $
2923
+ * @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
2924
+ */
2925
+ function primaryAtoms(
2926
+ $,
2927
+ {
2928
+ name,
2929
+ member,
2930
+ collection,
2931
+ element = $.element_access_expression,
2932
+ invocation = $.invocation_expression,
2933
+ parenthesized = $.parenthesized_expression,
2934
+ tuple = true,
2935
+ array = $.array_creation_expression,
2936
+ stackalloc = $.stackalloc_expression,
2937
+ definite,
2938
+ }
2939
+ ) {
2940
+ const uncertain = [
2941
+ ...(name ? [name] : []),
2942
+ member,
2943
+ element,
2944
+ invocation,
2945
+ ...(tuple ? [$.tuple_expression] : []),
2946
+ parenthesized,
2947
+ ...(collection ? [$.collection_expression] : []),
2948
+ alias(sym('preproc_if_in_expression'), sym('preproc_if')),
2949
+ ];
2950
+ const completed = [
2951
+ alias($._nameof_expression, $.invocation_expression),
2952
+ alias($._conditional_update_expression, $.postfix_unary_expression),
2953
+ alias($._conditional_assignment_suppression_expression, $.postfix_unary_expression),
2954
+ 'this',
2955
+ 'base',
2956
+ $.postfix_unary_expression,
2957
+ $.literal,
2958
+ $.interpolated_string_expression,
2959
+ $.checked_expression,
2960
+ $.default_expression,
2961
+ $.sizeof_expression,
2962
+ $.typeof_expression,
2963
+ $.makeref_expression,
2964
+ $.reftype_expression,
2965
+ $.refvalue_expression,
2966
+ stackalloc,
2967
+ array,
2968
+ $.object_creation_expression,
2969
+ $.anonymous_method_expression,
2970
+ $.anonymous_object_creation_expression,
2971
+ $.implicit_array_creation_expression,
2972
+ $.implicit_object_creation_expression,
2973
+ $.implicit_stackalloc_expression,
2974
+ ];
2975
+ return choice(...(definite === true ? [] : uncertain), ...(definite === false ? [] : completed));
2976
+ }
2977
+
2978
+ function reservedIdentifiers() {
2979
+ return [
2980
+ prec(-1, '_'),
2981
+ 'alias',
2982
+ 'async',
2983
+ 'ascending',
2984
+ 'by',
2985
+ 'descending',
2986
+ 'equals',
2987
+ // attribute_target_specifier keywords — contextual only when followed
2988
+ // by `:` in `[target: Attr]` position. Anywhere else they're
2989
+ // identifiers. Without listing them here the LR table preferred the
2990
+ // literal-keyword interpretation, breaking `[type]`, `[field]`, etc.
2991
+ // as collection_expression elements. Excludes `'event'` and `'return'`
2992
+ // from the attribute_target_specifier choice — those are real C#
2993
+ // keywords and must not be accepted as identifiers anywhere else.
2994
+ 'field',
2995
+ 'file',
2996
+ 'from',
2997
+ 'global',
2998
+ 'group',
2999
+ 'into',
3000
+ 'join',
3001
+ 'let',
3002
+ 'method',
3003
+ 'nameof',
3004
+ 'nint',
3005
+ 'nuint',
3006
+ 'notnull',
3007
+ 'on',
3008
+ 'orderby',
3009
+ 'param',
3010
+ 'partial',
3011
+ 'property',
3012
+ 'scoped',
3013
+ 'select',
3014
+ 'type',
3015
+ 'typevar',
3016
+ 'unmanaged',
3017
+ 'var',
3018
+ 'when',
3019
+ 'where',
3020
+ 'yield',
3021
+ ];
3022
+ }
3023
+
3024
+ /**
3025
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} left
3026
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} right
3027
+ * @param {boolean} [preferArithmetic]
3028
+ */
3029
+ function arithmeticBinaryExpression(left, right, preferArithmetic = false) {
3030
+ return choice(
3031
+ ...binaryOperators()
3032
+ .filter(([, precedence]) => precedence >= PREC.SHIFT)
3033
+ .map(([operator, precedence]) => {
3034
+ const rule = prec.left(
3035
+ precedence,
3036
+ seq(field('left', left), field('operator', operator), field('right', right))
3037
+ );
3038
+ return preferArithmetic && operator !== '>>' && operator !== '>>>' ? prec.dynamic(2, rule) : rule;
3039
+ })
3040
+ );
3041
+ }
3042
+
3043
+ /**
3044
+ * @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'>} $
3045
+ * @param {boolean} [implicit]
3046
+ * @param {boolean} [pointer]
3047
+ * @param {boolean} [tuple]
3048
+ * @param {boolean} [array]
3049
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} [name]
3050
+ */
3051
+ function typeAlternatives($, implicit = true, pointer = true, tuple = true, array = true, name = $._name) {
3052
+ return choice(
3053
+ ...(implicit ? [$.implicit_type] : []),
3054
+ ...(array ? [$.array_type] : []),
3055
+ name,
3056
+ $.nullable_type,
3057
+ ...(pointer ? [$.pointer_type] : []),
3058
+ $.function_pointer_type,
3059
+ $.predefined_type,
3060
+ ...(tuple ? [$.tuple_type] : []),
3061
+ $.ref_type,
3062
+ $.scoped_type
3063
+ );
3064
+ }
3065
+
3066
+ /**
3067
+ * @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'>} $
3068
+ */
3069
+ function nonconstantPatterns($) {
3070
+ return choice(
3071
+ $.declaration_pattern,
3072
+ $.discard,
3073
+ $.recursive_pattern,
3074
+ $.var_pattern,
3075
+ $.negated_pattern,
3076
+ prec.dynamic(1, alias($._parenthesized_pattern_with_designation, $.recursive_pattern)),
3077
+ $.parenthesized_pattern,
3078
+ $.relational_pattern,
3079
+ $.or_pattern,
3080
+ $.and_pattern,
3081
+ $.list_pattern,
3082
+ $.slice_pattern,
3083
+ $.type_pattern
3084
+ );
3085
+ }
3086
+
3087
+ /**
3088
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'expression' | 'identifier' | 'pattern'>} $
3089
+ * @param {boolean} [named]
3090
+ */
3091
+ function subpattern($, named = false) {
3092
+ const name = choice(seq($.expression, ':'), seq($.identifier, ':'));
3093
+ return seq(named ? name : optional(name), $.pattern);
3094
+ }
3095
+
3096
+ /**
3097
+ * @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'>} $
3098
+ */
3099
+ function nestedConstantExpressionRoots($) {
3100
+ return [
3101
+ $._pattern_unary_expression,
3102
+ $.binary_expression,
3103
+ $.conditional_expression,
3104
+ $.is_pattern_expression,
3105
+ $.as_expression,
3106
+ $.switch_expression,
3107
+ $.throw_expression,
3108
+ $.range_expression,
3109
+ $.with_expression,
3110
+ ];
3111
+ }
3112
+
3113
+ /**
3114
+ * @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'>} $
3115
+ */
3116
+ function constantExpressionRoots($) {
3117
+ return [
3118
+ $._pattern_unary_expression,
3119
+ alias($._is_arithmetic_binary_expression, $.binary_expression),
3120
+ alias($._is_range_expression, $.range_expression),
3121
+ alias($._is_switch_expression, $.switch_expression),
3122
+ alias($._is_with_expression, $.with_expression),
3123
+ ];
3124
+ }
3125
+
3126
+ /**
3127
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_switch_expression_body'>} $
3128
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
3129
+ */
3130
+ function switchExpression($, receiver) {
3131
+ return prec(PREC.SWITCH, seq(receiver, 'switch', $._switch_expression_body));
3132
+ }
3133
+
3134
+ /**
3135
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'_with_body'>} $
3136
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} receiver
3137
+ */
3138
+ function withExpression($, receiver) {
3139
+ return prec.left(PREC.WITH, seq(receiver, 'with', $._with_body));
3140
+ }
3141
+
3142
+ /**
3143
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} left
3144
+ * @param {import('@willbooster/web-tree-sitter/dsl').Rule} right
3145
+ * @param {boolean} [prefix]
3146
+ */
3147
+ function rangeExpression(left, right, prefix = true) {
3148
+ return prec.right(PREC.RANGE, seq(prefix ? optional(left) : left, '..', optional(right)));
3149
+ }
3150
+
3151
+ /** @param {import('@willbooster/web-tree-sitter/dsl').Rule} operand */
3152
+ function prefixRangeExpression(operand) {
3153
+ return prec.right(PREC.RANGE, seq('..', optional(operand)));
3154
+ }
3155
+
3156
+ function statementEnd() {
3157
+ return choice(';', alias(sym('_statement_end'), ';'));
3158
+ }
3159
+
3160
+ function blockEnd() {
3161
+ return choice('}', alias(sym('_block_end'), '}'));
3162
+ }
3163
+
3164
+ function ampersandOperator() {
3165
+ return alias(sym('_ampersand_operator'), '&');
3166
+ }