@willbooster/tree-sitter-c-sharp 14.1.1 → 14.1.3

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
@@ -11,7 +11,7 @@
11
11
  const { alias, choice, field, grammar, optional, prec, repeat, repeat1, seq, sym, token } =
12
12
  /** @type {typeof globalThis & import('@willbooster/web-tree-sitter/dsl').DSL} */ (globalThis);
13
13
 
14
- /** @typedef {'_preproc_expression' | '_top_level_item_no_statement' | '_namespace_body_item' | '_base_list_mixed_type' | '_base_list_mixed_suffix' | '_base_list_trivia' | '_base_list' | '_base_list_type' | '_base_list_suffix' | '_base_list_prefix' | '_base_list_separator' | '_base_list_separator_path' | '_enum_base_clause' | '_enum_base_type' | 'attribute_list' | 'declaration' | 'enum_member_declaration' | 'expression' | 'method_signature' | 'statement'} PreprocContentRule */
14
+ /** @typedef {'_preproc_expression' | '_top_level_item_no_statement' | '_namespace_body_item' | '_base_list_mixed_type' | '_base_list_mixed_suffix' | '_base_list_trivia' | '_base_list' | '_base_list_type' | '_base_list_suffix' | '_base_list_prefix' | '_base_list_separator' | '_base_list_separator_path' | '_enum_base_clause' | '_enum_base_type' | '_dangling_else_if_statement' | '_object_initializer_element' | '_modified_argument' | '_spread_collection_element' | '_object_member_initializers' | 'argument' | 'attribute_list' | 'collection_element' | 'declaration' | 'enum_member_declaration' | 'expression' | 'if_statement' | 'method_signature' | 'statement' | 'switch_expression_arm'} PreprocContentRule */
15
15
 
16
16
  const PREC = {
17
17
  GENERIC: 19,
@@ -143,6 +143,16 @@ module.exports = grammar({
143
143
  [$._simple_name, $._definite_cast_name],
144
144
  [$._name, $._definite_cast_name],
145
145
  [$._object_initializer_expression, $.initializer_expression],
146
+ [$._object_initializer_element, $.initializer_expression],
147
+ [$._object_initializer_element, sym('preproc_elif_in_initializer')],
148
+ [sym('preproc_elif_in_initializer'), sym('preproc_elif_in_object_initializer')],
149
+ [$._object_initializer_element, sym('preproc_else_in_initializer')],
150
+ [$._object_initializer_element, sym('preproc_if_in_initializer')],
151
+ [sym('preproc_else_in_initializer'), sym('preproc_else_in_object_initializer')],
152
+ [sym('preproc_if_in_initializer'), sym('preproc_if_in_object_initializer')],
153
+ [sym('preproc_elif_in_top_level'), sym('preproc_elif_in_initializer')],
154
+ [sym('preproc_else_in_top_level'), sym('preproc_else_in_initializer')],
155
+ [sym('preproc_if_in_top_level'), sym('preproc_if_in_initializer')],
146
156
  [
147
157
  $._pattern_primary_expression,
148
158
  $._primary_no_conditional_access_expression,
@@ -348,6 +358,7 @@ module.exports = grammar({
348
358
  sym('_pragma_text'),
349
359
  sym('_expression_generic_end'),
350
360
  sym('_definite_expression_generic_end'),
361
+ sym('_if_alternative_directive'),
351
362
  ],
352
363
 
353
364
  extras: ($) => [
@@ -978,16 +989,20 @@ module.exports = grammar({
978
989
 
979
990
  constructor_initializer: ($) => seq(':', choice('base', 'this'), $.argument_list),
980
991
 
981
- argument_list: ($) => seq('(', commaSep($.argument), ')'),
992
+ argument_list: ($) => seq('(', conditionalList($.argument, 'preproc_if_in_argument_list', false), ')'),
982
993
 
983
994
  tuple_pattern: ($) => seq('(', commaSep1(choice(field('name', $.identifier), $.discard, $.tuple_pattern)), ')'),
984
995
 
985
- argument: ($) =>
996
+ argument: ($) => prec(1, seq(optional(seq(field('name', $.identifier), ':')), argumentValue($))),
997
+
998
+ // An argument that a directive branch cannot hold as a bare expression.
999
+ _modified_argument: ($) =>
986
1000
  prec(
987
1001
  1,
988
- seq(
989
- optional(seq(field('name', $.identifier), ':')),
990
- choice(seq(optional(choice('ref', 'out', 'in')), $.expression), seq('out', $.declaration_expression))
1002
+ choice(
1003
+ seq(field('name', $.identifier), ':', argumentValue($)),
1004
+ seq(choice('ref', 'out', 'in'), $.expression),
1005
+ seq('out', $.declaration_expression)
991
1006
  )
992
1007
  ),
993
1008
 
@@ -1456,15 +1471,23 @@ module.exports = grammar({
1456
1471
  if_statement: ($) =>
1457
1472
  prec.right(
1458
1473
  seq(
1459
- 'if',
1460
- '(',
1461
- field('condition', $.expression),
1462
- ')',
1463
- field('consequence', $.statement),
1474
+ $._if_statement_head,
1475
+ repeat(seq(sym('_if_alternative_directive'), alias(sym('preproc_if_in_if_alternative'), sym('preproc_if')))),
1464
1476
  optional(seq('else', field('alternative', $.statement)))
1465
1477
  )
1466
1478
  ),
1467
1479
 
1480
+ _if_statement_head: ($) => seq('if', '(', field('condition', $.expression), ')', field('consequence', $.statement)),
1481
+
1482
+ // An `else` directly before a conditional directive takes the statement after the directive as its body, which a
1483
+ // tree cannot attach across the directive boundary.
1484
+ _dangling_else_if_statement: ($) =>
1485
+ seq(
1486
+ $._if_statement_head,
1487
+ 'else',
1488
+ optional(field('alternative', alias($._dangling_else_if_statement, $.if_statement)))
1489
+ ),
1490
+
1468
1491
  while_statement: ($) => seq('while', '(', field('condition', $.expression), ')', field('body', $.statement)),
1469
1492
 
1470
1493
  local_declaration_statement: ($) =>
@@ -2314,8 +2337,7 @@ module.exports = grammar({
2314
2337
  _switch_expression_body: ($) =>
2315
2338
  seq(
2316
2339
  '{',
2317
- commaSep($.switch_expression_arm),
2318
- optional(','),
2340
+ conditionalList($.switch_expression_arm, 'preproc_if_in_switch_expression'),
2319
2341
  choice('}', alias(sym('_nonprimary_expression_end'), '}'))
2320
2342
  ),
2321
2343
 
@@ -2507,26 +2529,25 @@ module.exports = grammar({
2507
2529
 
2508
2530
  implicit_stackalloc_expression: ($) => seq('stackalloc', '[', ']', $.initializer_expression),
2509
2531
 
2510
- collection_expression: ($) => seq('[', optional(seq(commaSep1($.collection_element), optional(','))), ']'),
2532
+ collection_expression: ($) => seq('[', conditionalList($.collection_element, 'preproc_if_in_collection'), ']'),
2511
2533
 
2512
2534
  collection_element: ($) => choice($.expression_element, $.spread_element),
2513
2535
 
2536
+ _spread_collection_element: ($) => $.spread_element,
2537
+
2514
2538
  expression_element: ($) => prec(1, $.expression),
2515
2539
 
2516
2540
  spread_element: ($) => prec.dynamic(1, prec(PREC.RANGE, seq('..', $.expression))),
2517
2541
 
2518
2542
  _object_initializer_expression: ($) =>
2519
- seq(
2520
- '{',
2521
- commaSep(
2522
- choice(
2523
- alias($._object_index_initializer, $.assignment_expression),
2524
- alias($._object_member_initializer, $.assignment_expression),
2525
- $.expression
2526
- )
2527
- ),
2528
- optional(','),
2529
- '}'
2543
+ seq('{', conditionalList($._object_initializer_element, 'preproc_if_in_object_initializer'), '}'),
2544
+
2545
+ _object_initializer_element: ($) => choice($._object_member_initializers, $.expression),
2546
+
2547
+ _object_member_initializers: ($) =>
2548
+ choice(
2549
+ alias($._object_index_initializer, $.assignment_expression),
2550
+ alias($._object_member_initializer, $.assignment_expression)
2530
2551
  ),
2531
2552
 
2532
2553
  _object_initializer_value: ($) =>
@@ -2544,7 +2565,7 @@ module.exports = grammar({
2544
2565
 
2545
2566
  _object_member_initializer: ($) => assignmentExpression($, $.identifier, '=', $._object_initializer_value),
2546
2567
 
2547
- initializer_expression: ($) => seq('{', commaSep($.expression), optional(','), '}'),
2568
+ initializer_expression: ($) => seq('{', conditionalList($.expression, 'preproc_if_in_initializer'), '}'),
2548
2569
 
2549
2570
  declaration_expression: ($) => prec.dynamic(1, seq(field('type', $.type), field('name', $.identifier))),
2550
2571
 
@@ -2699,8 +2720,31 @@ module.exports = grammar({
2699
2720
  ...preprocIf('_in_base_list_separator', ($) => $._base_list_separator_path, 0, false, true),
2700
2721
  ...preprocIf('_in_base_list_suffix', ($) => $._base_list_suffix, 0, false),
2701
2722
  ...preprocIf('', ($) => $.declaration),
2702
- ...preprocIf('_in_top_level', ($) => choice($._top_level_item_no_statement, $.statement)),
2723
+ ...preprocIf('_in_top_level', ($) => conditionalStatements($), 0, false, true),
2724
+ ...preprocIf('_in_if_alternative', ($) => seq(optional('else'), conditionalStatements($)), 0, false),
2725
+
2703
2726
  ...preprocIf('_in_expression', ($) => $.expression, -2, false),
2727
+ ...conditionalListDirective('_in_initializer', ($) => $.expression),
2728
+ ...conditionalListDirective(
2729
+ '_in_object_initializer',
2730
+ ($) => $._object_initializer_element,
2731
+ ($) => $._object_member_initializers
2732
+ ),
2733
+ ...conditionalListDirective(
2734
+ '_in_collection',
2735
+ ($) => $.collection_element,
2736
+ ($) => alias($._spread_collection_element, $.collection_element)
2737
+ ),
2738
+ ...conditionalListDirective(
2739
+ '_in_argument_list',
2740
+ ($) => $.argument,
2741
+ ($) => alias($._modified_argument, $.argument)
2742
+ ),
2743
+ ...conditionalListDirective(
2744
+ '_in_switch_expression',
2745
+ ($) => $.switch_expression_arm,
2746
+ ($) => $.switch_expression_arm
2747
+ ),
2704
2748
  ...preprocIf('_in_enum_member_declaration', ($) => $.enum_member_declaration, 0, false),
2705
2749
  ...preprocIf('_in_attribute_list', ($) => $.attribute_list, -1, false),
2706
2750
 
@@ -3110,6 +3154,25 @@ function preprocIf(suffix, content, precedence = 0, rep = true, required = false
3110
3154
  };
3111
3155
  }
3112
3156
 
3157
+ /**
3158
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<'declaration_expression' | 'expression'>} $
3159
+ */
3160
+ function argumentValue($) {
3161
+ return choice(seq(optional(choice('ref', 'out', 'in')), $.expression), seq('out', $.declaration_expression));
3162
+ }
3163
+
3164
+ /**
3165
+ * Statements of a conditional branch, where the last may be an if statement whose `else` body follows the directive.
3166
+ *
3167
+ * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<PreprocContentRule>} $
3168
+ */
3169
+ function conditionalStatements($) {
3170
+ return seq(
3171
+ repeat(choice($._top_level_item_no_statement, $.statement)),
3172
+ optional(alias($._dangling_else_if_statement, $.if_statement))
3173
+ );
3174
+ }
3175
+
3113
3176
  /**
3114
3177
  * @param {'if' | 'elif'} command
3115
3178
  * @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<PreprocContentRule>} $
@@ -3306,6 +3369,68 @@ function nullableQuestion() {
3306
3369
  return choice(alias(sym('_question_nullable'), '?'), alias(sym('_question_unknown'), '?'));
3307
3370
  }
3308
3371
 
3372
+ /**
3373
+ * Comma-separated elements, optionally with a trailing comma, where conditional directives may enclose whole elements
3374
+ * together with their commas.
3375
+ *
3376
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral} element
3377
+ * @param {string} directive
3378
+ * @param {boolean} trailingComma
3379
+ */
3380
+ function conditionalList(element, directive, trailingComma = true) {
3381
+ const items = repeat(conditionalListItem(element, directive));
3382
+ const conditional = alias(sym(directive), sym('preproc_if'));
3383
+ return trailingComma
3384
+ ? seq(items, optional(element))
3385
+ : optional(seq(items, choice(element, seq(optional(element), conditional))));
3386
+ }
3387
+
3388
+ /**
3389
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral} element
3390
+ * @param {string} directive
3391
+ */
3392
+ function conditionalListItem(element, directive) {
3393
+ return choice(seq(element, ','), seq(optional(element), alias(sym(directive), sym('preproc_if')), optional(',')));
3394
+ }
3395
+
3396
+ /**
3397
+ * Conditional directive rules for a comma-separated list. The `#if` branch alone decides between this rule and the
3398
+ * expression-level directive, so only `#elif` and `#else` branches may hold a single expression.
3399
+ *
3400
+ * @param {string} suffix
3401
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleBuilder<PreprocContentRule>} element
3402
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleBuilder<PreprocContentRule>} [single]
3403
+ * @returns {Record<string, import('@willbooster/web-tree-sitter/dsl').RuleBuilder<PreprocContentRule>>}
3404
+ */
3405
+ function conditionalListDirective(suffix, element, single) {
3406
+ const directive = 'preproc_if' + suffix;
3407
+ const rules = preprocIf(suffix, ($) => conditionalListContent(element($), directive, single?.($)), 0, false);
3408
+ /** @param {import('@willbooster/web-tree-sitter/dsl').GrammarSymbols<PreprocContentRule>} $ */
3409
+ const alternativeContent = ($) => choice(conditionalListContent(element($), directive), element($));
3410
+ const alternatives = Object.entries(preprocIf(suffix, alternativeContent, 0, false)).filter(
3411
+ ([name]) => !name.startsWith('preproc_if')
3412
+ );
3413
+ return { ...rules, ...Object.fromEntries(alternatives) };
3414
+ }
3415
+
3416
+ /**
3417
+ * The elements of a conditional branch, which may start with the comma after the preceding element and contain nested
3418
+ * conditional groups. A single expression without commas is left to the expression-level directive, which lets an
3419
+ * operator after the directive continue it.
3420
+ *
3421
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral} element
3422
+ * @param {string} directive
3423
+ * @param {import('@willbooster/web-tree-sitter/dsl').RuleOrLiteral} [single] a single element without commas that cannot be an
3424
+ * expression
3425
+ */
3426
+ function conditionalListContent(element, directive, single) {
3427
+ return choice(
3428
+ seq(',', conditionalList(element, directive)),
3429
+ seq(repeat1(conditionalListItem(element, directive)), optional(element)),
3430
+ ...(single ? [single] : [])
3431
+ );
3432
+ }
3433
+
3309
3434
  /**
3310
3435
  * @param {import('@willbooster/web-tree-sitter/dsl').Rule} rule
3311
3436
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@willbooster/tree-sitter-c-sharp",
3
- "version": "14.1.1",
3
+ "version": "14.1.3",
4
4
  "description": "C# grammar for tree-sitter",
5
5
  "keywords": [
6
6
  "incremental",
@@ -231,6 +231,13 @@
231
231
  (member_binding_expression name: (generic_name (identifier) @variable.member))
232
232
  ]
233
233
 
234
+ ;; Object initializer members inside conditional directives (alternative branches are omitted because each nested
235
+ ;; pattern through `preproc_elif` or `preproc_else` adds noticeable query compilation time)
236
+
237
+ (object_creation_expression initializer: (initializer_expression (preproc_if (assignment_expression left: (identifier) @variable.member))))
238
+ (implicit_object_creation_expression (initializer_expression (preproc_if (assignment_expression left: (identifier) @variable.member))))
239
+ (assignment_expression right: (initializer_expression (preproc_if (assignment_expression left: (identifier) @variable.member))))
240
+
234
241
  ;; Calls
235
242
 
236
243
  (invocation_expression
@@ -808,6 +808,10 @@
808
808
  {
809
809
  "type": "argument",
810
810
  "named": true
811
+ },
812
+ {
813
+ "type": "preproc_if",
814
+ "named": true
811
815
  }
812
816
  ]
813
817
  }
@@ -2089,6 +2093,10 @@
2089
2093
  {
2090
2094
  "type": "collection_element",
2091
2095
  "named": true
2096
+ },
2097
+ {
2098
+ "type": "preproc_if",
2099
+ "named": true
2092
2100
  }
2093
2101
  ]
2094
2102
  }
@@ -4122,6 +4130,16 @@
4122
4130
  }
4123
4131
  ]
4124
4132
  }
4133
+ },
4134
+ "children": {
4135
+ "multiple": true,
4136
+ "required": false,
4137
+ "types": [
4138
+ {
4139
+ "type": "preproc_if",
4140
+ "named": true
4141
+ }
4142
+ ]
4125
4143
  }
4126
4144
  },
4127
4145
  {
@@ -6294,6 +6312,10 @@
6294
6312
  "multiple": true,
6295
6313
  "required": false,
6296
6314
  "types": [
6315
+ {
6316
+ "type": "argument",
6317
+ "named": true
6318
+ },
6297
6319
  {
6298
6320
  "type": "argument_list",
6299
6321
  "named": true
@@ -6306,6 +6328,10 @@
6306
6328
  "type": "base_list",
6307
6329
  "named": true
6308
6330
  },
6331
+ {
6332
+ "type": "collection_element",
6333
+ "named": true
6334
+ },
6309
6335
  {
6310
6336
  "type": "declaration",
6311
6337
  "named": true
@@ -6338,6 +6364,10 @@
6338
6364
  "type": "statement",
6339
6365
  "named": true
6340
6366
  },
6367
+ {
6368
+ "type": "switch_expression_arm",
6369
+ "named": true
6370
+ },
6341
6371
  {
6342
6372
  "type": "type_declaration",
6343
6373
  "named": true
@@ -6374,6 +6404,10 @@
6374
6404
  "multiple": true,
6375
6405
  "required": false,
6376
6406
  "types": [
6407
+ {
6408
+ "type": "argument",
6409
+ "named": true
6410
+ },
6377
6411
  {
6378
6412
  "type": "argument_list",
6379
6413
  "named": true
@@ -6386,6 +6420,10 @@
6386
6420
  "type": "base_list",
6387
6421
  "named": true
6388
6422
  },
6423
+ {
6424
+ "type": "collection_element",
6425
+ "named": true
6426
+ },
6389
6427
  {
6390
6428
  "type": "declaration",
6391
6429
  "named": true
@@ -6418,6 +6456,10 @@
6418
6456
  "type": "statement",
6419
6457
  "named": true
6420
6458
  },
6459
+ {
6460
+ "type": "switch_expression_arm",
6461
+ "named": true
6462
+ },
6421
6463
  {
6422
6464
  "type": "type_declaration",
6423
6465
  "named": true
@@ -6535,6 +6577,10 @@
6535
6577
  "multiple": true,
6536
6578
  "required": false,
6537
6579
  "types": [
6580
+ {
6581
+ "type": "argument",
6582
+ "named": true
6583
+ },
6538
6584
  {
6539
6585
  "type": "argument_list",
6540
6586
  "named": true
@@ -6543,6 +6589,10 @@
6543
6589
  "type": "base_list",
6544
6590
  "named": true
6545
6591
  },
6592
+ {
6593
+ "type": "collection_element",
6594
+ "named": true
6595
+ },
6546
6596
  {
6547
6597
  "type": "declaration",
6548
6598
  "named": true
@@ -6575,6 +6625,10 @@
6575
6625
  "type": "statement",
6576
6626
  "named": true
6577
6627
  },
6628
+ {
6629
+ "type": "switch_expression_arm",
6630
+ "named": true
6631
+ },
6578
6632
  {
6579
6633
  "type": "type_declaration",
6580
6634
  "named": true
Binary file
package/tree-sitter.json CHANGED
@@ -19,6 +19,7 @@
19
19
  "external-files": [
20
20
  "src/genericExpressions.h",
21
21
  "src/identifierCharacters.h",
22
+ "src/ifAlternativeDirective.h",
22
23
  "src/nullableRank.h",
23
24
  "src/nullableTypes.h",
24
25
  "src/questionContext.h",
@@ -30,7 +31,7 @@
30
31
  }
31
32
  ],
32
33
  "metadata": {
33
- "version": "14.1.1",
34
+ "version": "14.1.3",
34
35
  "license": "MIT",
35
36
  "description": "C# grammar for tree-sitter",
36
37
  "authors": [