├── .github └── workflows │ └── ci.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── binding.gyp ├── build.zig ├── grammar.js ├── package-lock.json ├── package.json └── test ├── samples └── hello.zig └── valid.py /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | paths: 6 | - "build.zig" 7 | - "grammar.js" 8 | - '.github/workflows/ci.yml' 9 | pull_request: 10 | paths: 11 | - "build.zig" 12 | - "grammar.js" 13 | - '.github/workflows/ci.yml' 14 | workflow_dispatch: 15 | 16 | permissions: 17 | contents: read 18 | 19 | jobs: 20 | build: 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - uses: actions/checkout@v3 25 | 26 | - name: Checkout zig 27 | uses: actions/checkout@v3 28 | with: 29 | path: zig 30 | repository: "ziglang/zig" 31 | 32 | - uses: actions/setup-python@v4 33 | with: 34 | python-version: '3.10' 35 | 36 | - uses: actions/setup-node@v3 37 | with: 38 | node-version: 18 39 | 40 | - name: Install Dependencies 41 | run: | 42 | npm i -g tree-sitter-cli 43 | pip3 install tree_sitter 44 | 45 | - name: Generate Tree-Sitter Parser 46 | run: | 47 | cd $GITHUB_WORKSPACE 48 | tree-sitter generate 49 | 50 | - name: Run Tests 51 | run: | 52 | python ./test/valid.py $GITHUB_WORKSPACE/zig/lib/std/\*\*/\*.zig 53 | 54 | - name: Create Tarball 55 | if: ${{ github.ref == 'refs/heads/main' && github.repository_owner == 'ziglibs' }} 56 | run: | 57 | mkdir -p ../staging/tree-sitter-zig 58 | tar --exclude='node_modules' --exclude='zig' --exclude='.git' -czvf ../staging/tree-sitter-zig/${{ github.sha }}.tar.gz . 59 | 60 | - name: Upload to DigitalOcean Space 61 | uses: BetaHuhn/do-spaces-action@v2 62 | if: ${{ github.ref == 'refs/heads/main' && github.repository_owner == 'ziglibs' }} 63 | with: 64 | access_key: ${{ secrets.DO_SPACES_ACCESS_KEY }} 65 | secret_key: ${{ secrets.DO_SPACES_SECRET_KEY }} 66 | space_name: zigtools-releases 67 | space_region: nyc3 68 | source: ../staging 69 | 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | zig-cache 2 | zig-out 3 | node_modules 4 | 5 | build 6 | test/invalid_outputs 7 | 8 | parser.exp 9 | parser.lib 10 | parser.obj 11 | 12 | # Tree-sitter generated stuff we don't want in here 13 | src 14 | bindings 15 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tree-sitter-zig" 3 | description = "zig grammar for the tree-sitter parsing library" 4 | version = "0.0.1" 5 | keywords = ["incremental", "parsing", "zig"] 6 | categories = ["parsing", "text-editors"] 7 | repository = "https://github.com/zigtools/tree-sitter-zig" 8 | edition = "2018" 9 | license = "MIT" 10 | 11 | build = "bindings/rust/build.rs" 12 | include = [ 13 | "bindings/rust/*", 14 | "grammar.js", 15 | "queries/*", 16 | "src/*", 17 | ] 18 | 19 | [lib] 20 | path = "bindings/rust/lib.rs" 21 | 22 | [dependencies] 23 | tree-sitter = "~0.20.10" 24 | 25 | [build-dependencies] 26 | cc = "1.0" 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 tree-sitter-zig contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tree-sitter-zig 2 | 3 | [tree-sitter](https://github.com/tree-sitter/tree-sitter) grammar inspired by and partially built on [maxxnino/tree-sitter-zig](https://github.com/maxxnino/tree-sitter-zig) that's going to be made simple to query and structure-preserving on error rather than 100% adherent to the Zig spec. This grammar can successfully parse every behavior testcase, all std files, and all compiler files. 4 | 5 | ## Tests 6 | 7 | ```bash 8 | npm i 9 | ``` 10 | 11 | Then: 12 | ```bash 13 | .\node_modules\.bin\tree-sitter generate; .\node_modules\.bin\tree-sitter parse .\test\samples\hello.zig 14 | ``` 15 | 16 | ```bash 17 | node .\test\valid.mjs --path=C:\Programming\Zig\zig\test\cases 18 | ``` 19 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_zig_binding", 5 | "include_dirs": [ 6 | " repeat(choice( 22 | seq($.test_decl), 23 | seq($.comptime_decl), 24 | seq(optional($.doc_comment), optional(field("pub", $.pub)), $.decl) 25 | )); 26 | 27 | const container_members = $ => seq(container_declarations($), repeat(seq($.container_field, ",")), choice($.container_field, container_declarations($))); 28 | 29 | // Lists 30 | 31 | const identifier_list = $ => seq(repeat(seq(optional($.doc_comment), $.identifier, ",")), optional(seq(optional($.doc_comment), $.identifier))); 32 | 33 | const switch_prong_list = $ => seq(repeat(seq($.switch_prong, ",")), optional($.switch_prong)); 34 | 35 | const asm_output_list = $ => seq(repeat(seq($.asm_output_item, ",")), optional($.asm_output_item)); 36 | 37 | const asm_input_list = $ => seq(repeat(seq($.asm_input_item, ",")), optional($.asm_input_item)); 38 | 39 | const string_list = $ => seq(repeat(seq($.string_literal, ",")), optional($.string_literal)); 40 | 41 | const param_decl_list = $ => seq(repeat(seq($.param_decl, ",")), optional($.param_decl)); 42 | 43 | const expr_list = $ => seq(repeat(seq($.expr, ",")), optional($.expr)); 44 | 45 | module.exports = grammar({ 46 | name: "zig", 47 | 48 | externals: (_) => [], 49 | inline: (_) => [], 50 | extras: ($) => [/\s/, $.line_comment], 51 | // TODO: Investigate these - can we fix them? 52 | conflicts: ($) => [[$.root], [$.container_decl_auto]], 53 | 54 | rules: { 55 | root: $ => seq(optional($.container_doc_comment), container_members($)), 56 | 57 | // *** Keywords *** 58 | pub: _ => "pub", 59 | anyframe: _ => "anyframe", 60 | unreachable: _ => "unreachable", 61 | 62 | // *** Top level *** 63 | test_decl: $ => seq("test", optional(field("name", choice($.string_literal_single, $.identifier))), $.block), 64 | 65 | comptime_decl: $ => seq("comptime", $.block), 66 | 67 | decl: $ => choice( 68 | seq(optional(choice("export", seq("extern", optional($.string_literal_single)), choice("inline", "noinline"))), $.fn_proto, choice(";", $.block)), 69 | seq(optional(choice("export", seq("extern", optional($.string_literal_single)))), optional("threadlocal"), $.var_decl), 70 | seq("usingnamespace", $.expr, ";") 71 | ), 72 | 73 | fn_proto: $ => seq("fn", optional($.identifier), "(", param_decl_list($), ")", optional($.byte_align), optional($.addr_space), optional($.link_section), optional($.call_conv), optional("!"), $._type_expr), 74 | var_decl: $ => seq(choice("const", "var"), field("name", $.identifier), optional(seq(":", field("type", $._type_expr))), optional($.byte_align), optional($.addr_space), optional($.link_section), optional(seq("=", field("init", $.expr))), ";"), 75 | container_field: $ => choice( 76 | seq(optional($.doc_comment), optional("comptime"), $.identifier, optional(seq(":", $._type_expr)), optional($.byte_align), optional(seq("=", $.expr))), 77 | seq(optional($.doc_comment), optional("comptime"), optional(seq($.identifier, ":")), $._type_expr, optional($.byte_align), optional(seq("=", $.expr))), 78 | ), 79 | 80 | // *** Block Level *** 81 | statement: $ => prec(precedence.curly, choice( 82 | seq(optional("comptime"), $.var_decl), 83 | seq("comptime", $.block_expr_statement), 84 | seq("nosuspend", $.block_expr_statement), 85 | seq("suspend", $.block_expr_statement), 86 | seq("defer", $.block_expr_statement), 87 | seq("errdefer", optional($.payload), $.block_expr_statement), 88 | seq($.if_statement), 89 | seq($.labeled_statement), 90 | seq($.switch_expr), 91 | seq(choice($.assign_expr, $.expr), ";"), 92 | )), 93 | 94 | if_statement: $ => choice( 95 | seq($.if_prefix, $.block_expr, optional(seq("else", optional($.payload), $.statement))), 96 | seq($.if_prefix, choice($.assign_expr, $.expr), choice(";", seq("else", optional($.payload), $.statement))) 97 | ), 98 | 99 | labeled_statement: $ => prec(precedence.curly, seq(optional($.block_label), choice($.block, $.loop_statement))), 100 | loop_statement: $ => seq(optional("inline"), choice($.for_statement, $.while_statement)), 101 | 102 | for_statement: $ => choice( 103 | seq($.for_prefix, $.block_expr, optional(seq("else", $.statement))), 104 | seq($.for_prefix, choice($.assign_expr, $.expr), seq(choice(";", seq("else", $.statement)))), 105 | ), 106 | 107 | while_statement: $ => choice( 108 | seq($.while_prefix, $.block_expr, optional(seq("else", optional($.payload), $.statement))), 109 | seq($.while_prefix, choice($.assign_expr, $.expr), seq(choice(";", seq("else", optional($.payload), $.statement)))), 110 | ), 111 | 112 | block_expr_statement: $ => choice( 113 | $.block_expr, 114 | seq(choice($.assign_expr, $.expr), ";"), 115 | ), 116 | 117 | block_expr: $ => prec(precedence.curly, seq(optional($.block_label), $.block)), 118 | 119 | // *** Expression Level *** 120 | 121 | assign_expr: $ => prec(precedence.assign, seq($.expr, $.assign_op, $.expr)), 122 | 123 | expr: $ => choice($.binary_expr, $._prefix_expr, $._primary_expr), 124 | 125 | binary_expr: $ => { 126 | const table = [ 127 | [precedence.or, "or"], 128 | [precedence.and, "and"], 129 | [precedence.comparative, $.compare_op], 130 | [precedence.bitwise, $.bitwise_op], 131 | [precedence.bitshift, $.bit_shift_op], 132 | [precedence.addition, $.addition_op], 133 | [precedence.multiply, $.multiply_op], 134 | ]; 135 | 136 | return choice( 137 | ...table.map(([precedence, operator]) => 138 | prec.left( 139 | precedence, 140 | seq( 141 | $.expr, 142 | operator, 143 | $.expr 144 | ) 145 | ) 146 | ) 147 | ); 148 | }, 149 | 150 | _prefix_expr: $ => prec.left(precedence.prefix, seq(repeat($.prefix_op), $._primary_expr)), 151 | 152 | _primary_expr: $ => prec.right(precedence.primary, choice( 153 | $.asm_expr, 154 | $.if_expr, 155 | seq("break", optional($.break_label), optional($.expr)), 156 | seq("comptime", $.expr), 157 | seq("nosuspend", $.expr), 158 | seq("continue", optional($.break_label)), 159 | seq("resume", $.expr), 160 | seq("return", optional($.expr)), 161 | seq(optional($.block_label), $.loop_expr), 162 | $.block, 163 | $._curly_suffix_expr, 164 | )), 165 | 166 | if_expr: $ => prec.right(seq($.if_prefix, $.expr, optional(seq("else", optional($.payload), $.expr)))), 167 | 168 | block: $ => seq("{", repeat($.statement), "}"), 169 | 170 | loop_expr: $ => choice( 171 | prec(2, seq("inline", choice($.for_expr, $.while_expr))), 172 | seq(optional("inline"), choice($.for_expr, $.while_expr)), 173 | ), 174 | 175 | for_expr: $ => prec.right(seq($.for_prefix, $.expr, optional(seq("else", $.expr)))), 176 | 177 | while_expr: $ => prec.right(seq($.while_prefix, $.expr, optional(seq("else", optional($.payload), $.expr)))), 178 | 179 | _curly_suffix_expr: $ => prec.right(precedence.curly, seq($._type_expr, optional($.init_list))), 180 | 181 | init_list: $ => choice( 182 | seq("{", $.field_init, repeat(seq(",", $.field_init)), optional(","), "}"), 183 | seq("{", $.expr, repeat(seq(",", $.expr)), optional(","), "}"), 184 | seq("{", "}"), 185 | ), 186 | 187 | _type_expr: $ => seq(repeat($.prefix_type_op), choice($.error_union_expr, $._suffix_expr)), 188 | 189 | error_union_expr: $ => prec.right(2, seq($._suffix_expr, seq("!", $._type_expr))), 190 | 191 | _suffix_expr: $ => prec.right(choice( 192 | seq("async", $._primary_type_expr, repeat($._suffix_op), $.fn_call_arguments), 193 | seq($._primary_type_expr, repeat(choice($._suffix_op, $.fn_call_arguments))), 194 | )), 195 | 196 | _primary_type_expr: $ => prec(2, choice( 197 | seq($.builtin_identifier, $.fn_call_arguments), 198 | $.char_literal, 199 | $.container_decl, 200 | seq(".", $.identifier), 201 | seq(".", $.init_list), 202 | $.error_set_decl, 203 | $.float, 204 | $.fn_proto, 205 | $.grouped_expr, 206 | $.labeled_type_expr, 207 | $.identifier, 208 | $.if_type_expr, 209 | $.integer, 210 | seq("comptime", $._type_expr), 211 | seq("error", ".", $.identifier), 212 | $.anyframe, 213 | $.unreachable, 214 | $.string_literal, 215 | $.switch_expr, 216 | )), 217 | 218 | container_decl: $ => seq(optional(choice("extern", "packed")), $.container_decl_auto), 219 | 220 | error_set_decl: $ => seq("error", "{", identifier_list($), "}"), 221 | 222 | grouped_expr: $ => seq("(", $.expr, ")"), 223 | 224 | if_type_expr: $ => prec.right(seq($.if_prefix, $._type_expr, optional(seq("else", optional($.payload), $._type_expr)))), 225 | 226 | labeled_type_expr: $ => choice( 227 | seq($.block_label, $.block), 228 | seq(optional($.block_label), $.loop_type_expr), 229 | ), 230 | 231 | loop_type_expr: $ => choice( 232 | prec(2, seq("inline", choice($.for_type_expr, $.while_type_expr))), 233 | seq(optional("inline"), choice($.for_type_expr, $.while_type_expr)), 234 | ), 235 | 236 | for_type_expr: $ => prec.right(seq($.for_prefix, $._type_expr, optional(seq("else", $._type_expr)))), 237 | 238 | while_type_expr: $ => prec.right(seq($.while_prefix, $._type_expr, optional(seq("else", optional($.payload), $._type_expr)))), 239 | 240 | switch_expr: $ => seq("switch", "(", $.expr, ")", "{", switch_prong_list($), "}"), 241 | 242 | // *** Assembly *** 243 | asm_expr: $ => seq("asm", optional("volatile"), "(", $.expr, optional($.asm_output), ")"), 244 | 245 | asm_output: $ => seq(":", asm_output_list($), optional($.asm_input)), 246 | 247 | asm_output_item: $ => seq("[", $.identifier, "]", $.string_literal, "(", choice(seq("->", $._type_expr), $.identifier), ")"), 248 | 249 | asm_input: $ => seq(":", asm_input_list($), optional($.asm_clobbers)), 250 | 251 | asm_input_item: $ => seq("[", $.identifier, "]", $.string_literal, "(", $.expr, ")"), 252 | 253 | asm_clobbers: $ => seq(":", string_list($)), 254 | 255 | // *** Helper grammar *** 256 | break_label: $ => seq(":", $.identifier), 257 | 258 | block_label: $ => prec.left(seq($.identifier, ":")), 259 | 260 | field_init: $ => seq(".", $.identifier, "=", $.expr), 261 | 262 | while_continue_expr: $ => seq(":", "(", choice($.assign_expr, $.expr), ")"), 263 | 264 | link_section: $ => seq("linksection", "(", $.expr, ")"), 265 | 266 | addr_space: $ => seq("addrspace", "(", $.expr, ")"), 267 | 268 | // Fn specific 269 | call_conv: $ => seq("callconv", "(", $.expr, ")"), 270 | 271 | param_decl: $ => choice( 272 | seq(optional($.doc_comment), optional(choice("noalias", "comptime")), optional(seq($.identifier, ":")), $.param_type), 273 | "...", 274 | ), 275 | 276 | param_type: $ => choice( 277 | "anytype", 278 | $._type_expr, 279 | ), 280 | 281 | // Control flow prefixes 282 | if_prefix: $ => seq( 283 | "if", 284 | "(", 285 | $.expr, 286 | ")", 287 | optional($.ptr_payload) 288 | ), 289 | 290 | while_prefix: $ => seq( 291 | "while", 292 | "(", 293 | $.expr, 294 | ")", 295 | optional($.ptr_payload), 296 | optional($.while_continue_expr) 297 | ), 298 | 299 | for_prefix: $ => seq( 300 | "for", 301 | "(", 302 | $.for_arguments_list, 303 | ")", 304 | $.ptr_list_payload 305 | ), 306 | 307 | // Payloads 308 | payload: $ => seq("|", $.identifier, "|"), 309 | 310 | ptr_payload: $ => seq("|", optional("*"), $.identifier, "|"), 311 | 312 | ptr_index_payload: $ => seq("|", optional("*"), $.identifier, optional(seq(",", $.identifier)), "|"), 313 | 314 | ptr_list_payload: $ => seq("|", optional("*"), $.identifier, repeat(seq(",", optional("*"), $.identifier)), optional(","), "|"), 315 | 316 | // Switch specific 317 | switch_prong: $ => seq( 318 | optional("inline"), 319 | $.switch_case, 320 | "=>", 321 | optional($.ptr_index_payload), 322 | choice($.assign_expr, $.expr), 323 | ), 324 | 325 | switch_case: $ => choice( 326 | seq($.switch_item, repeat(seq(",", $.switch_item)), optional(",")), 327 | "else" 328 | ), 329 | 330 | switch_item: $ => seq($.expr, optional(seq("...", $.expr))), 331 | 332 | // For specific 333 | for_arguments_list: $ => seq( 334 | $.for_item, 335 | repeat(seq(",", $.for_item)), 336 | optional(",") 337 | ), 338 | 339 | for_item: $ => seq( 340 | $.expr, 341 | optional(seq("..", optional($.expr))) 342 | ), 343 | 344 | // Operators 345 | assign_op: $ => choice( 346 | "*=", 347 | "*|=", 348 | "/=", 349 | "%=", 350 | "+=", 351 | "+|=", 352 | "-=", 353 | "-|=", 354 | "<<=", 355 | "<<|=", 356 | ">>=", 357 | "&=", 358 | "^=", 359 | "|=", 360 | "*%=", 361 | "+%=", 362 | "-%=", 363 | "=", 364 | ), 365 | 366 | compare_op: $ => choice( 367 | "==", 368 | "!=", 369 | ">", 370 | "<", 371 | ">=", 372 | "<=", 373 | ), 374 | 375 | bitwise_op: $ => choice( 376 | "&", 377 | "^", 378 | "|", 379 | "orelse", 380 | seq("catch", optional($.payload)), 381 | ), 382 | 383 | bit_shift_op: $ => choice( 384 | "<<", 385 | ">>", 386 | "<<|" 387 | ), 388 | 389 | addition_op: $ => choice( 390 | "+", 391 | "-", 392 | "++", 393 | "+%", 394 | "-%", 395 | "+|", 396 | "-|", 397 | ), 398 | 399 | multiply_op: $ => choice( 400 | "||", 401 | "*", 402 | "/", 403 | "%", 404 | "**", 405 | "*%", 406 | "*|", 407 | ), 408 | 409 | prefix_op: $ => choice( 410 | "!", 411 | "-", 412 | "~", 413 | "-%", 414 | "&", 415 | "try", 416 | "await", 417 | ), 418 | 419 | prefix_type_op: $ => choice( 420 | "?", 421 | seq("anyframe", "->"), 422 | seq($.slice_type_start, repeat(choice($.byte_align, $.addr_space, "const", "volatile", "allowzero"))), 423 | seq($.ptr_type_start, repeat(choice($.addr_space, seq("align", "(", $.expr, optional(seq(":", $.expr, ":", $.expr)), ")"), "const", "volatile", "allowzero"))), 424 | $.array_type_start, 425 | ), 426 | 427 | array_access: $ => seq("[", $.expr, "]"), 428 | slice: $ => seq("[", field("start", $.expr), "..", optional(seq(optional(field("end", $.expr)), optional(seq(":", field("sentinel", $.expr))))), "]"), 429 | 430 | deref: _ => ".*", 431 | unwrap: _ => ".?", 432 | 433 | field_access: $ => seq(".", $.identifier), 434 | 435 | _suffix_op: $ => choice( 436 | $.slice, 437 | $.array_access, 438 | $.field_access, 439 | $.deref, 440 | $.unwrap, 441 | ), 442 | 443 | fn_call_arguments: $ => seq("(", expr_list($), ")"), 444 | 445 | // Ptr specific 446 | slice_type_start: $ => seq("[", optional(seq(":", $.expr)), "]"), 447 | 448 | ptr_type_start: $ => choice( 449 | "*", 450 | "**", 451 | seq("[", "*", optional(choice("c", seq(":", $.expr))), "]"), 452 | ), 453 | 454 | array_type_start: $ => seq("[", $.expr, optional(seq(":", $.expr)), "]"), 455 | 456 | // ContainerDecl specific 457 | container_decl_auto: $ => seq($.container_decl_type, "{", optional($.container_doc_comment), container_members($), "}"), 458 | 459 | container_decl_type: $ => choice( 460 | seq("struct", optional(seq("(", $.expr, ")"))), 461 | "opaque", 462 | seq("enum", optional(seq("(", $.expr, ")"))), 463 | seq("union", optional(seq("(", choice(seq("enum", optional(seq("(", $.expr, ")"))), $.expr), ")"))), 464 | ), 465 | 466 | // Alignment 467 | byte_align: $ => seq("align", "(", $.expr, ")"), 468 | 469 | // Comments 470 | container_doc_comment: (_) => 471 | token(repeat1(seq("//!", /[^\n]*/, /[ \n]*/))), 472 | doc_comment: (_) => token(repeat1(/\/\/\/(([^/\n][^\n]*[ \n]*)|)/)), 473 | line_comment: (_) => token(seq("//", /.*/)), 474 | 475 | // Strings 476 | identifier: ($) => choice(/[A-Za-z_][A-Za-z0-9_]*/, seq("@", $.string_literal)), 477 | string_escape: ($) => choice( 478 | "\\n", 479 | "\\r", 480 | "\\t", 481 | "\\\\", 482 | "\\'", 483 | "\\\"", 484 | /\\x[0-9a-fA-F]{2}/, 485 | /\\u\{[0-9a-fA-F]{1,6}\}/ 486 | ), 487 | builtin_identifier: $ => /@[A-Za-z_][A-Za-z0-9_]*/, 488 | 489 | char_fragment: ($) => token.immediate(prec(1, /[^'\\]/)), 490 | string_fragment: ($) => token.immediate(prec(1, /[^"\\]+/)), 491 | 492 | char_literal: ($) => seq("'", choice($.char_fragment, $.string_escape), "'"), 493 | string_literal_single: ($) => seq("\"", repeat(choice($.string_fragment, $.string_escape)), "\""), 494 | multi_string_literal: ($) => prec(1, repeat1(seq("\\\\", /[^\n]*/, "\n"))), 495 | string_literal: $ => prec(1, choice($.string_literal_single, $.multi_string_literal)), 496 | 497 | integer: $ => choice( 498 | token(seq("0b", numericWithSeparator(/[01]/))), 499 | token(seq("0o", numericWithSeparator(/[0-7]/))), 500 | token(seq("0x", numericWithSeparator(/[0-9a-fA-F]/), optional(seq(/[pP]\+?/, numericWithSeparator(/[0-9]/))))), 501 | token(seq(numericWithSeparator(/[0-9]/), optional(seq(/[eE]\+?/, numericWithSeparator(/[0-9]/))))), 502 | ), 503 | 504 | float: $ => prec(10, choice( 505 | token(seq("0x", numericWithSeparator(/[0-9a-fA-F]/), ".", numericWithSeparator(/[0-9a-fA-F]/), optional(seq(/[pP][+\-]?/, numericWithSeparator(/[0-9]/))))), 506 | token(seq(numericWithSeparator(/[0-9]/), ".", numericWithSeparator(/[0-9]/), optional(seq(/[eE][+\-]?/, numericWithSeparator(/[0-9]/))))), 507 | token(seq("0x", numericWithSeparator(/[0-9a-fA-F]/), /[pP]-/, numericWithSeparator(/[0-9]/))), 508 | token(seq(numericWithSeparator(/[0-9]/), /[eE]-/, numericWithSeparator(/[0-9]/))), 509 | )), 510 | } 511 | }); 512 | 513 | function numericWithSeparator(regex) { 514 | return seq(regex, repeat(seq(optional("_"), regex))); 515 | } 516 | 517 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-zig", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "tree-sitter-zig", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "nan": "^2.17.0" 13 | }, 14 | "devDependencies": { 15 | "glob": "^10.2.2", 16 | "minimist": "^1.2.8", 17 | "tree-sitter-cli": "^0.20.8" 18 | } 19 | }, 20 | "../../..": { 21 | "extraneous": true 22 | }, 23 | "../../../bindings/node/index.js": { 24 | "extraneous": true 25 | }, 26 | "node_modules/@pkgjs/parseargs": { 27 | "version": "0.11.0", 28 | "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", 29 | "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", 30 | "dev": true, 31 | "optional": true, 32 | "engines": { 33 | "node": ">=14" 34 | } 35 | }, 36 | "node_modules/ansi-regex": { 37 | "version": "5.0.1", 38 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 39 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 40 | "dev": true, 41 | "engines": { 42 | "node": ">=8" 43 | } 44 | }, 45 | "node_modules/ansi-styles": { 46 | "version": "4.3.0", 47 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 48 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 49 | "dev": true, 50 | "dependencies": { 51 | "color-convert": "^2.0.1" 52 | }, 53 | "engines": { 54 | "node": ">=8" 55 | }, 56 | "funding": { 57 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 58 | } 59 | }, 60 | "node_modules/balanced-match": { 61 | "version": "1.0.2", 62 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 63 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 64 | "dev": true 65 | }, 66 | "node_modules/brace-expansion": { 67 | "version": "2.0.1", 68 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 69 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 70 | "dev": true, 71 | "dependencies": { 72 | "balanced-match": "^1.0.0" 73 | } 74 | }, 75 | "node_modules/cliui": { 76 | "version": "7.0.4", 77 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 78 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 79 | "dev": true, 80 | "dependencies": { 81 | "string-width": "^4.2.0", 82 | "strip-ansi": "^6.0.0", 83 | "wrap-ansi": "^7.0.0" 84 | } 85 | }, 86 | "node_modules/color-convert": { 87 | "version": "2.0.1", 88 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 89 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 90 | "dev": true, 91 | "dependencies": { 92 | "color-name": "~1.1.4" 93 | }, 94 | "engines": { 95 | "node": ">=7.0.0" 96 | } 97 | }, 98 | "node_modules/color-name": { 99 | "version": "1.1.4", 100 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 101 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 102 | "dev": true 103 | }, 104 | "node_modules/cross-spawn": { 105 | "version": "7.0.3", 106 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 107 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 108 | "dev": true, 109 | "dependencies": { 110 | "path-key": "^3.1.0", 111 | "shebang-command": "^2.0.0", 112 | "which": "^2.0.1" 113 | }, 114 | "engines": { 115 | "node": ">= 8" 116 | } 117 | }, 118 | "node_modules/emoji-regex": { 119 | "version": "8.0.0", 120 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 121 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 122 | "dev": true 123 | }, 124 | "node_modules/foreground-child": { 125 | "version": "3.1.1", 126 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", 127 | "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", 128 | "dev": true, 129 | "dependencies": { 130 | "cross-spawn": "^7.0.0", 131 | "signal-exit": "^4.0.1" 132 | }, 133 | "engines": { 134 | "node": ">=14" 135 | }, 136 | "funding": { 137 | "url": "https://github.com/sponsors/isaacs" 138 | } 139 | }, 140 | "node_modules/glob": { 141 | "version": "10.2.2", 142 | "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.2.tgz", 143 | "integrity": "sha512-Xsa0BcxIC6th9UwNjZkhrMtNo/MnyRL8jGCP+uEwhA5oFOCY1f2s1/oNKY47xQ0Bg5nkjsfAEIej1VeH62bDDQ==", 144 | "dev": true, 145 | "dependencies": { 146 | "foreground-child": "^3.1.0", 147 | "jackspeak": "^2.0.3", 148 | "minimatch": "^9.0.0", 149 | "minipass": "^5.0.0", 150 | "path-scurry": "^1.7.0" 151 | }, 152 | "bin": { 153 | "glob": "dist/cjs/src/bin.js" 154 | }, 155 | "engines": { 156 | "node": ">=16 || 14 >=14.17" 157 | }, 158 | "funding": { 159 | "url": "https://github.com/sponsors/isaacs" 160 | } 161 | }, 162 | "node_modules/is-fullwidth-code-point": { 163 | "version": "3.0.0", 164 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 165 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 166 | "dev": true, 167 | "engines": { 168 | "node": ">=8" 169 | } 170 | }, 171 | "node_modules/isexe": { 172 | "version": "2.0.0", 173 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 174 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 175 | "dev": true 176 | }, 177 | "node_modules/jackspeak": { 178 | "version": "2.1.0", 179 | "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.1.0.tgz", 180 | "integrity": "sha512-DiEwVPqsieUzZBNxQ2cxznmFzfg/AMgJUjYw5xl6rSmCxAQXECcbSdwcLM6Ds6T09+SBfSNCGPhYUoQ96P4h7A==", 181 | "dev": true, 182 | "dependencies": { 183 | "cliui": "^7.0.4" 184 | }, 185 | "engines": { 186 | "node": ">=14" 187 | }, 188 | "funding": { 189 | "url": "https://github.com/sponsors/isaacs" 190 | }, 191 | "optionalDependencies": { 192 | "@pkgjs/parseargs": "^0.11.0" 193 | } 194 | }, 195 | "node_modules/lru-cache": { 196 | "version": "9.1.1", 197 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.1.tgz", 198 | "integrity": "sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A==", 199 | "dev": true, 200 | "engines": { 201 | "node": "14 || >=16.14" 202 | } 203 | }, 204 | "node_modules/minimatch": { 205 | "version": "9.0.0", 206 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", 207 | "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", 208 | "dev": true, 209 | "dependencies": { 210 | "brace-expansion": "^2.0.1" 211 | }, 212 | "engines": { 213 | "node": ">=16 || 14 >=14.17" 214 | }, 215 | "funding": { 216 | "url": "https://github.com/sponsors/isaacs" 217 | } 218 | }, 219 | "node_modules/minimist": { 220 | "version": "1.2.8", 221 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 222 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 223 | "dev": true, 224 | "funding": { 225 | "url": "https://github.com/sponsors/ljharb" 226 | } 227 | }, 228 | "node_modules/minipass": { 229 | "version": "5.0.0", 230 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", 231 | "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", 232 | "dev": true, 233 | "engines": { 234 | "node": ">=8" 235 | } 236 | }, 237 | "node_modules/nan": { 238 | "version": "2.17.0", 239 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", 240 | "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" 241 | }, 242 | "node_modules/path-key": { 243 | "version": "3.1.1", 244 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 245 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 246 | "dev": true, 247 | "engines": { 248 | "node": ">=8" 249 | } 250 | }, 251 | "node_modules/path-scurry": { 252 | "version": "1.7.0", 253 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.7.0.tgz", 254 | "integrity": "sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==", 255 | "dev": true, 256 | "dependencies": { 257 | "lru-cache": "^9.0.0", 258 | "minipass": "^5.0.0" 259 | }, 260 | "engines": { 261 | "node": ">=16 || 14 >=14.17" 262 | }, 263 | "funding": { 264 | "url": "https://github.com/sponsors/isaacs" 265 | } 266 | }, 267 | "node_modules/shebang-command": { 268 | "version": "2.0.0", 269 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 270 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 271 | "dev": true, 272 | "dependencies": { 273 | "shebang-regex": "^3.0.0" 274 | }, 275 | "engines": { 276 | "node": ">=8" 277 | } 278 | }, 279 | "node_modules/shebang-regex": { 280 | "version": "3.0.0", 281 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 282 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 283 | "dev": true, 284 | "engines": { 285 | "node": ">=8" 286 | } 287 | }, 288 | "node_modules/signal-exit": { 289 | "version": "4.0.1", 290 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.1.tgz", 291 | "integrity": "sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==", 292 | "dev": true, 293 | "engines": { 294 | "node": ">=14" 295 | }, 296 | "funding": { 297 | "url": "https://github.com/sponsors/isaacs" 298 | } 299 | }, 300 | "node_modules/string-width": { 301 | "version": "4.2.3", 302 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 303 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 304 | "dev": true, 305 | "dependencies": { 306 | "emoji-regex": "^8.0.0", 307 | "is-fullwidth-code-point": "^3.0.0", 308 | "strip-ansi": "^6.0.1" 309 | }, 310 | "engines": { 311 | "node": ">=8" 312 | } 313 | }, 314 | "node_modules/strip-ansi": { 315 | "version": "6.0.1", 316 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 317 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 318 | "dev": true, 319 | "dependencies": { 320 | "ansi-regex": "^5.0.1" 321 | }, 322 | "engines": { 323 | "node": ">=8" 324 | } 325 | }, 326 | "node_modules/tree-sitter-cli": { 327 | "version": "0.20.8", 328 | "resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.8.tgz", 329 | "integrity": "sha512-XjTcS3wdTy/2cc/ptMLc/WRyOLECRYcMTrSWyhZnj1oGSOWbHLTklgsgRICU3cPfb0vy+oZCC33M43u6R1HSCA==", 330 | "dev": true, 331 | "hasInstallScript": true, 332 | "bin": { 333 | "tree-sitter": "cli.js" 334 | } 335 | }, 336 | "node_modules/which": { 337 | "version": "2.0.2", 338 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 339 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 340 | "dev": true, 341 | "dependencies": { 342 | "isexe": "^2.0.0" 343 | }, 344 | "bin": { 345 | "node-which": "bin/node-which" 346 | }, 347 | "engines": { 348 | "node": ">= 8" 349 | } 350 | }, 351 | "node_modules/wrap-ansi": { 352 | "version": "7.0.0", 353 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 354 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 355 | "dev": true, 356 | "dependencies": { 357 | "ansi-styles": "^4.0.0", 358 | "string-width": "^4.1.0", 359 | "strip-ansi": "^6.0.0" 360 | }, 361 | "engines": { 362 | "node": ">=10" 363 | }, 364 | "funding": { 365 | "url": "https://github.com/chalk/wrap-ansi?sponsor=1" 366 | } 367 | } 368 | }, 369 | "dependencies": { 370 | "@pkgjs/parseargs": { 371 | "version": "0.11.0", 372 | "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", 373 | "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", 374 | "dev": true, 375 | "optional": true 376 | }, 377 | "ansi-regex": { 378 | "version": "5.0.1", 379 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 380 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 381 | "dev": true 382 | }, 383 | "ansi-styles": { 384 | "version": "4.3.0", 385 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 386 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 387 | "dev": true, 388 | "requires": { 389 | "color-convert": "^2.0.1" 390 | } 391 | }, 392 | "balanced-match": { 393 | "version": "1.0.2", 394 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 395 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", 396 | "dev": true 397 | }, 398 | "brace-expansion": { 399 | "version": "2.0.1", 400 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", 401 | "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", 402 | "dev": true, 403 | "requires": { 404 | "balanced-match": "^1.0.0" 405 | } 406 | }, 407 | "cliui": { 408 | "version": "7.0.4", 409 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", 410 | "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", 411 | "dev": true, 412 | "requires": { 413 | "string-width": "^4.2.0", 414 | "strip-ansi": "^6.0.0", 415 | "wrap-ansi": "^7.0.0" 416 | } 417 | }, 418 | "color-convert": { 419 | "version": "2.0.1", 420 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 421 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 422 | "dev": true, 423 | "requires": { 424 | "color-name": "~1.1.4" 425 | } 426 | }, 427 | "color-name": { 428 | "version": "1.1.4", 429 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 430 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", 431 | "dev": true 432 | }, 433 | "cross-spawn": { 434 | "version": "7.0.3", 435 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 436 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 437 | "dev": true, 438 | "requires": { 439 | "path-key": "^3.1.0", 440 | "shebang-command": "^2.0.0", 441 | "which": "^2.0.1" 442 | } 443 | }, 444 | "emoji-regex": { 445 | "version": "8.0.0", 446 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 447 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", 448 | "dev": true 449 | }, 450 | "foreground-child": { 451 | "version": "3.1.1", 452 | "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", 453 | "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", 454 | "dev": true, 455 | "requires": { 456 | "cross-spawn": "^7.0.0", 457 | "signal-exit": "^4.0.1" 458 | } 459 | }, 460 | "glob": { 461 | "version": "10.2.2", 462 | "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.2.tgz", 463 | "integrity": "sha512-Xsa0BcxIC6th9UwNjZkhrMtNo/MnyRL8jGCP+uEwhA5oFOCY1f2s1/oNKY47xQ0Bg5nkjsfAEIej1VeH62bDDQ==", 464 | "dev": true, 465 | "requires": { 466 | "foreground-child": "^3.1.0", 467 | "jackspeak": "^2.0.3", 468 | "minimatch": "^9.0.0", 469 | "minipass": "^5.0.0", 470 | "path-scurry": "^1.7.0" 471 | } 472 | }, 473 | "is-fullwidth-code-point": { 474 | "version": "3.0.0", 475 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 476 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", 477 | "dev": true 478 | }, 479 | "isexe": { 480 | "version": "2.0.0", 481 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 482 | "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", 483 | "dev": true 484 | }, 485 | "jackspeak": { 486 | "version": "2.1.0", 487 | "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.1.0.tgz", 488 | "integrity": "sha512-DiEwVPqsieUzZBNxQ2cxznmFzfg/AMgJUjYw5xl6rSmCxAQXECcbSdwcLM6Ds6T09+SBfSNCGPhYUoQ96P4h7A==", 489 | "dev": true, 490 | "requires": { 491 | "@pkgjs/parseargs": "^0.11.0", 492 | "cliui": "^7.0.4" 493 | } 494 | }, 495 | "lru-cache": { 496 | "version": "9.1.1", 497 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.1.tgz", 498 | "integrity": "sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A==", 499 | "dev": true 500 | }, 501 | "minimatch": { 502 | "version": "9.0.0", 503 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.0.tgz", 504 | "integrity": "sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==", 505 | "dev": true, 506 | "requires": { 507 | "brace-expansion": "^2.0.1" 508 | } 509 | }, 510 | "minimist": { 511 | "version": "1.2.8", 512 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", 513 | "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", 514 | "dev": true 515 | }, 516 | "minipass": { 517 | "version": "5.0.0", 518 | "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", 519 | "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", 520 | "dev": true 521 | }, 522 | "nan": { 523 | "version": "2.17.0", 524 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", 525 | "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" 526 | }, 527 | "path-key": { 528 | "version": "3.1.1", 529 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 530 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 531 | "dev": true 532 | }, 533 | "path-scurry": { 534 | "version": "1.7.0", 535 | "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.7.0.tgz", 536 | "integrity": "sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg==", 537 | "dev": true, 538 | "requires": { 539 | "lru-cache": "^9.0.0", 540 | "minipass": "^5.0.0" 541 | } 542 | }, 543 | "shebang-command": { 544 | "version": "2.0.0", 545 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 546 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 547 | "dev": true, 548 | "requires": { 549 | "shebang-regex": "^3.0.0" 550 | } 551 | }, 552 | "shebang-regex": { 553 | "version": "3.0.0", 554 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 555 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 556 | "dev": true 557 | }, 558 | "signal-exit": { 559 | "version": "4.0.1", 560 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.1.tgz", 561 | "integrity": "sha512-uUWsN4aOxJAS8KOuf3QMyFtgm1pkb6I+KRZbRF/ghdf5T7sM+B1lLLzPDxswUjkmHyxQAVzEgG35E3NzDM9GVw==", 562 | "dev": true 563 | }, 564 | "string-width": { 565 | "version": "4.2.3", 566 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 567 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 568 | "dev": true, 569 | "requires": { 570 | "emoji-regex": "^8.0.0", 571 | "is-fullwidth-code-point": "^3.0.0", 572 | "strip-ansi": "^6.0.1" 573 | } 574 | }, 575 | "strip-ansi": { 576 | "version": "6.0.1", 577 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 578 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 579 | "dev": true, 580 | "requires": { 581 | "ansi-regex": "^5.0.1" 582 | } 583 | }, 584 | "tree-sitter-cli": { 585 | "version": "0.20.8", 586 | "resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.20.8.tgz", 587 | "integrity": "sha512-XjTcS3wdTy/2cc/ptMLc/WRyOLECRYcMTrSWyhZnj1oGSOWbHLTklgsgRICU3cPfb0vy+oZCC33M43u6R1HSCA==", 588 | "dev": true 589 | }, 590 | "which": { 591 | "version": "2.0.2", 592 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 593 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 594 | "dev": true, 595 | "requires": { 596 | "isexe": "^2.0.0" 597 | } 598 | }, 599 | "wrap-ansi": { 600 | "version": "7.0.0", 601 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", 602 | "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", 603 | "dev": true, 604 | "requires": { 605 | "ansi-styles": "^4.0.0", 606 | "string-width": "^4.1.0", 607 | "strip-ansi": "^6.0.0" 608 | } 609 | } 610 | } 611 | } 612 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-zig", 3 | "version": "1.0.0", 4 | "description": "tree-sitter grammar for Zig for use in ZLS", 5 | "main": "bindings/node/index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/zigtools/tree-sitter-zig" 12 | }, 13 | "author": "Auguste Rame", 14 | "license": "MIT", 15 | "dependencies": { 16 | "nan": "^2.17.0" 17 | }, 18 | "devDependencies": { 19 | "glob": "^10.2.2", 20 | "minimist": "^1.2.8", 21 | "tree-sitter-cli": "^0.20.8" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /test/samples/hello.zig: -------------------------------------------------------------------------------- 1 | test { 2 | // a = 1; 3 | // const abc = &.{ 1, 2, 3, 4 }; 4 | // _ = abc; 5 | 6 | if (1 == 1) { 7 | @compileLog("bruh"); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/valid.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import glob 4 | import signal 5 | import hashlib 6 | from tree_sitter import Language, Parser 7 | from concurrent.futures import ThreadPoolExecutor, as_completed 8 | 9 | def execute(path, parser, query): 10 | file = open(path, "rb") 11 | tree = parser.parse(file.read()) 12 | h = hashlib.md5(path.encode("utf-8")).hexdigest() 13 | hp = os.path.join("test", "invalid_outputs", h) 14 | if len(query.captures(tree.root_node)) == 0: 15 | if os.path.exists(hp): 16 | os.remove(hp) 17 | print("✅ " + path) 18 | file.close() 19 | return True 20 | else: 21 | out = open(hp, "w+") 22 | out.write("File: " + path + "\n\n") 23 | out.write(tree.root_node.sexp()) 24 | print("❌ " + path + " (@ " + hp + ")") 25 | out.close() 26 | file.close() 27 | return False 28 | 29 | def main(): 30 | if not os.path.exists("test/invalid_outputs"): 31 | os.mkdir("test/invalid_outputs") 32 | 33 | Language.build_library( 34 | "build/zig-py.so", 35 | 36 | [ 37 | "." 38 | ] 39 | ) 40 | 41 | ZIG_LANGUAGE = Language("build/zig-py.so", "zig") 42 | 43 | query = ZIG_LANGUAGE.query(""" 44 | (ERROR) @error 45 | """) 46 | 47 | parser = Parser() 48 | parser.set_language(ZIG_LANGUAGE) 49 | 50 | paths = [] 51 | passed = 0 52 | for arg in sys.argv[1:]: 53 | paths.extend(glob.glob(arg, recursive=True)) 54 | 55 | executor = ThreadPoolExecutor() 56 | 57 | results = [] 58 | for path in paths: 59 | results.append(executor.submit(execute, path, parser, query)) 60 | 61 | for future in as_completed(results): 62 | if future.result(): 63 | passed += 1 64 | 65 | print("👍 " + str(passed) + " / " + str(len(paths)) + " (" + str(passed / len(paths) * 100) + "%)") 66 | if passed != len(paths): 67 | exit(1) 68 | 69 | if __name__ == "__main__": 70 | if len(sys.argv) == 1: 71 | print("valid.py [paths...]") 72 | else: 73 | main() 74 | --------------------------------------------------------------------------------