@willbooster/tree-sitter-c-sharp 1.0.8 → 1.0.9

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/README.md CHANGED
@@ -27,8 +27,9 @@ The grammar is based upon the Roslyn grammar with changes in order to:
27
27
  Known gaps:
28
28
 
29
29
  - `async`, `var` and `await` cannot be used as identifiers everywhere they are valid
30
- - A pointer dereference can be assigned to only when its operand is a variable, member access, element access,
31
- or another dereference (`*p = 1`, `*(p) = 1`, `*a.b = 1`); `*(int*)p = 1` and `*(p + 1) = 1` are not recognized
30
+ - A pointer dereference can be assigned to only when its operand is a variable, an address, a parenthesized or
31
+ postfix expression, or a cast of one of these or of an invocation (`*p = 1`, `*(p + 1) = 1`, `*(int*)p = 1`,
32
+ `*dst++ = 1`); `*++p = 1` and `*f() = 1` are not recognized
32
33
  - File-based apps preprocessor directives (`#:property`, `#:package`, `#:sdk`, `#:project`) are not yet recognized
33
34
 
34
35
  ## Usage
package/grammar.js CHANGED
@@ -1007,9 +1007,10 @@ module.exports = grammar({
1007
1007
  _name_invocation_pattern: ($) => seq(field('function', $._name), field('arguments', $.argument_list)),
1008
1008
 
1009
1009
  // Invocation where function is not a simple name
1010
+ // One above `invocation_expression`, which reads the same tokens where both fit.
1010
1011
  _complex_invocation_expression: ($) =>
1011
1012
  prec(
1012
- PREC.INVOCATION,
1013
+ PREC.INVOCATION + 1,
1013
1014
  seq(
1014
1015
  field(
1015
1016
  'function',
@@ -1242,7 +1243,7 @@ module.exports = grammar({
1242
1243
  )
1243
1244
  ),
1244
1245
 
1245
- postfix_unary_expression: ($) => prec(PREC.POSTFIX, seq($.expression, choice('++', '--', '!'))),
1246
+ postfix_unary_expression: ($) => prec(PREC.POSTFIX, seq(postfixOperand($), choice('++', '--', '!'))),
1246
1247
 
1247
1248
  prefix_unary_expression: ($) =>
1248
1249
  prec(
@@ -1260,35 +1261,69 @@ module.exports = grammar({
1260
1261
  )
1261
1262
  ),
1262
1263
 
1263
- // Pointer indirection is split by its operand. Dereferencing an lvalue
1264
- // (`*p`, `*(p)`, `**pp`) yields an lvalue, so it is surfaced in
1265
- // `lvalue_expression` and can be assigned to. Dereferencing any other
1266
- // expression (`*(long*)&v`, `*(p + 1)`) is only read: surfacing it in
1267
- // `lvalue_expression` too would let `=` follow every expression that can
1268
- // be its operand, which grows the parser from 8,495 to 13,339 states.
1264
+ // Pointer indirection is split by its operand. The assignable form, surfaced in `lvalue_expression`, takes an
1265
+ // lvalue (`*p`, `*(p)`, `**pp`) or an operand that ends in a closing token or an lvalue: a parenthesized
1266
+ // expression (`*(p + 1)`), a postfix expression (`*p++`), an address (`*&v`), or a cast of an lvalue, a
1267
+ // parenthesized, postfix, or invocation expression, or an address (`*(int*)p`, `*(long*)(p + 4)`, `*(T*)f()`,
1268
+ // `*(long*)&v`). Dereferencing any other expression (`*++p`) is only read: letting any expression be the assignable
1269
+ // form's operand lets `=` follow every expression that can be the operand, which grows the parser by about 4,800
1270
+ // states and nearly doubles the Wasm build, while these operands add about 550.
1269
1271
  //
1270
- // A parenthesized expression followed by `*` is a multiplication, not a
1271
- // cast of a dereference (C# spec §12.9.8 Cast expressions: `(a) * b` is
1272
- // a cast only when `a` cannot be an expression), so a dereference's
1273
- // penalty outweighs the cast's +1. `*(p) + 1` is likewise the sum of a
1274
- // dereference of `(p)` (-2), not a dereference of a cast of `+1`
1275
- // (-4 + 1), so dereferencing a non-lvalue carries the larger penalty.
1276
- _pointer_indirection_expression: ($) => prec.dynamic(-2, prec.right(PREC.UNARY, seq('*', $.lvalue_expression))),
1272
+ // Dynamic precedences: an assignable dereference -2, a read-only one -4, a read-only cast +1, and an assignable cast
1273
+ // -1. C# reads a parenthesized name as a cast only when the token after `)` is `~`, `!`, `(`, an identifier, a
1274
+ // literal, or a keyword (C# spec §12.9.8 Cast expressions), and these values keep that reading: `(a) * b` is a
1275
+ // multiplication (0), not a cast of `*b` (+1 - 2); `*(p) + 1` and `*(p) & x` apply to a dereference of `(p)` (-2),
1276
+ // not to a dereference of a cast of `+1` or `&x` (-4 + 1 or -2 - 1); `*(b)[0]` dereferences an element access
1277
+ // (-2), not a cast of `[0]` (-2 - 1). Where both casts fit, they give the same tree.
1278
+ _pointer_indirection_expression: ($) =>
1279
+ prec.dynamic(
1280
+ -2,
1281
+ prec.right(
1282
+ PREC.UNARY,
1283
+ seq(
1284
+ '*',
1285
+ choice(
1286
+ $.lvalue_expression,
1287
+ $.parenthesized_expression,
1288
+ alias($._address_of_expression, $.prefix_unary_expression),
1289
+ alias($._lvalue_cast_expression, $.cast_expression),
1290
+ $.postfix_unary_expression
1291
+ )
1292
+ )
1293
+ )
1294
+ ),
1295
+
1296
+ _lvalue_cast_expression: ($) =>
1297
+ prec(
1298
+ PREC.CAST,
1299
+ prec.dynamic(
1300
+ -1,
1301
+ seq(
1302
+ '(',
1303
+ field('type', $.type),
1304
+ ')',
1305
+ field(
1306
+ 'value',
1307
+ choice(
1308
+ $.lvalue_expression,
1309
+ $.parenthesized_expression,
1310
+ alias($._address_of_expression, $.prefix_unary_expression),
1311
+ $.postfix_unary_expression,
1312
+ $.invocation_expression
1313
+ )
1314
+ )
1315
+ )
1316
+ )
1317
+ ),
1277
1318
 
1278
1319
  _value_indirection_expression: ($) => prec.dynamic(-4, prec.right(PREC.UNARY, seq('*', $.non_lvalue_expression))),
1279
1320
 
1280
- // Address-of is split out from `prefix_unary_expression` so that
1281
- // `&` can't act as a fallback when the lexer would otherwise
1282
- // emit `&&`. Its operand is restricted to an lvalue (same shape
1283
- // as the spec's `address-of-expression`). This is the fix for
1284
- // tree-sitter#413: `(a) && (b > 0)` was misparsed as
1285
- // `cast(a, &(&(b > 0)))` because the cast state accepted `&` as
1286
- // a unary start and the lexer split `&&` into two `&` tokens.
1287
- // With this split, `&` is only valid before an lvalue, which
1288
- // `(b > 0)` is not — so the cast interpretation can no longer
1289
- // consume the trailing parenthesized expression and `&&` must
1290
- // be emitted as a single token for the binary path to succeed.
1291
- _address_of_expression: ($) => prec.right(PREC.UNARY, seq('&', $.lvalue_expression)),
1321
+ // Address-of is split out from `prefix_unary_expression` and takes only a variable: an lvalue, or an invocation,
1322
+ // which can return a reference (`&span.GetPinnableReference()`). If a cast could take `&` before any expression,
1323
+ // the lexer would split `&&` into two `&` tokens and `(a) && (b > 0)` would read as a cast of `&(&(b > 0))`; as
1324
+ // `(b > 0)` is not a variable, that reading fails and `&&` stays one token.
1325
+ _address_of_expression: ($) =>
1326
+ prec.right(PREC.UNARY, seq('&', choice($.lvalue_expression, $.invocation_expression))),
1292
1327
 
1293
1328
  query_expression: ($) => seq($.from_clause, $._query_body),
1294
1329
 
@@ -1370,7 +1405,7 @@ module.exports = grammar({
1370
1405
  checked_expression: ($) => seq(choice('checked', 'unchecked'), '(', $.expression, ')'),
1371
1406
 
1372
1407
  invocation_expression: ($) =>
1373
- prec(PREC.INVOCATION, seq(field('function', $.expression), field('arguments', $.argument_list))),
1408
+ prec(PREC.INVOCATION, seq(field('function', postfixOperand($)), field('arguments', $.argument_list))),
1374
1409
 
1375
1410
  switch_expression: ($) => prec(PREC.SWITCH, seq($.expression, 'switch', $._switch_expression_body)),
1376
1411
  _switch_expression_body: ($) => seq('{', commaSep($.switch_expression_arm), optional(','), '}'),
@@ -1384,7 +1419,7 @@ module.exports = grammar({
1384
1419
  throw_expression: ($) => seq('throw', $.expression),
1385
1420
 
1386
1421
  element_access_expression: ($) =>
1387
- prec(PREC.POSTFIX, seq(field('expression', $.expression), field('subscript', $.bracketed_argument_list))),
1422
+ prec(PREC.POSTFIX, seq(field('expression', postfixOperand($)), field('subscript', $.bracketed_argument_list))),
1388
1423
 
1389
1424
  interpolated_string_expression: ($) =>
1390
1425
  choice(
@@ -1434,7 +1469,7 @@ module.exports = grammar({
1434
1469
  prec(
1435
1470
  PREC.DOT,
1436
1471
  seq(
1437
- field('expression', choice($.expression, $.predefined_type, $._name)),
1472
+ field('expression', choice(postfixOperand($), $.predefined_type, $._name)),
1438
1473
  choice('.', '->'),
1439
1474
  field('name', $._simple_name)
1440
1475
  )
@@ -1855,6 +1890,26 @@ function preprocIf(suffix, content, precedence = 0, rep = true) {
1855
1890
  };
1856
1891
  }
1857
1892
 
1893
+ /**
1894
+ * The operand of a postfix operator, an invocation, an element access, or a member access. Besides `expression`, it
1895
+ * lists the forms that are operands of `&`, of the assignable `*`, or of the assignable cast: reaching them only
1896
+ * through `expression` would reduce the unary operator or the cast (precedence UNARY or CAST) before `expression`
1897
+ * (precedence 0) lets the postfix operator apply, reading `&a[0]` as `(&a)[0]` and `*(T*)f()[0]` as `(*(T*)f())[0]`.
1898
+ *
1899
+ * @param {GrammarSymbols<string>} $
1900
+ *
1901
+ * @returns {ChoiceRule}
1902
+ */
1903
+ function postfixOperand($) {
1904
+ return choice(
1905
+ $.expression,
1906
+ $.lvalue_expression,
1907
+ $.invocation_expression,
1908
+ $.postfix_unary_expression,
1909
+ $.parenthesized_expression
1910
+ );
1911
+ }
1912
+
1858
1913
  /**
1859
1914
  * Creates a rule to match one or more of the rules separated by a comma
1860
1915
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@willbooster/tree-sitter-c-sharp",
3
- "version": "1.0.8",
3
+ "version": "1.0.9",
4
4
  "description": "C# grammar for tree-sitter",
5
5
  "keywords": [
6
6
  "incremental",
@@ -1511,6 +1511,14 @@
1511
1511
  {
1512
1512
  "type": "expression",
1513
1513
  "named": true
1514
+ },
1515
+ {
1516
+ "type": "invocation_expression",
1517
+ "named": true
1518
+ },
1519
+ {
1520
+ "type": "postfix_unary_expression",
1521
+ "named": true
1514
1522
  }
1515
1523
  ]
1516
1524
  }
@@ -2316,6 +2324,14 @@
2316
2324
  {
2317
2325
  "type": "expression",
2318
2326
  "named": true
2327
+ },
2328
+ {
2329
+ "type": "invocation_expression",
2330
+ "named": true
2331
+ },
2332
+ {
2333
+ "type": "postfix_unary_expression",
2334
+ "named": true
2319
2335
  }
2320
2336
  ]
2321
2337
  },
@@ -3449,36 +3465,16 @@
3449
3465
  "type": "cast_expression",
3450
3466
  "named": true
3451
3467
  },
3452
- {
3453
- "type": "conditional_access_expression",
3454
- "named": true
3455
- },
3456
- {
3457
- "type": "element_access_expression",
3458
- "named": true
3459
- },
3460
3468
  {
3461
3469
  "type": "expression",
3462
3470
  "named": true
3463
3471
  },
3464
- {
3465
- "type": "generic_name",
3466
- "named": true
3467
- },
3468
- {
3469
- "type": "identifier",
3470
- "named": true
3471
- },
3472
3472
  {
3473
3473
  "type": "invocation_expression",
3474
3474
  "named": true
3475
3475
  },
3476
3476
  {
3477
- "type": "member_access_expression",
3478
- "named": true
3479
- },
3480
- {
3481
- "type": "parenthesized_expression",
3477
+ "type": "postfix_unary_expression",
3482
3478
  "named": true
3483
3479
  },
3484
3480
  {
@@ -3894,11 +3890,11 @@
3894
3890
  "named": true
3895
3891
  },
3896
3892
  {
3897
- "type": "generic_name",
3893
+ "type": "invocation_expression",
3898
3894
  "named": true
3899
3895
  },
3900
3896
  {
3901
- "type": "identifier",
3897
+ "type": "postfix_unary_expression",
3902
3898
  "named": true
3903
3899
  },
3904
3900
  {
@@ -4668,6 +4664,14 @@
4668
4664
  {
4669
4665
  "type": "expression",
4670
4666
  "named": true
4667
+ },
4668
+ {
4669
+ "type": "invocation_expression",
4670
+ "named": true
4671
+ },
4672
+ {
4673
+ "type": "postfix_unary_expression",
4674
+ "named": true
4671
4675
  }
4672
4676
  ]
4673
4677
  }
Binary file
package/tree-sitter.json CHANGED
@@ -19,7 +19,7 @@
19
19
  }
20
20
  ],
21
21
  "metadata": {
22
- "version": "1.0.8",
22
+ "version": "1.0.9",
23
23
  "license": "MIT",
24
24
  "description": "C# grammar for tree-sitter",
25
25
  "authors": [