@willbooster/tree-sitter-c-sharp 2.0.1 → 3.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/README.md +20 -13
- package/grammar.js +62 -9
- package/package.json +6 -5
- package/tree-sitter-c_sharp.wasm +0 -0
- package/tree-sitter.json +1 -1
package/README.md
CHANGED
|
@@ -28,16 +28,12 @@ The grammar is based upon the Roslyn grammar with changes in order to:
|
|
|
28
28
|
Known gaps:
|
|
29
29
|
|
|
30
30
|
- `var` and `await` cannot be used as identifiers everywhere they are valid
|
|
31
|
-
- A pointer dereference can be assigned to only when its operand is a variable, an address, a parenthesized or
|
|
32
|
-
postfix expression, or a cast of one of these or of an invocation (`*p = 1`, `*(p + 1) = 1`, `*(int*)p = 1`,
|
|
33
|
-
`*dst++ = 1`); `*++p = 1` and `*f() = 1` are not recognized
|
|
34
31
|
|
|
35
32
|
## Usage
|
|
36
33
|
|
|
37
34
|
The npm package ships `tree-sitter-c_sharp.wasm` for
|
|
38
35
|
[@willbooster/web-tree-sitter](https://www.npmjs.com/package/@willbooster/web-tree-sitter), which runs in Node.js, Bun,
|
|
39
|
-
browsers, and Cloudflare Workers. Use runtime version 1.
|
|
40
|
-
instantiation support for this grammar. Install the runtime alongside the grammar when using the Wasm parser; it
|
|
36
|
+
browsers, and Cloudflare Workers. Use runtime version 1.3.0 or later for the compact ABI 16 parser. Install the runtime alongside the grammar when using the Wasm parser; it
|
|
41
37
|
remains an optional peer for consumers that only use the grammar source or queries.
|
|
42
38
|
|
|
43
39
|
In Node.js and Bun, load it from the package:
|
|
@@ -83,13 +79,12 @@ The package also ships the queries in `queries/` and the node types in `src/node
|
|
|
83
79
|
|
|
84
80
|
In Rust, depend on the [crate](https://crates.io/crates/willbooster-tree-sitter-c-sharp) and on
|
|
85
81
|
[willbooster-tree-sitter](https://crates.io/crates/willbooster-tree-sitter), the runtime this package is tested and
|
|
86
|
-
fuzzed with
|
|
87
|
-
`tree-sitter` crate 0.27, whose error recovery never ends on some malformed input):
|
|
82
|
+
fuzzed with. The compact ABI 16 parser requires runtime 1.3.0 or later:
|
|
88
83
|
|
|
89
84
|
```toml
|
|
90
85
|
[dependencies]
|
|
91
|
-
tree-sitter = { package = "willbooster-tree-sitter", version = "1.
|
|
92
|
-
tree-sitter-c-sharp = { package = "willbooster-tree-sitter-c-sharp", version = "
|
|
86
|
+
tree-sitter = { package = "willbooster-tree-sitter", version = "1.3.0" }
|
|
87
|
+
tree-sitter-c-sharp = { package = "willbooster-tree-sitter-c-sharp", version = "3" }
|
|
93
88
|
```
|
|
94
89
|
|
|
95
90
|
```rust
|
|
@@ -114,16 +109,28 @@ runtime this package ships. The first run downloads that CLI from its GitHub Rel
|
|
|
114
109
|
`cargo` (with the `cmake` that `mise.toml` pins) when the download fails or the release has no binary that runs here. The `tree-sitter-cli` package provides
|
|
115
110
|
only the types of the grammar DSL that `grammar.js` checks against; its `tree-sitter` binary is upstream's.
|
|
116
111
|
|
|
112
|
+
`bun run generate` records a fresh ABI 16 generation profile from the applicable `test/corpus` cases and Git-tracked
|
|
113
|
+
files in `examples/`, then generates compact parser tables. The parser also embeds metadata from `tree-sitter.json`. After changing a grammar,
|
|
114
|
+
`tree-sitter.json`, a corpus case, or a tracked example,
|
|
115
|
+
regenerate and commit `src/`. Stage added or removed examples with `git add -A examples` before generation so the profile uses the intended file list.
|
|
116
|
+
Profiles in `.tmp/generation-profiles/` are temporary and must not be committed. `bun run build-wasm`, `bun run build/ci`,
|
|
117
|
+
and the release build regenerate the parsers before compiling them.
|
|
118
|
+
|
|
119
|
+
The tracked `examples/JsonWriter.cs` and `examples/JsonSerializerInternalWriter.cs` are verbatim MIT-licensed
|
|
120
|
+
snapshots from Newtonsoft.Json commit `52fa3aef1f2cadcd3a3f874251eddc98d3efbbaa`, under `Src/Newtonsoft.Json/`
|
|
121
|
+
and its `Serialization/` directory respectively. Refresh these training inputs independently of the clone pins in
|
|
122
|
+
`script/parse-examples` so changing a test checkout does not change profile training.
|
|
123
|
+
|
|
117
124
|
`bun run test` runs:
|
|
118
125
|
|
|
119
126
|
- the corpus in `test/corpus`, with the native build and with the Wasm build (the first run downloads the WASI SDK);
|
|
120
127
|
- an incremental-parsing check (`test/unit/incremental.test.ts`): `script/fuzz-corpus` runs `tree-sitter fuzz`, which
|
|
121
128
|
edits each corpus case at random, reparses it, undoes the edits, and reparses again. `TREE_SITTER_SEED`,
|
|
122
129
|
`TREE_SITTER_ITERATIONS`, and `TREE_SITTER_EDITS` run other or more edits;
|
|
123
|
-
- a check that the
|
|
124
|
-
`script/known-failures.txt`.
|
|
125
|
-
`script/parse-examples`. After
|
|
126
|
-
|
|
130
|
+
- a check that the C# files under `examples/` that fail to parse are exactly those listed in
|
|
131
|
+
`script/known-failures.txt`. Inputs include Git-tracked generation examples and pinned clones. The first run fetches the pinned repositories listed in
|
|
132
|
+
`script/parse-examples`. After adding, removing, or changing an example, changing the grammar, or moving a pin,
|
|
133
|
+
run `script/parse-examples` and review the failure-list diff before committing;
|
|
127
134
|
- a performance check (`test/unit/performance.test.ts`) that recovering from an error on each line takes linear time
|
|
128
135
|
(ten times the lines take about ten times the CPU time, under a ceiling), since consumers parse files while they are
|
|
129
136
|
being edited. It loads the Wasm build through @willbooster/web-tree-sitter, which `bun run build/ci` rebuilds after
|
package/grammar.js
CHANGED
|
@@ -49,6 +49,8 @@ module.exports = grammar({
|
|
|
49
49
|
name: 'c_sharp',
|
|
50
50
|
|
|
51
51
|
conflicts: ($) => [
|
|
52
|
+
[$._assignment_pointer_cast, $._lvalue_cast_expression],
|
|
53
|
+
[$._assignment_pointer_expression, $._pointer_indirection_expression],
|
|
52
54
|
[$.modifier, $._constructor_declaration_initializer, $._reserved_identifier],
|
|
53
55
|
[$._simple_name, $.generic_name],
|
|
54
56
|
[$._simple_name, $.type_parameter],
|
|
@@ -1209,11 +1211,67 @@ module.exports = grammar({
|
|
|
1209
1211
|
seq(
|
|
1210
1212
|
// An invocation can return a reference (`Unsafe.Add(ref x, i) = v`). It ends with `)`, so `=` after it adds few
|
|
1211
1213
|
// parse states, unlike making any expression assignable.
|
|
1212
|
-
field(
|
|
1214
|
+
field(
|
|
1215
|
+
'left',
|
|
1216
|
+
choice(
|
|
1217
|
+
$.lvalue_expression,
|
|
1218
|
+
$.invocation_expression,
|
|
1219
|
+
alias($._assignment_pointer_expression, $.prefix_unary_expression)
|
|
1220
|
+
)
|
|
1221
|
+
),
|
|
1213
1222
|
field('operator', choice('=', '+=', '-=', '*=', '/=', '%=', '&=', '^=', '|=', '<<=', '>>=', '>>>=', '??=')),
|
|
1214
1223
|
field('right', $.expression)
|
|
1215
1224
|
),
|
|
1216
1225
|
|
|
1226
|
+
// Keep this alternative confined to assignment targets: sharing it with ordinary dereferences changes hidden
|
|
1227
|
+
// expression-supertype captures in nested reads. -3 prefers the existing lvalue path (-2) when both fit.
|
|
1228
|
+
_assignment_pointer_expression: ($) =>
|
|
1229
|
+
prec.dynamic(
|
|
1230
|
+
-3,
|
|
1231
|
+
prec.right(
|
|
1232
|
+
PREC.UNARY,
|
|
1233
|
+
seq(
|
|
1234
|
+
'*',
|
|
1235
|
+
choice(
|
|
1236
|
+
$.lvalue_expression,
|
|
1237
|
+
$.parenthesized_expression,
|
|
1238
|
+
$.invocation_expression,
|
|
1239
|
+
$.postfix_unary_expression,
|
|
1240
|
+
alias($._assignment_pointer_expression, $.prefix_unary_expression),
|
|
1241
|
+
alias($._pointer_prefix_update, $.prefix_unary_expression),
|
|
1242
|
+
alias($._assignment_pointer_cast, $.cast_expression)
|
|
1243
|
+
)
|
|
1244
|
+
)
|
|
1245
|
+
)
|
|
1246
|
+
),
|
|
1247
|
+
|
|
1248
|
+
_pointer_prefix_update: ($) =>
|
|
1249
|
+
prec(
|
|
1250
|
+
PREC.UNARY,
|
|
1251
|
+
seq(choice('++', '--'), choice($.lvalue_expression, $.invocation_expression, $.parenthesized_expression))
|
|
1252
|
+
),
|
|
1253
|
+
|
|
1254
|
+
_assignment_pointer_cast: ($) =>
|
|
1255
|
+
prec(
|
|
1256
|
+
PREC.CAST,
|
|
1257
|
+
seq(
|
|
1258
|
+
'(',
|
|
1259
|
+
field('type', $.type),
|
|
1260
|
+
')',
|
|
1261
|
+
field(
|
|
1262
|
+
'value',
|
|
1263
|
+
choice(
|
|
1264
|
+
$.lvalue_expression,
|
|
1265
|
+
$.parenthesized_expression,
|
|
1266
|
+
$.invocation_expression,
|
|
1267
|
+
$.postfix_unary_expression,
|
|
1268
|
+
alias($._assignment_pointer_expression, $.prefix_unary_expression),
|
|
1269
|
+
alias($._pointer_prefix_update, $.prefix_unary_expression)
|
|
1270
|
+
)
|
|
1271
|
+
)
|
|
1272
|
+
)
|
|
1273
|
+
),
|
|
1274
|
+
|
|
1217
1275
|
binary_expression: ($) =>
|
|
1218
1276
|
choice(
|
|
1219
1277
|
...[
|
|
@@ -1267,14 +1325,9 @@ module.exports = grammar({
|
|
|
1267
1325
|
)
|
|
1268
1326
|
),
|
|
1269
1327
|
|
|
1270
|
-
//
|
|
1271
|
-
//
|
|
1272
|
-
//
|
|
1273
|
-
// parenthesized, postfix, or invocation expression, or an address (`*(int*)p`, `*(long*)(p + 4)`, `*(T*)f()`,
|
|
1274
|
-
// `*(long*)&v`). Dereferencing any other expression (`*++p`) is only read: letting any expression be the assignable
|
|
1275
|
-
// form's operand lets `=` follow every expression that can be the operand, which grows the parser by about 4,800
|
|
1276
|
-
// states and nearly doubles the Wasm build, while these operands add about 550.
|
|
1277
|
-
//
|
|
1328
|
+
// Keep the lvalue operand set restricted: a general expression also permits assignment after every operand,
|
|
1329
|
+
// substantially increasing parser states. Additional call and prefix-update operands use the assignment-only
|
|
1330
|
+
// `_assignment_pointer_expression` path to preserve the shared read derivations and their query captures.
|
|
1278
1331
|
// Dynamic precedences: an assignable dereference -2, a read-only one -4, a read-only cast +1, an assignable cast -1,
|
|
1279
1332
|
// and a unary `+`, `-`, `^`, or `&` -2. C# reads a parenthesized name as a cast only when the token after `)` is
|
|
1280
1333
|
// `~`, `!`, `(`, an identifier, a literal, or a keyword (C# spec §12.9.8 Cast expressions), and these values keep
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@willbooster/tree-sitter-c-sharp",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "C# grammar for tree-sitter",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"incremental",
|
|
@@ -22,10 +22,11 @@
|
|
|
22
22
|
"*.wasm"
|
|
23
23
|
],
|
|
24
24
|
"scripts": {
|
|
25
|
-
"build-wasm": "script/
|
|
26
|
-
"build/ci": "
|
|
25
|
+
"build-wasm": "script/generate --build-wasm",
|
|
26
|
+
"build/ci": "bun run build-wasm",
|
|
27
27
|
"cleanup": "bun wb lint --fix --format",
|
|
28
28
|
"format": "bun wb lint --format",
|
|
29
|
+
"generate": "script/generate",
|
|
29
30
|
"lint": "bun wb lint",
|
|
30
31
|
"lint-fix": "bun wb lint --fix",
|
|
31
32
|
"prepare": "(bun lefthook install || true) && (test ! -f .lefthook/normalize-bun-lockfile.sh || bash .lefthook/normalize-bun-lockfile.sh)",
|
|
@@ -47,7 +48,7 @@
|
|
|
47
48
|
"@willbooster/oxfmt-config": "1.2.2",
|
|
48
49
|
"@willbooster/oxlint-config": "1.4.8",
|
|
49
50
|
"@willbooster/wb": "22.13.1",
|
|
50
|
-
"@willbooster/web-tree-sitter": "1.
|
|
51
|
+
"@willbooster/web-tree-sitter": "1.4.0",
|
|
51
52
|
"conventional-changelog-conventionalcommits": "10.4.0",
|
|
52
53
|
"lefthook": "2.1.14",
|
|
53
54
|
"oxfmt": "0.70.0",
|
|
@@ -63,7 +64,7 @@
|
|
|
63
64
|
"wrangler": "4.135.0"
|
|
64
65
|
},
|
|
65
66
|
"peerDependencies": {
|
|
66
|
-
"@willbooster/web-tree-sitter": "^1.
|
|
67
|
+
"@willbooster/web-tree-sitter": "^1.3.0"
|
|
67
68
|
},
|
|
68
69
|
"peerDependenciesMeta": {
|
|
69
70
|
"@willbooster/web-tree-sitter": {
|
package/tree-sitter-c_sharp.wasm
CHANGED
|
Binary file
|