├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── fuzz.yml │ ├── lint.yml │ └── publish.yml ├── .gitignore ├── CMakeLists.txt ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── Makefile ├── Package.resolved ├── Package.swift ├── README.md ├── binding.gyp ├── bindings ├── c │ ├── tree-sitter-rust.h │ └── tree-sitter-rust.pc.in ├── go │ ├── binding.go │ └── binding_test.go ├── node │ ├── binding.cc │ ├── binding_test.js │ ├── index.d.ts │ └── index.js ├── python │ ├── tests │ │ └── test_binding.py │ └── tree_sitter_rust │ │ ├── __init__.py │ │ ├── __init__.pyi │ │ ├── binding.c │ │ └── py.typed ├── rust │ ├── build.rs │ └── lib.rs └── swift │ ├── TreeSitterRust │ └── rust.h │ └── TreeSitterRustTests │ └── TreeSitterRustTests.swift ├── eslint.config.mjs ├── examples ├── ast.rs └── weird-exprs.rs ├── go.mod ├── go.sum ├── grammar.js ├── package-lock.json ├── package.json ├── pyproject.toml ├── queries ├── highlights.scm ├── injections.scm └── tags.scm ├── setup.py ├── src ├── grammar.json ├── node-types.json ├── parser.c ├── scanner.c └── tree_sitter │ ├── alloc.h │ ├── array.h │ └── parser.h ├── test └── corpus │ ├── async.txt │ ├── declarations.txt │ ├── expressions.txt │ ├── literals.txt │ ├── macros.txt │ ├── patterns.txt │ ├── source_files.txt │ └── types.txt └── tree-sitter.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | 6 | [*.{json,toml,yml,gyp}] 7 | indent_style = space 8 | indent_size = 2 9 | 10 | [*.js] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.scm] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.{c,cc,h}] 19 | indent_style = space 20 | indent_size = 4 21 | 22 | [*.rs] 23 | indent_style = space 24 | indent_size = 4 25 | 26 | [*.{py,pyi}] 27 | indent_style = space 28 | indent_size = 4 29 | 30 | [*.swift] 31 | indent_style = space 32 | indent_size = 4 33 | 34 | [*.go] 35 | indent_style = tab 36 | indent_size = 8 37 | 38 | [Makefile] 39 | indent_style = tab 40 | indent_size = 8 41 | 42 | [parser.c] 43 | indent_size = 2 44 | 45 | [{alloc,array,parser}.h] 46 | indent_size = 2 47 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | # Generated source files 4 | src/*.json linguist-generated 5 | src/parser.c linguist-generated 6 | src/tree_sitter/* linguist-generated 7 | 8 | # C bindings 9 | bindings/c/* linguist-generated 10 | CMakeLists.txt linguist-generated 11 | Makefile linguist-generated 12 | 13 | # Rust bindings 14 | bindings/rust/* linguist-generated 15 | Cargo.toml linguist-generated 16 | Cargo.lock linguist-generated 17 | 18 | # Node.js bindings 19 | bindings/node/* linguist-generated 20 | binding.gyp linguist-generated 21 | package.json linguist-generated 22 | package-lock.json linguist-generated 23 | 24 | # Python bindings 25 | bindings/python/** linguist-generated 26 | setup.py linguist-generated 27 | pyproject.toml linguist-generated 28 | 29 | # Go bindings 30 | bindings/go/* linguist-generated 31 | go.mod linguist-generated 32 | go.sum linguist-generated 33 | 34 | # Swift bindings 35 | bindings/swift/** linguist-generated 36 | Package.swift linguist-generated 37 | Package.resolved linguist-generated 38 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: tree-sitter 4 | patreon: # Replace with a single Patreon username 5 | open_collective: tree-sitter # Replace with a single Open Collective username 6 | ko_fi: amaanq 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: File a bug or issue 3 | title: "bug: " 4 | labels: [bug] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | **Before** reporting an issue, make sure to search [existing issues](https://github.com/tree-sitter/tree-sitter-rust/issues). Usage questions such as ***"How do I...?"*** either belong in [Discussions](https://github.com/tree-sitter/tree-sitter/discussions) upstream or in our [Discord server](https://discord.gg/w7nTvsVJhm) and will be closed. 10 | If your issue is related to a bug in your editor-experience because your editor *leverages* tree-sitter and this parser, then it is likely your issue does *NOT* belong here and belongs in the relevant editor's repository. 11 | - type: checkboxes 12 | attributes: 13 | label: Did you check existing issues? 14 | description: Make sure you've checked all of the below before submitting an issue 15 | options: 16 | - label: I have read all the [tree-sitter docs](https://tree-sitter.github.io/tree-sitter/using-parsers) if it relates to using the parser 17 | required: false 18 | - label: I have searched the existing issues of tree-sitter-rust 19 | required: true 20 | - type: input 21 | attributes: 22 | label: "Tree-Sitter CLI Version, if relevant (output of `tree-sitter --version`)" 23 | placeholder: "tree-sitter 0.20.8 (6bbb50bef8249e6460e7d69e42cc8146622fa4fd)" 24 | validations: 25 | required: false 26 | - type: textarea 27 | attributes: 28 | label: Describe the bug 29 | description: A clear and concise description of what the bug is. Please include any related errors you see such as parsing errors or tree-sitter cli errors. 30 | validations: 31 | required: true 32 | - type: textarea 33 | attributes: 34 | label: Steps To Reproduce/Bad Parse Tree 35 | description: Steps to reproduce the behavior. If you have a bad parse tree, please include it here. You can get this by running `tree-sitter parse ` and copying the output. 36 | placeholder: | 37 | 1. 38 | 2. 39 | 3. 40 | validations: 41 | required: true 42 | - type: textarea 43 | attributes: 44 | label: Expected Behavior/Parse Tree 45 | description: A concise description of what you expected to happen, or in the case of a bad parse tree, the expected parse tree. 46 | validations: 47 | required: true 48 | - type: textarea 49 | attributes: 50 | label: Repro 51 | description: Minimal code to reproduce this issue. Ideally this should be reproducible with the C library or the tree-sitter cli, do not suggest an editor or external tool. 52 | value: | 53 | // Example code that causes the issue 54 | fn foo() { 55 | // Code that fails to parse, or causes an error 56 | } 57 | render: Rust 58 | validations: 59 | required: false 60 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Suggest a new feature 3 | title: "feature: " 4 | labels: [enhancement] 5 | body: 6 | - type: checkboxes 7 | attributes: 8 | label: Did you check the tree-sitter docs? 9 | description: Make sure you read all the docs before submitting a feature request 10 | options: 11 | - label: I have read all the [tree-sitter docs](https://tree-sitter.github.io/tree-sitter/using-parsers) if it relates to using the parser 12 | required: false 13 | - type: textarea 14 | validations: 15 | required: true 16 | attributes: 17 | label: Is your feature request related to a problem? Please describe. 18 | description: A clear and concise description of what the problem is. Ex. I think the grammar models this rule incorrectly and can be improved, or the scanner can be improved by doing [...], or Rust has officially added a new feature that should be added to the grammar. 19 | - type: textarea 20 | validations: 21 | required: true 22 | attributes: 23 | label: Describe the solution you'd like 24 | description: A clear and concise description of what you want to happen. 25 | - type: textarea 26 | validations: 27 | required: true 28 | attributes: 29 | label: Describe alternatives you've considered 30 | description: A clear and concise description of any alternative solutions or features you've considered. 31 | - type: textarea 32 | validations: 33 | required: false 34 | attributes: 35 | label: Additional context 36 | description: Add any other context or screenshots about the feature request here. If your feature request is related to a new Rust feature, please include a link to the relevant **official** Rust documentation. 37 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | commit-message: 8 | prefix: "ci" 9 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | paths: 7 | - grammar.js 8 | - src/** 9 | - test/** 10 | - bindings/** 11 | - binding.gyp 12 | pull_request: 13 | paths: 14 | - grammar.js 15 | - src/** 16 | - test/** 17 | - bindings/** 18 | - binding.gyp 19 | 20 | concurrency: 21 | group: ${{github.workflow}}-${{github.ref}} 22 | cancel-in-progress: true 23 | 24 | jobs: 25 | test: 26 | name: Test parser 27 | runs-on: ${{matrix.os}} 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | os: [ubuntu-latest, windows-latest, macos-14] 32 | steps: 33 | - name: Checkout repository 34 | uses: actions/checkout@v4 35 | - name: Set up tree-sitter 36 | uses: tree-sitter/setup-action/cli@v2 37 | - name: Set up examples 38 | run: |- 39 | git clone https://github.com/rust-lang-nursery/bitflags examples/bitflags --single-branch --depth=1 --filter=blob:none 40 | git clone https://github.com/rust-lang/libc examples/libc --single-branch --depth=1 --filter=blob:none 41 | git clone https://github.com/rust-lang/regex examples/regex --single-branch --depth=1 --filter=blob:none 42 | git clone https://github.com/serde-rs/serde examples/serde --single-branch --depth=1 --filter=blob:none 43 | git clone https://github.com/tokio-rs/tokio examples/tokio --single-branch --depth=1 --filter=blob:none 44 | - name: Run tests 45 | uses: tree-sitter/parser-test-action@v2 46 | with: 47 | test-rust: true 48 | test-node: true 49 | test-python: true 50 | test-go: true 51 | test-swift: true 52 | - name: Parse examples 53 | uses: tree-sitter/parse-action@v4 54 | with: 55 | files: examples/**/*.rs 56 | -------------------------------------------------------------------------------- /.github/workflows/fuzz.yml: -------------------------------------------------------------------------------- 1 | name: Fuzz Parser 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | paths: 7 | - src/scanner.c 8 | pull_request: 9 | paths: 10 | - src/scanner.c 11 | 12 | jobs: 13 | fuzz: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | - name: Run fuzzer 19 | uses: tree-sitter/fuzz-action@v4 20 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | paths: 7 | - grammar.js 8 | pull_request: 9 | paths: 10 | - grammar.js 11 | 12 | jobs: 13 | lint: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | - name: Set up Node.js 19 | uses: actions/setup-node@v4 20 | with: 21 | cache: npm 22 | node-version: ${{vars.NODE_VERSION}} 23 | - name: Install modules 24 | run: npm ci --legacy-peer-deps 25 | - name: Run ESLint 26 | run: npm run lint 27 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish packages 2 | 3 | on: 4 | push: 5 | tags: ["*"] 6 | 7 | permissions: 8 | contents: write 9 | id-token: write 10 | attestations: write 11 | 12 | jobs: 13 | github: 14 | uses: tree-sitter/workflows/.github/workflows/release.yml@main 15 | with: 16 | generate: true 17 | attestations: true 18 | npm: 19 | uses: tree-sitter/workflows/.github/workflows/package-npm.yml@main 20 | secrets: 21 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 22 | with: 23 | generate: true 24 | crates: 25 | uses: tree-sitter/workflows/.github/workflows/package-crates.yml@main 26 | secrets: 27 | CARGO_REGISTRY_TOKEN: ${{secrets.CARGO_REGISTRY_TOKEN}} 28 | with: 29 | generate: true 30 | pypi: 31 | uses: tree-sitter/workflows/.github/workflows/package-pypi.yml@main 32 | secrets: 33 | PYPI_API_TOKEN: ${{secrets.PYPI_API_TOKEN}} 34 | with: 35 | generate: true 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust artifacts 2 | target/ 3 | 4 | # Node artifacts 5 | build/ 6 | prebuilds/ 7 | node_modules/ 8 | 9 | # Swift artifacts 10 | .build/ 11 | 12 | # Go artifacts 13 | _obj/ 14 | 15 | # Python artifacts 16 | .venv/ 17 | dist/ 18 | *.egg-info 19 | *.whl 20 | 21 | # C artifacts 22 | *.a 23 | *.so 24 | *.so.* 25 | *.dylib 26 | *.dll 27 | *.pc 28 | 29 | # Example dirs 30 | /examples/*/ 31 | 32 | # Grammar volatiles 33 | *.wasm 34 | *.obj 35 | *.o 36 | 37 | # Archives 38 | *.tar.gz 39 | *.tgz 40 | *.zip 41 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | project(tree-sitter-rust 4 | VERSION "0.24.0" 5 | DESCRIPTION "Rust grammar for tree-sitter" 6 | HOMEPAGE_URL "https://github.com/tree-sitter/tree-sitter-rust" 7 | LANGUAGES C) 8 | 9 | option(BUILD_SHARED_LIBS "Build using shared libraries" ON) 10 | option(TREE_SITTER_REUSE_ALLOCATOR "Reuse the library allocator" OFF) 11 | 12 | set(TREE_SITTER_ABI_VERSION 14 CACHE STRING "Tree-sitter ABI version") 13 | if(NOT ${TREE_SITTER_ABI_VERSION} MATCHES "^[0-9]+$") 14 | unset(TREE_SITTER_ABI_VERSION CACHE) 15 | message(FATAL_ERROR "TREE_SITTER_ABI_VERSION must be an integer") 16 | endif() 17 | 18 | find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI") 19 | 20 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c" 21 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json" 22 | COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json 23 | --abi=${TREE_SITTER_ABI_VERSION} 24 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 25 | COMMENT "Generating parser.c") 26 | 27 | add_library(tree-sitter-rust src/parser.c) 28 | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/scanner.c) 29 | target_sources(tree-sitter-rust PRIVATE src/scanner.c) 30 | endif() 31 | target_include_directories(tree-sitter-rust PRIVATE src) 32 | 33 | target_compile_definitions(tree-sitter-rust PRIVATE 34 | $<$:TREE_SITTER_REUSE_ALLOCATOR> 35 | $<$:TREE_SITTER_DEBUG>) 36 | 37 | set_target_properties(tree-sitter-rust 38 | PROPERTIES 39 | C_STANDARD 11 40 | POSITION_INDEPENDENT_CODE ON 41 | SOVERSION "${TREE_SITTER_ABI_VERSION}.${PROJECT_VERSION_MAJOR}" 42 | DEFINE_SYMBOL "") 43 | 44 | configure_file(bindings/c/tree-sitter-rust.pc.in 45 | "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-rust.pc" @ONLY) 46 | 47 | include(GNUInstallDirs) 48 | 49 | install(FILES bindings/c/tree-sitter-rust.h 50 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/tree_sitter") 51 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-rust.pc" 52 | DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig") 53 | install(TARGETS tree-sitter-rust 54 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") 55 | 56 | add_custom_target(ts-test "${TREE_SITTER_CLI}" test 57 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 58 | COMMENT "tree-sitter test") 59 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "cc" 16 | version = "1.2.17" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" 19 | dependencies = [ 20 | "shlex", 21 | ] 22 | 23 | [[package]] 24 | name = "equivalent" 25 | version = "1.0.2" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 28 | 29 | [[package]] 30 | name = "hashbrown" 31 | version = "0.15.2" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 34 | 35 | [[package]] 36 | name = "indexmap" 37 | version = "2.8.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" 40 | dependencies = [ 41 | "equivalent", 42 | "hashbrown", 43 | ] 44 | 45 | [[package]] 46 | name = "itoa" 47 | version = "1.0.15" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 50 | 51 | [[package]] 52 | name = "memchr" 53 | version = "2.7.4" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 56 | 57 | [[package]] 58 | name = "proc-macro2" 59 | version = "1.0.94" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" 62 | dependencies = [ 63 | "unicode-ident", 64 | ] 65 | 66 | [[package]] 67 | name = "quote" 68 | version = "1.0.40" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 71 | dependencies = [ 72 | "proc-macro2", 73 | ] 74 | 75 | [[package]] 76 | name = "regex" 77 | version = "1.11.1" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" 80 | dependencies = [ 81 | "aho-corasick", 82 | "memchr", 83 | "regex-automata", 84 | "regex-syntax", 85 | ] 86 | 87 | [[package]] 88 | name = "regex-automata" 89 | version = "0.4.9" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 92 | dependencies = [ 93 | "aho-corasick", 94 | "memchr", 95 | "regex-syntax", 96 | ] 97 | 98 | [[package]] 99 | name = "regex-syntax" 100 | version = "0.8.5" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" 103 | 104 | [[package]] 105 | name = "ryu" 106 | version = "1.0.20" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 109 | 110 | [[package]] 111 | name = "serde" 112 | version = "1.0.219" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 115 | dependencies = [ 116 | "serde_derive", 117 | ] 118 | 119 | [[package]] 120 | name = "serde_derive" 121 | version = "1.0.219" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 124 | dependencies = [ 125 | "proc-macro2", 126 | "quote", 127 | "syn", 128 | ] 129 | 130 | [[package]] 131 | name = "serde_json" 132 | version = "1.0.140" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 135 | dependencies = [ 136 | "indexmap", 137 | "itoa", 138 | "memchr", 139 | "ryu", 140 | "serde", 141 | ] 142 | 143 | [[package]] 144 | name = "shlex" 145 | version = "1.3.0" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 148 | 149 | [[package]] 150 | name = "streaming-iterator" 151 | version = "0.1.9" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520" 154 | 155 | [[package]] 156 | name = "syn" 157 | version = "2.0.100" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 160 | dependencies = [ 161 | "proc-macro2", 162 | "quote", 163 | "unicode-ident", 164 | ] 165 | 166 | [[package]] 167 | name = "tree-sitter" 168 | version = "0.25.3" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "b9ac5ea5e7f2f1700842ec071401010b9c59bf735295f6e9fa079c3dc035b167" 171 | dependencies = [ 172 | "cc", 173 | "regex", 174 | "regex-syntax", 175 | "serde_json", 176 | "streaming-iterator", 177 | "tree-sitter-language", 178 | ] 179 | 180 | [[package]] 181 | name = "tree-sitter-language" 182 | version = "0.1.5" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "c4013970217383f67b18aef68f6fb2e8d409bc5755227092d32efb0422ba24b8" 185 | 186 | [[package]] 187 | name = "tree-sitter-rust" 188 | version = "0.24.0" 189 | dependencies = [ 190 | "cc", 191 | "tree-sitter", 192 | "tree-sitter-language", 193 | ] 194 | 195 | [[package]] 196 | name = "unicode-ident" 197 | version = "1.0.18" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 200 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tree-sitter-rust" 3 | description = "Rust grammar for tree-sitter" 4 | version = "0.24.0" 5 | authors = [ 6 | "Max Brunsfeld ", 7 | "Amaan Qureshi ", 8 | ] 9 | license = "MIT" 10 | readme = "README.md" 11 | keywords = ["incremental", "parsing", "tree-sitter", "rust"] 12 | categories = ["parsing", "text-editors"] 13 | repository = "https://github.com/tree-sitter/tree-sitter-rust" 14 | edition = "2021" 15 | autoexamples = false 16 | 17 | build = "bindings/rust/build.rs" 18 | include = ["bindings/rust/*", "grammar.js", "queries/*", "src/*", "tree-sitter.json"] 19 | 20 | [lib] 21 | path = "bindings/rust/lib.rs" 22 | 23 | [dependencies] 24 | tree-sitter-language = "0.1" 25 | 26 | [build-dependencies] 27 | cc = "1.1" 28 | 29 | [dev-dependencies] 30 | tree-sitter = "0.25" 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Maxim Sokolov 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 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | $(error Windows is not supported) 3 | endif 4 | 5 | LANGUAGE_NAME := tree-sitter-rust 6 | HOMEPAGE_URL := https://github.com/tree-sitter/tree-sitter-rust 7 | VERSION := 0.24.0 8 | 9 | # repository 10 | SRC_DIR := src 11 | 12 | TS ?= tree-sitter 13 | 14 | # install directory layout 15 | PREFIX ?= /usr/local 16 | INCLUDEDIR ?= $(PREFIX)/include 17 | LIBDIR ?= $(PREFIX)/lib 18 | PCLIBDIR ?= $(LIBDIR)/pkgconfig 19 | 20 | # source/object files 21 | PARSER := $(SRC_DIR)/parser.c 22 | EXTRAS := $(filter-out $(PARSER),$(wildcard $(SRC_DIR)/*.c)) 23 | OBJS := $(patsubst %.c,%.o,$(PARSER) $(EXTRAS)) 24 | 25 | # flags 26 | ARFLAGS ?= rcs 27 | override CFLAGS += -I$(SRC_DIR) -std=c11 -fPIC 28 | 29 | # ABI versioning 30 | SONAME_MAJOR = $(shell sed -n 's/\#define LANGUAGE_VERSION //p' $(PARSER)) 31 | SONAME_MINOR = $(word 1,$(subst ., ,$(VERSION))) 32 | 33 | # OS-specific bits 34 | ifeq ($(shell uname),Darwin) 35 | SOEXT = dylib 36 | SOEXTVER_MAJOR = $(SONAME_MAJOR).$(SOEXT) 37 | SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).$(SOEXT) 38 | LINKSHARED = -dynamiclib -Wl,-install_name,$(LIBDIR)/lib$(LANGUAGE_NAME).$(SOEXTVER),-rpath,@executable_path/../Frameworks 39 | else 40 | SOEXT = so 41 | SOEXTVER_MAJOR = $(SOEXT).$(SONAME_MAJOR) 42 | SOEXTVER = $(SOEXT).$(SONAME_MAJOR).$(SONAME_MINOR) 43 | LINKSHARED = -shared -Wl,-soname,lib$(LANGUAGE_NAME).$(SOEXTVER) 44 | endif 45 | ifneq ($(filter $(shell uname),FreeBSD NetBSD DragonFly),) 46 | PCLIBDIR := $(PREFIX)/libdata/pkgconfig 47 | endif 48 | 49 | all: lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) $(LANGUAGE_NAME).pc 50 | 51 | lib$(LANGUAGE_NAME).a: $(OBJS) 52 | $(AR) $(ARFLAGS) $@ $^ 53 | 54 | lib$(LANGUAGE_NAME).$(SOEXT): $(OBJS) 55 | $(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@ 56 | ifneq ($(STRIP),) 57 | $(STRIP) $@ 58 | endif 59 | 60 | $(LANGUAGE_NAME).pc: bindings/c/$(LANGUAGE_NAME).pc.in 61 | sed -e 's|@PROJECT_VERSION@|$(VERSION)|' \ 62 | -e 's|@CMAKE_INSTALL_LIBDIR@|$(LIBDIR:$(PREFIX)/%=%)|' \ 63 | -e 's|@CMAKE_INSTALL_INCLUDEDIR@|$(INCLUDEDIR:$(PREFIX)/%=%)|' \ 64 | -e 's|@PROJECT_DESCRIPTION@|$(DESCRIPTION)|' \ 65 | -e 's|@PROJECT_HOMEPAGE_URL@|$(HOMEPAGE_URL)|' \ 66 | -e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|' $< > $@ 67 | 68 | $(PARSER): $(SRC_DIR)/grammar.json 69 | $(TS) generate $^ 70 | 71 | install: all 72 | install -d '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)' 73 | install -m644 bindings/c/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h 74 | install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc 75 | install -m644 lib$(LANGUAGE_NAME).a '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a 76 | install -m755 lib$(LANGUAGE_NAME).$(SOEXT) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) 77 | ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) 78 | ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) 79 | 80 | uninstall: 81 | $(RM) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a \ 82 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) \ 83 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) \ 84 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) \ 85 | '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h \ 86 | '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc 87 | 88 | clean: 89 | $(RM) $(OBJS) $(LANGUAGE_NAME).pc lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) 90 | 91 | test: 92 | $(TS) test 93 | 94 | .PHONY: all install uninstall clean test 95 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "SwiftTreeSitter", 6 | "repositoryURL": "https://github.com/ChimeHQ/SwiftTreeSitter", 7 | "state": { 8 | "branch": null, 9 | "revision": "2599e95310b3159641469d8a21baf2d3d200e61f", 10 | "version": "0.8.0" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | import PackageDescription 3 | 4 | let package = Package( 5 | name: "TreeSitterRust", 6 | products: [ 7 | .library(name: "TreeSitterRust", targets: ["TreeSitterRust"]), 8 | ], 9 | dependencies: [ 10 | .package(url: "https://github.com/ChimeHQ/SwiftTreeSitter", from: "0.8.0"), 11 | ], 12 | targets: [ 13 | .target( 14 | name: "TreeSitterRust", 15 | dependencies: [], 16 | path: ".", 17 | sources: [ 18 | "src/parser.c", 19 | "src/scanner.c", 20 | ], 21 | resources: [ 22 | .copy("queries") 23 | ], 24 | publicHeadersPath: "bindings/swift", 25 | cSettings: [.headerSearchPath("src")] 26 | ), 27 | .testTarget( 28 | name: "TreeSitterRustTests", 29 | dependencies: [ 30 | "SwiftTreeSitter", 31 | "TreeSitterRust", 32 | ], 33 | path: "bindings/swift/TreeSitterRustTests" 34 | ) 35 | ], 36 | cLanguageStandard: .c11 37 | ) 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tree-sitter-rust 2 | 3 | [![CI][ci]](https://github.com/tree-sitter/tree-sitter-rust/actions/workflows/ci.yml) 4 | [![discord][discord]](https://discord.gg/w7nTvsVJhm) 5 | [![matrix][matrix]](https://matrix.to/#/#tree-sitter-chat:matrix.org) 6 | [![crates][crates]](https://crates.io/crates/tree-sitter-rust) 7 | [![npm][npm]](https://www.npmjs.com/package/tree-sitter-rust) 8 | [![pypi][pypi]](https://pypi.org/project/tree-sitter-rust) 9 | 10 | Rust grammar for [tree-sitter](https://github.com/tree-sitter/tree-sitter). 11 | 12 | ## Features 13 | 14 | - **Speed** — When initially parsing a file, `tree-sitter-rust` takes around two to three times 15 | as long as rustc's hand-written parser. 16 | 17 | ```sh 18 | $ wc -l examples/ast.rs 19 | 2157 examples/ast.rs 20 | 21 | $ rustc -Z unpretty=ast-tree -Z time-passes examples/ast.rs | head -n0 22 | time: 0.002; rss: 55MB -> 60MB ( +5MB) parse_crate 23 | 24 | $ tree-sitter parse examples/ast.rs --quiet --time 25 | examples/ast.rs 6.48 ms 9908 bytes/ms 26 | ``` 27 | 28 | But if you _edit_ the file after parsing it, tree-sitter can generally _update_ 29 | the previous existing syntax tree to reflect your edit in less than a millisecond, 30 | thanks to its incremental parsing system. 31 | 32 | ## References 33 | 34 | - [The Rust Reference](https://doc.rust-lang.org/reference/) — While Rust does 35 | not have a specification, the reference tries to describe its working in detail. 36 | It tends to be out of date. 37 | - [Keywords](https://doc.rust-lang.org/stable/book/appendix-01-keywords.html) and 38 | [Operators and Symbols](https://doc.rust-lang.org/stable/book/appendix-02-operators.html). 39 | 40 | [ci]: https://img.shields.io/github/actions/workflow/status/tree-sitter/tree-sitter-rust/ci.yml?logo=github&label=CI 41 | [discord]: https://img.shields.io/discord/1063097320771698699?logo=discord&label=discord 42 | [matrix]: https://img.shields.io/matrix/tree-sitter-chat%3Amatrix.org?logo=matrix&label=matrix 43 | [npm]: https://img.shields.io/npm/v/tree-sitter-rust?logo=npm 44 | [crates]: https://img.shields.io/crates/v/tree-sitter-rust?logo=rust 45 | [pypi]: https://img.shields.io/pypi/v/tree-sitter-rust?logo=pypi&logoColor=ffd242 46 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_rust_binding", 5 | "dependencies": [ 6 | " 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | extern "C" TSLanguage *tree_sitter_rust(); 6 | 7 | // "tree-sitter", "language" hashed with BLAKE2 8 | const napi_type_tag LANGUAGE_TYPE_TAG = { 9 | 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16 10 | }; 11 | 12 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 13 | exports["name"] = Napi::String::New(env, "rust"); 14 | auto language = Napi::External::New(env, tree_sitter_rust()); 15 | language.TypeTag(&LANGUAGE_TYPE_TAG); 16 | exports["language"] = language; 17 | return exports; 18 | } 19 | 20 | NODE_API_MODULE(tree_sitter_rust_binding, Init) 21 | -------------------------------------------------------------------------------- /bindings/node/binding_test.js: -------------------------------------------------------------------------------- 1 | const assert = require("node:assert"); 2 | const { test } = require("node:test"); 3 | 4 | const Parser = require("tree-sitter"); 5 | 6 | test("can load grammar", () => { 7 | const parser = new Parser(); 8 | assert.doesNotThrow(() => parser.setLanguage(require("."))); 9 | }); 10 | -------------------------------------------------------------------------------- /bindings/node/index.d.ts: -------------------------------------------------------------------------------- 1 | type BaseNode = { 2 | type: string; 3 | named: boolean; 4 | }; 5 | 6 | type ChildNode = { 7 | multiple: boolean; 8 | required: boolean; 9 | types: BaseNode[]; 10 | }; 11 | 12 | type NodeInfo = 13 | | (BaseNode & { 14 | subtypes: BaseNode[]; 15 | }) 16 | | (BaseNode & { 17 | fields: { [name: string]: ChildNode }; 18 | children: ChildNode[]; 19 | }); 20 | 21 | type Language = { 22 | name: string; 23 | language: unknown; 24 | nodeTypeInfo: NodeInfo[]; 25 | }; 26 | 27 | declare const language: Language; 28 | export = language; 29 | -------------------------------------------------------------------------------- /bindings/node/index.js: -------------------------------------------------------------------------------- 1 | const root = require("path").join(__dirname, "..", ".."); 2 | 3 | module.exports = 4 | typeof process.versions.bun === "string" 5 | // Support `bun build --compile` by being statically analyzable enough to find the .node file at build-time 6 | ? require(`../../prebuilds/${process.platform}-${process.arch}/tree-sitter-rust.node`) 7 | : require("node-gyp-build")(root); 8 | 9 | try { 10 | module.exports.nodeTypeInfo = require("../../src/node-types.json"); 11 | } catch (_) {} 12 | -------------------------------------------------------------------------------- /bindings/python/tests/test_binding.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import tree_sitter, tree_sitter_rust 4 | 5 | 6 | class TestLanguage(TestCase): 7 | def test_can_load_grammar(self): 8 | try: 9 | tree_sitter.Language(tree_sitter_rust.language()) 10 | except Exception: 11 | self.fail("Error loading Rust grammar") 12 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_rust/__init__.py: -------------------------------------------------------------------------------- 1 | """Rust grammar for tree-sitter""" 2 | 3 | from importlib.resources import files as _files 4 | 5 | from ._binding import language 6 | 7 | 8 | def _get_query(name, file): 9 | query = _files(f"{__package__}.queries") / file 10 | globals()[name] = query.read_text() 11 | return globals()[name] 12 | 13 | 14 | def __getattr__(name): 15 | if name == "HIGHLIGHTS_QUERY": 16 | return _get_query("HIGHLIGHTS_QUERY", "highlights.scm") 17 | if name == "INJECTIONS_QUERY": 18 | return _get_query("INJECTIONS_QUERY", "injections.scm") 19 | if name == "TAGS_QUERY": 20 | return _get_query("TAGS_QUERY", "tags.scm") 21 | 22 | raise AttributeError(f"module {__name__!r} has no attribute {name!r}") 23 | 24 | 25 | __all__ = [ 26 | "language", 27 | "HIGHLIGHTS_QUERY", 28 | "INJECTIONS_QUERY", 29 | "TAGS_QUERY", 30 | ] 31 | 32 | 33 | def __dir__(): 34 | return sorted(__all__ + [ 35 | "__all__", "__builtins__", "__cached__", "__doc__", "__file__", 36 | "__loader__", "__name__", "__package__", "__path__", "__spec__", 37 | ]) 38 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_rust/__init__.pyi: -------------------------------------------------------------------------------- 1 | from typing import Final 2 | 3 | HIGHLIGHTS_QUERY: Final[str] 4 | INJECTIONS_QUERY: Final[str] 5 | TAGS_QUERY: Final[str] 6 | 7 | def language() -> object: ... 8 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_rust/binding.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | TSLanguage *tree_sitter_rust(void); 6 | 7 | static PyObject* _binding_language(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { 8 | return PyCapsule_New(tree_sitter_rust(), "tree_sitter.Language", NULL); 9 | } 10 | 11 | static PyMethodDef methods[] = { 12 | {"language", _binding_language, METH_NOARGS, 13 | "Get the tree-sitter language for this grammar."}, 14 | {NULL, NULL, 0, NULL} 15 | }; 16 | 17 | static struct PyModuleDef module = { 18 | .m_base = PyModuleDef_HEAD_INIT, 19 | .m_name = "_binding", 20 | .m_doc = NULL, 21 | .m_size = -1, 22 | .m_methods = methods 23 | }; 24 | 25 | PyMODINIT_FUNC PyInit__binding(void) { 26 | return PyModule_Create(&module); 27 | } 28 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_rust/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tree-sitter/tree-sitter-rust/3691201b01cacb2f96ffca4c632c4e938bfacd88/bindings/python/tree_sitter_rust/py.typed -------------------------------------------------------------------------------- /bindings/rust/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let src_dir = std::path::Path::new("src"); 3 | 4 | let mut c_config = cc::Build::new(); 5 | c_config.std("c11").include(src_dir); 6 | 7 | #[cfg(target_env = "msvc")] 8 | c_config.flag("-utf-8"); 9 | 10 | let parser_path = src_dir.join("parser.c"); 11 | c_config.file(&parser_path); 12 | println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); 13 | 14 | let scanner_path = src_dir.join("scanner.c"); 15 | c_config.file(&scanner_path); 16 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 17 | 18 | c_config.compile("tree-sitter-rust"); 19 | } 20 | -------------------------------------------------------------------------------- /bindings/rust/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate provides Rust language support for the [tree-sitter][] parsing library. 2 | //! 3 | //! Typically, you will use the [LANGUAGE][] constant to add this language to a 4 | //! tree-sitter [Parser][], and then use the parser to parse some code: 5 | //! 6 | //! ``` 7 | //! use tree_sitter::Parser; 8 | //! 9 | //! let code = r#" 10 | //! fn double(x: i32) -> i32 { 11 | //! x * 2 12 | //! } 13 | //! "#; 14 | //! let mut parser = Parser::new(); 15 | //! let language = tree_sitter_rust::LANGUAGE; 16 | //! parser 17 | //! .set_language(&language.into()) 18 | //! .expect("Error loading Rust parser"); 19 | //! let tree = parser.parse(code, None).unwrap(); 20 | //! assert!(!tree.root_node().has_error()); 21 | //! ``` 22 | //! 23 | //! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html 24 | //! [tree-sitter]: https://tree-sitter.github.io/ 25 | 26 | use tree_sitter_language::LanguageFn; 27 | 28 | extern "C" { 29 | fn tree_sitter_rust() -> *const (); 30 | } 31 | 32 | /// The tree-sitter [`LanguageFn`][LanguageFn] for this grammar. 33 | /// 34 | /// [LanguageFn]: https://docs.rs/tree-sitter-language/*/tree_sitter_language/struct.LanguageFn.html 35 | pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_rust) }; 36 | 37 | /// The content of the [`node-types.json`][] file for this grammar. 38 | /// 39 | /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types 40 | pub const NODE_TYPES: &str = include_str!("../../src/node-types.json"); 41 | 42 | /// The syntax highlighting query for this language. 43 | pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); 44 | 45 | /// The injections query for this language. 46 | pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); 47 | 48 | /// The symbol tagging query for this language. 49 | pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm"); 50 | 51 | #[cfg(test)] 52 | mod tests { 53 | #[test] 54 | fn test_can_load_grammar() { 55 | let mut parser = tree_sitter::Parser::new(); 56 | parser 57 | .set_language(&super::LANGUAGE.into()) 58 | .expect("Error loading Rust parser"); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /bindings/swift/TreeSitterRust/rust.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_RUST_H_ 2 | #define TREE_SITTER_RUST_H_ 3 | 4 | typedef struct TSLanguage TSLanguage; 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | const TSLanguage *tree_sitter_rust(void); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif // TREE_SITTER_RUST_H_ 17 | -------------------------------------------------------------------------------- /bindings/swift/TreeSitterRustTests/TreeSitterRustTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import SwiftTreeSitter 3 | import TreeSitterRust 4 | 5 | final class TreeSitterRustTests: XCTestCase { 6 | func testCanLoadGrammar() throws { 7 | let parser = Parser() 8 | let language = Language(language: tree_sitter_rust()) 9 | XCTAssertNoThrow(try parser.setLanguage(language), 10 | "Error loading Rust grammar") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import treesitter from 'eslint-config-treesitter'; 2 | 3 | export default [ 4 | ...treesitter, 5 | ]; 6 | -------------------------------------------------------------------------------- /examples/weird-exprs.rs: -------------------------------------------------------------------------------- 1 | //@ run-pass 2 | 3 | #![feature(coroutines)] 4 | 5 | #![allow(non_camel_case_types)] 6 | #![allow(dead_code)] 7 | #![allow(redundant_semicolons)] 8 | #![allow(unreachable_code)] 9 | #![allow(unused_braces, unused_must_use, unused_parens)] 10 | #![allow(uncommon_codepoints, confusable_idents)] 11 | #![allow(unused_imports)] 12 | #![allow(unreachable_patterns)] 13 | 14 | #![recursion_limit = "256"] 15 | 16 | extern crate core; 17 | use std::cell::Cell; 18 | use std::mem::swap; 19 | use std::ops::Deref; 20 | 21 | // Just a grab bag of stuff that you wouldn't want to actually write. 22 | 23 | fn strange() -> bool { let _x: bool = return true; } 24 | 25 | fn funny() { 26 | fn f(_x: ()) { } 27 | f(return); 28 | } 29 | 30 | fn what() { 31 | fn the(x: &Cell) { 32 | return while !x.get() { x.set(true); }; 33 | } 34 | let i = &Cell::new(false); 35 | let dont = {||the(i)}; 36 | dont(); 37 | assert!((i.get())); 38 | } 39 | 40 | fn zombiejesus() { 41 | loop { 42 | while (return) { 43 | if (return) { 44 | match (return) { 45 | 1 => { 46 | if (return) { 47 | return 48 | } else { 49 | return 50 | } 51 | } 52 | _ => { return } 53 | }; 54 | } else if (return) { 55 | return; 56 | } 57 | } 58 | if (return) { break; } 59 | } 60 | } 61 | 62 | fn notsure() { 63 | let mut _x: isize; 64 | let mut _y = (_x = 0) == (_x = 0); 65 | let mut _z = (_x = 0) < (_x = 0); 66 | let _a = (_x += 0) == (_x = 0); 67 | let _b = swap(&mut _y, &mut _z) == swap(&mut _y, &mut _z); 68 | } 69 | 70 | fn canttouchthis() -> usize { 71 | fn p() -> bool { true } 72 | let _a = (assert!((true)) == (assert!(p()))); 73 | let _c = (assert!((p())) == ()); 74 | let _b: bool = (println!("{}", 0) == (return 0)); 75 | } 76 | 77 | fn angrydome() { 78 | loop { if break { } } 79 | let mut i = 0; 80 | loop { i += 1; if i == 1 { match (continue) { 1 => { }, _ => panic!("wat") } } 81 | break; } 82 | } 83 | 84 | fn evil_lincoln() { let _evil: () = println!("lincoln"); } 85 | 86 | fn dots() { 87 | assert_eq!(String::from(".................................................."), 88 | format!("{:?}", .. .. .. .. .. .. .. .. .. .. .. .. .. 89 | .. .. .. .. .. .. .. .. .. .. .. ..)); 90 | } 91 | 92 | fn u8(u8: u8) { 93 | if u8 != 0u8 { 94 | assert_eq!(8u8, { 95 | macro_rules! u8 { 96 | (u8) => { 97 | mod u8 { 98 | pub fn u8<'u8: 'u8 + 'u8>(u8: &'u8 u8) -> &'u8 u8 { 99 | "u8"; 100 | u8 101 | } 102 | } 103 | }; 104 | } 105 | 106 | u8!(u8); 107 | let &u8: &u8 = u8::u8(&8u8); 108 | ::u8(0u8); 109 | u8 110 | }); 111 | } 112 | } 113 | 114 | fn fishy() { 115 | assert_eq!(String::from("><>"), 116 | String::<>::from::<>("><>").chars::<>().rev::<>().collect::()); 117 | } 118 | 119 | fn union() { 120 | union union<'union> { union: &'union union<'union>, } 121 | } 122 | 123 | fn special_characters() { 124 | let val = !((|(..):(_,_),(|__@_|__)|__)((&*"\\",'🤔')/**/,{})=={&[..=..][..];})// 125 | ; 126 | assert!(!val); 127 | } 128 | 129 | fn punch_card() -> impl std::fmt::Debug { 130 | ..=..=.. .. .. .. .. .. .. .. .. .. .. ..=.. .. 131 | ..=.. ..=.. .. .. .. .. .. .. .. .. ..=..=..=.. 132 | ..=.. ..=.. ..=.. ..=.. .. ..=..=.. .. ..=.. .. 133 | ..=..=.. .. ..=.. ..=.. ..=.. .. .. .. ..=.. .. 134 | ..=.. ..=.. ..=.. ..=.. .. ..=.. .. .. ..=.. .. 135 | ..=.. ..=.. ..=.. ..=.. .. .. ..=.. .. ..=.. .. 136 | ..=.. ..=.. .. ..=..=.. ..=..=.. .. .. ..=.. .. 137 | } 138 | 139 | fn r#match() { 140 | let val: () = match match match match match () { 141 | () => () 142 | } { 143 | () => () 144 | } { 145 | () => () 146 | } { 147 | () => () 148 | } { 149 | () => () 150 | }; 151 | assert_eq!(val, ()); 152 | } 153 | 154 | fn i_yield() { 155 | static || { 156 | yield yield yield yield yield yield yield yield yield; 157 | }; 158 | } 159 | 160 | fn match_nested_if() { 161 | let val = match () { 162 | () if if if if true {true} else {false} {true} else {false} {true} else {false} => true, 163 | _ => false, 164 | }; 165 | assert!(val); 166 | } 167 | 168 | fn monkey_barrel() { 169 | let val: () = ()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=()=(); 170 | assert_eq!(val, ()); 171 | } 172 | 173 | fn 𝚌𝚘𝚗𝚝𝚒𝚗𝚞𝚎() { 174 | type 𝚕𝚘𝚘𝚙 = i32; 175 | fn 𝚋𝚛𝚎𝚊𝚔() -> 𝚕𝚘𝚘𝚙 { 176 | let 𝚛𝚎𝚝𝚞𝚛𝚗 = 42; 177 | return 𝚛𝚎𝚝𝚞𝚛𝚗; 178 | } 179 | assert_eq!(loop { 180 | break 𝚋𝚛𝚎𝚊𝚔 (); 181 | }, 42); 182 | } 183 | 184 | fn function() { 185 | struct foo; 186 | impl Deref for foo { 187 | type Target = fn() -> Self; 188 | fn deref(&self) -> &Self::Target { 189 | &((|| foo) as _) 190 | } 191 | } 192 | let foo = foo () ()() ()()() ()()()() ()()()()(); 193 | } 194 | 195 | fn bathroom_stall() { 196 | let mut i = 1; 197 | matches!(2, _|_|_|_|_|_ if (i+=1) != (i+=1)); 198 | assert_eq!(i, 13); 199 | } 200 | 201 | fn closure_matching() { 202 | let x = |_| Some(1); 203 | let (|x| x) = match x(..) { 204 | |_| Some(2) => |_| Some(3), 205 | |_| _ => unreachable!(), 206 | }; 207 | assert!(matches!(x(..), |_| Some(4))); 208 | } 209 | 210 | fn semisemisemisemisemi() { 211 | ;;;;;;; ;;;;;;; ;;; ;;; ;; 212 | ;; ;; ;;;; ;;;; ;; 213 | ;;;;;;; ;;;;; ;; ;;;; ;; ;; 214 | ;; ;; ;; ;; ;; ;; 215 | ;;;;;;; ;;;;;;; ;; ;; ;; 216 | } 217 | 218 | fn useful_syntax() { 219 | use {{std::{{collections::{{HashMap}}}}}}; 220 | use ::{{{{core}, {std}}}}; 221 | use {{::{{core as core2}}}}; 222 | } 223 | 224 | fn infcx() { 225 | pub mod cx { 226 | pub mod cx { 227 | pub use super::cx; 228 | pub struct Cx; 229 | } 230 | } 231 | let _cx: cx::cx::Cx = cx::cx::cx::cx::cx::Cx; 232 | } 233 | 234 | fn return_already() -> impl std::fmt::Debug { 235 | loop { 236 | return !!!!!!! 237 | break !!!!!!1111 238 | } 239 | } 240 | 241 | fn fake_macros() -> impl std::fmt::Debug { 242 | loop { 243 | if! { 244 | match! ( 245 | break! { 246 | return! { 247 | 1337 248 | } 249 | } 250 | ) 251 | 252 | {} 253 | } 254 | 255 | {} 256 | } 257 | } 258 | 259 | pub fn main() { 260 | strange(); 261 | funny(); 262 | what(); 263 | zombiejesus(); 264 | notsure(); 265 | canttouchthis(); 266 | angrydome(); 267 | evil_lincoln(); 268 | dots(); 269 | u8(8u8); 270 | fishy(); 271 | union(); 272 | special_characters(); 273 | punch_card(); 274 | r#match(); 275 | i_yield(); 276 | match_nested_if(); 277 | monkey_barrel(); 278 | 𝚌𝚘𝚗𝚝𝚒𝚗𝚞𝚎(); 279 | function(); 280 | bathroom_stall(); 281 | closure_matching(); 282 | semisemisemisemisemi(); 283 | useful_syntax(); 284 | infcx(); 285 | return_already(); 286 | fake_macros(); 287 | } 288 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tree-sitter/tree-sitter-rust 2 | 3 | go 1.22 4 | 5 | require github.com/tree-sitter/go-tree-sitter v0.24.0 6 | 7 | require github.com/mattn/go-pointer v0.0.1 // indirect 8 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= 4 | github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 8 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 9 | github.com/tree-sitter/go-tree-sitter v0.24.0 h1:kRZb6aBNfcI/u0Qh8XEt3zjNVnmxTisDBN+kXK0xRYQ= 10 | github.com/tree-sitter/go-tree-sitter v0.24.0/go.mod h1:x681iFVoLMEwOSIHA1chaLkXlroXEN7WY+VHGFaoDbk= 11 | github.com/tree-sitter/tree-sitter-c v0.21.5-0.20240818205408-927da1f210eb h1:A8425heRM8mylnv4H58FPUiH+aYivyitre0PzxrfmWs= 12 | github.com/tree-sitter/tree-sitter-c v0.21.5-0.20240818205408-927da1f210eb/go.mod h1:dOF6gtQiF9UwNh995T5OphYmtIypkjsp3ap7r9AN/iA= 13 | github.com/tree-sitter/tree-sitter-cpp v0.22.4-0.20240818224355-b1a4e2b25148 h1:AfFPZwtwGN01BW1jDdqBVqscTwetvMpydqYZz57RSlc= 14 | github.com/tree-sitter/tree-sitter-cpp v0.22.4-0.20240818224355-b1a4e2b25148/go.mod h1:Bh6U3viD57rFXRYIQ+kmiYtr+1Bx0AceypDLJJSyi9s= 15 | github.com/tree-sitter/tree-sitter-embedded-template v0.21.1-0.20240819044651-ffbf64942c33 h1:TwqSV3qLp3tKSqirGLRHnjFk9Tc2oy57LIl+FQ4GjI4= 16 | github.com/tree-sitter/tree-sitter-embedded-template v0.21.1-0.20240819044651-ffbf64942c33/go.mod h1:CvCKCt3v04Ufos1zZnNCelBDeCGRpPucaN8QczoUsN4= 17 | github.com/tree-sitter/tree-sitter-go v0.21.3-0.20240818010209-8c0f0e7a6012 h1:Xvxck3tE5FW7F7bTS97iNM2ADMyCMJztVqn5HYKdJGo= 18 | github.com/tree-sitter/tree-sitter-go v0.21.3-0.20240818010209-8c0f0e7a6012/go.mod h1:T40D0O1cPvUU/+AmiXVXy1cncYQT6wem4Z0g4SfAYvY= 19 | github.com/tree-sitter/tree-sitter-html v0.20.5-0.20240818004741-d11201a263d0 h1:c46K6uh5Dz00zJeU9BfjXdb8I+E4RkUdfnWJpQADXFo= 20 | github.com/tree-sitter/tree-sitter-html v0.20.5-0.20240818004741-d11201a263d0/go.mod h1:hcNt/kOJHcIcuMvouE7LJcYdeFUFbVpBJ6d4wmOA+tU= 21 | github.com/tree-sitter/tree-sitter-java v0.21.1-0.20240824015150-576d8097e495 h1:jrt4qbJVEFs4H93/ITxygHc6u0TGqAkkate7TQ4wFSA= 22 | github.com/tree-sitter/tree-sitter-java v0.21.1-0.20240824015150-576d8097e495/go.mod h1:oyaR7fLnRV0hT9z6qwE9GkaeTom/hTDwK3H2idcOJFc= 23 | github.com/tree-sitter/tree-sitter-javascript v0.21.5-0.20240818005344-15887341e5b5 h1:om4X9AVg3asL8gxNJDcz4e/Wp+VpQj1PY3uJXKr6EOg= 24 | github.com/tree-sitter/tree-sitter-javascript v0.21.5-0.20240818005344-15887341e5b5/go.mod h1:nNqgPoV/h9uYWk6kYEFdEAhNVOacpfpRW5SFmdaP4tU= 25 | github.com/tree-sitter/tree-sitter-json v0.21.1-0.20240818005659-bdd69eb8c8a5 h1:pfV3G3k7NCKqKk8THBmyuh2zA33lgYHS3GVrzRR8ry4= 26 | github.com/tree-sitter/tree-sitter-json v0.21.1-0.20240818005659-bdd69eb8c8a5/go.mod h1:GbMKRjLfk0H+PI7nLi1Sx5lHf5wCpLz9al8tQYSxpEk= 27 | github.com/tree-sitter/tree-sitter-php v0.22.9-0.20240819002312-a552625b56c1 h1:ZXZMDwE+IhUtGug4Brv6NjJWUU3rfkZBKpemf6RY8/g= 28 | github.com/tree-sitter/tree-sitter-php v0.22.9-0.20240819002312-a552625b56c1/go.mod h1:UKCLuYnJ312Mei+3cyTmGOHzn0YAnaPRECgJmHtzrqs= 29 | github.com/tree-sitter/tree-sitter-python v0.21.1-0.20240818005537-55a9b8a4fbfb h1:EXEM82lFM7JjJb6qiKZXkpIDaCcbV2obNn82ghwj9lw= 30 | github.com/tree-sitter/tree-sitter-python v0.21.1-0.20240818005537-55a9b8a4fbfb/go.mod h1:lXCF1nGG5Dr4J3BTS0ObN4xJCCICiSu/b+Xe/VqMV7g= 31 | github.com/tree-sitter/tree-sitter-ruby v0.21.1-0.20240818211811-7dbc1e2d0e2d h1:fcYCvoXdcP1uRQYXqJHRy6Hec+uKScQdKVtMwK9JeCI= 32 | github.com/tree-sitter/tree-sitter-ruby v0.21.1-0.20240818211811-7dbc1e2d0e2d/go.mod h1:T1nShQ4v5AJtozZ8YyAS4uzUtDAJj/iv4YfwXSbUHzg= 33 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 34 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-rust", 3 | "version": "0.24.0", 4 | "description": "Rust grammar for tree-sitter", 5 | "repository": "https://github.com/tree-sitter/tree-sitter-rust", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Maxim Sokolov", 9 | "email": "maxim0xff@gmail.com" 10 | }, 11 | "contributors": [ 12 | { 13 | "name": "Max Brunsfeld", 14 | "email": "maxbrunsfeld@gmail.com" 15 | }, 16 | { 17 | "name": "Amaan Qureshi", 18 | "email": "amaanq12@gmail.com" 19 | } 20 | ], 21 | "main": "bindings/node", 22 | "types": "bindings/node", 23 | "keywords": [ 24 | "incremental", 25 | "parsing", 26 | "tree-sitter", 27 | "rust" 28 | ], 29 | "files": [ 30 | "grammar.js", 31 | "tree-sitter.json", 32 | "binding.gyp", 33 | "prebuilds/**", 34 | "bindings/node/*", 35 | "queries/*", 36 | "src/**", 37 | "*.wasm" 38 | ], 39 | "dependencies": { 40 | "node-addon-api": "^8.2.2", 41 | "node-gyp-build": "^4.8.4" 42 | }, 43 | "devDependencies": { 44 | "eslint": "^9.15.0", 45 | "eslint-config-treesitter": "^1.0.2", 46 | "prebuildify": "^6.0.1", 47 | "tree-sitter-cli": "^0.24.4" 48 | }, 49 | "peerDependencies": { 50 | "tree-sitter": "^0.22.1" 51 | }, 52 | "peerDependenciesMeta": { 53 | "tree-sitter": { 54 | "optional": true 55 | } 56 | }, 57 | "scripts": { 58 | "install": "node-gyp-build", 59 | "lint": "eslint grammar.js", 60 | "prestart": "tree-sitter build --wasm", 61 | "start": "tree-sitter playground", 62 | "test": "node --test bindings/node/*_test.js" 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=42", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "tree-sitter-rust" 7 | description = "Rust grammar for tree-sitter" 8 | version = "0.24.0" 9 | keywords = ["incremental", "parsing", "tree-sitter", "rust"] 10 | classifiers = [ 11 | "Intended Audience :: Developers", 12 | "License :: OSI Approved :: MIT License", 13 | "Topic :: Software Development :: Compilers", 14 | "Topic :: Text Processing :: Linguistic", 15 | "Typing :: Typed", 16 | ] 17 | authors = [ 18 | { name = "Max Brunsfeld", email = "maxbrunsfeld@gmail.com" }, 19 | { name = "Amaan Qureshi", email = "amaanq12@gmail.com" }, 20 | ] 21 | requires-python = ">=3.9" 22 | license.text = "MIT" 23 | readme = "README.md" 24 | 25 | [project.urls] 26 | Homepage = "https://github.com/tree-sitter/tree-sitter-rust" 27 | 28 | [project.optional-dependencies] 29 | core = ["tree-sitter~=0.22"] 30 | 31 | [tool.cibuildwheel] 32 | build = "cp39-*" 33 | build-frontend = "build" 34 | -------------------------------------------------------------------------------- /queries/highlights.scm: -------------------------------------------------------------------------------- 1 | ; Identifiers 2 | 3 | (type_identifier) @type 4 | (primitive_type) @type.builtin 5 | (field_identifier) @property 6 | 7 | ; Identifier conventions 8 | 9 | ; Assume all-caps names are constants 10 | ((identifier) @constant 11 | (#match? @constant "^[A-Z][A-Z\\d_]+$'")) 12 | 13 | ; Assume uppercase names are enum constructors 14 | ((identifier) @constructor 15 | (#match? @constructor "^[A-Z]")) 16 | 17 | ; Assume that uppercase names in paths are types 18 | ((scoped_identifier 19 | path: (identifier) @type) 20 | (#match? @type "^[A-Z]")) 21 | ((scoped_identifier 22 | path: (scoped_identifier 23 | name: (identifier) @type)) 24 | (#match? @type "^[A-Z]")) 25 | ((scoped_type_identifier 26 | path: (identifier) @type) 27 | (#match? @type "^[A-Z]")) 28 | ((scoped_type_identifier 29 | path: (scoped_identifier 30 | name: (identifier) @type)) 31 | (#match? @type "^[A-Z]")) 32 | 33 | ; Assume all qualified names in struct patterns are enum constructors. (They're 34 | ; either that, or struct names; highlighting both as constructors seems to be 35 | ; the less glaring choice of error, visually.) 36 | (struct_pattern 37 | type: (scoped_type_identifier 38 | name: (type_identifier) @constructor)) 39 | 40 | ; Function calls 41 | 42 | (call_expression 43 | function: (identifier) @function) 44 | (call_expression 45 | function: (field_expression 46 | field: (field_identifier) @function.method)) 47 | (call_expression 48 | function: (scoped_identifier 49 | "::" 50 | name: (identifier) @function)) 51 | 52 | (generic_function 53 | function: (identifier) @function) 54 | (generic_function 55 | function: (scoped_identifier 56 | name: (identifier) @function)) 57 | (generic_function 58 | function: (field_expression 59 | field: (field_identifier) @function.method)) 60 | 61 | (macro_invocation 62 | macro: (identifier) @function.macro 63 | "!" @function.macro) 64 | 65 | ; Function definitions 66 | 67 | (function_item (identifier) @function) 68 | (function_signature_item (identifier) @function) 69 | 70 | (line_comment) @comment 71 | (block_comment) @comment 72 | 73 | (line_comment (doc_comment)) @comment.documentation 74 | (block_comment (doc_comment)) @comment.documentation 75 | 76 | "(" @punctuation.bracket 77 | ")" @punctuation.bracket 78 | "[" @punctuation.bracket 79 | "]" @punctuation.bracket 80 | "{" @punctuation.bracket 81 | "}" @punctuation.bracket 82 | 83 | (type_arguments 84 | "<" @punctuation.bracket 85 | ">" @punctuation.bracket) 86 | (type_parameters 87 | "<" @punctuation.bracket 88 | ">" @punctuation.bracket) 89 | 90 | "::" @punctuation.delimiter 91 | ":" @punctuation.delimiter 92 | "." @punctuation.delimiter 93 | "," @punctuation.delimiter 94 | ";" @punctuation.delimiter 95 | 96 | (parameter (identifier) @variable.parameter) 97 | 98 | (lifetime (identifier) @label) 99 | 100 | "as" @keyword 101 | "async" @keyword 102 | "await" @keyword 103 | "break" @keyword 104 | "const" @keyword 105 | "continue" @keyword 106 | "default" @keyword 107 | "dyn" @keyword 108 | "else" @keyword 109 | "enum" @keyword 110 | "extern" @keyword 111 | "fn" @keyword 112 | "for" @keyword 113 | "gen" @keyword 114 | "if" @keyword 115 | "impl" @keyword 116 | "in" @keyword 117 | "let" @keyword 118 | "loop" @keyword 119 | "macro_rules!" @keyword 120 | "match" @keyword 121 | "mod" @keyword 122 | "move" @keyword 123 | "pub" @keyword 124 | "raw" @keyword 125 | "ref" @keyword 126 | "return" @keyword 127 | "static" @keyword 128 | "struct" @keyword 129 | "trait" @keyword 130 | "type" @keyword 131 | "union" @keyword 132 | "unsafe" @keyword 133 | "use" @keyword 134 | "where" @keyword 135 | "while" @keyword 136 | "yield" @keyword 137 | (crate) @keyword 138 | (mutable_specifier) @keyword 139 | (use_list (self) @keyword) 140 | (scoped_use_list (self) @keyword) 141 | (scoped_identifier (self) @keyword) 142 | (super) @keyword 143 | 144 | (self) @variable.builtin 145 | 146 | (char_literal) @string 147 | (string_literal) @string 148 | (raw_string_literal) @string 149 | 150 | (boolean_literal) @constant.builtin 151 | (integer_literal) @constant.builtin 152 | (float_literal) @constant.builtin 153 | 154 | (escape_sequence) @escape 155 | 156 | (attribute_item) @attribute 157 | (inner_attribute_item) @attribute 158 | 159 | "*" @operator 160 | "&" @operator 161 | "'" @operator 162 | -------------------------------------------------------------------------------- /queries/injections.scm: -------------------------------------------------------------------------------- 1 | ((macro_invocation 2 | (token_tree) @injection.content) 3 | (#set! injection.language "rust") 4 | (#set! injection.include-children)) 5 | 6 | ((macro_rule 7 | (token_tree) @injection.content) 8 | (#set! injection.language "rust") 9 | (#set! injection.include-children)) 10 | -------------------------------------------------------------------------------- /queries/tags.scm: -------------------------------------------------------------------------------- 1 | ; ADT definitions 2 | 3 | (struct_item 4 | name: (type_identifier) @name) @definition.class 5 | 6 | (enum_item 7 | name: (type_identifier) @name) @definition.class 8 | 9 | (union_item 10 | name: (type_identifier) @name) @definition.class 11 | 12 | ; type aliases 13 | 14 | (type_item 15 | name: (type_identifier) @name) @definition.class 16 | 17 | ; method definitions 18 | 19 | (declaration_list 20 | (function_item 21 | name: (identifier) @name) @definition.method) 22 | 23 | ; function definitions 24 | 25 | (function_item 26 | name: (identifier) @name) @definition.function 27 | 28 | ; trait definitions 29 | (trait_item 30 | name: (type_identifier) @name) @definition.interface 31 | 32 | ; module definitions 33 | (mod_item 34 | name: (identifier) @name) @definition.module 35 | 36 | ; macro definitions 37 | 38 | (macro_definition 39 | name: (identifier) @name) @definition.macro 40 | 41 | ; references 42 | 43 | (call_expression 44 | function: (identifier) @name) @reference.call 45 | 46 | (call_expression 47 | function: (field_expression 48 | field: (field_identifier) @name)) @reference.call 49 | 50 | (macro_invocation 51 | macro: (identifier) @name) @reference.call 52 | 53 | ; implementations 54 | 55 | (impl_item 56 | trait: (type_identifier) @name) @reference.implementation 57 | 58 | (impl_item 59 | type: (type_identifier) @name 60 | !trait) @reference.implementation 61 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from os.path import isdir, join 2 | from platform import system 3 | 4 | from setuptools import Extension, find_packages, setup 5 | from setuptools.command.build import build 6 | from wheel.bdist_wheel import bdist_wheel 7 | 8 | 9 | class Build(build): 10 | def run(self): 11 | if isdir("queries"): 12 | dest = join(self.build_lib, "tree_sitter_rust", "queries") 13 | self.copy_tree("queries", dest) 14 | super().run() 15 | 16 | 17 | class BdistWheel(bdist_wheel): 18 | def get_tag(self): 19 | python, abi, platform = super().get_tag() 20 | if python.startswith("cp"): 21 | python, abi = "cp39", "abi3" 22 | return python, abi, platform 23 | 24 | 25 | setup( 26 | packages=find_packages("bindings/python"), 27 | package_dir={"": "bindings/python"}, 28 | package_data={ 29 | "tree_sitter_rust": ["*.pyi", "py.typed"], 30 | "tree_sitter_rust.queries": ["*.scm"], 31 | }, 32 | ext_package="tree_sitter_rust", 33 | ext_modules=[ 34 | Extension( 35 | name="_binding", 36 | sources=[ 37 | "bindings/python/tree_sitter_rust/binding.c", 38 | "src/parser.c", 39 | "src/scanner.c", 40 | ], 41 | extra_compile_args=[ 42 | "-std=c11", 43 | "-fvisibility=hidden", 44 | ] if system() != "Windows" else [ 45 | "/std:c11", 46 | "/utf-8", 47 | ], 48 | define_macros=[ 49 | ("Py_LIMITED_API", "0x03090000"), 50 | ("PY_SSIZE_T_CLEAN", None), 51 | ("TREE_SITTER_HIDE_SYMBOLS", None), 52 | ], 53 | include_dirs=["src"], 54 | py_limited_api=True, 55 | ) 56 | ], 57 | cmdclass={ 58 | "build": Build, 59 | "bdist_wheel": BdistWheel 60 | }, 61 | zip_safe=False 62 | ) 63 | -------------------------------------------------------------------------------- /src/scanner.c: -------------------------------------------------------------------------------- 1 | #include "tree_sitter/alloc.h" 2 | #include "tree_sitter/parser.h" 3 | 4 | #include 5 | 6 | enum TokenType { 7 | STRING_CONTENT, 8 | RAW_STRING_LITERAL_START, 9 | RAW_STRING_LITERAL_CONTENT, 10 | RAW_STRING_LITERAL_END, 11 | FLOAT_LITERAL, 12 | BLOCK_OUTER_DOC_MARKER, 13 | BLOCK_INNER_DOC_MARKER, 14 | BLOCK_COMMENT_CONTENT, 15 | LINE_DOC_CONTENT, 16 | ERROR_SENTINEL 17 | }; 18 | 19 | typedef struct { 20 | uint8_t opening_hash_count; 21 | } Scanner; 22 | 23 | void *tree_sitter_rust_external_scanner_create() { return ts_calloc(1, sizeof(Scanner)); } 24 | 25 | void tree_sitter_rust_external_scanner_destroy(void *payload) { ts_free((Scanner *)payload); } 26 | 27 | unsigned tree_sitter_rust_external_scanner_serialize(void *payload, char *buffer) { 28 | Scanner *scanner = (Scanner *)payload; 29 | buffer[0] = (char)scanner->opening_hash_count; 30 | return 1; 31 | } 32 | 33 | void tree_sitter_rust_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) { 34 | Scanner *scanner = (Scanner *)payload; 35 | scanner->opening_hash_count = 0; 36 | if (length == 1) { 37 | Scanner *scanner = (Scanner *)payload; 38 | scanner->opening_hash_count = buffer[0]; 39 | } 40 | } 41 | 42 | static inline bool is_num_char(int32_t c) { return c == '_' || iswdigit(c); } 43 | 44 | static inline void advance(TSLexer *lexer) { lexer->advance(lexer, false); } 45 | 46 | static inline void skip(TSLexer *lexer) { lexer->advance(lexer, true); } 47 | 48 | static inline bool process_string(TSLexer *lexer) { 49 | bool has_content = false; 50 | for (;;) { 51 | if (lexer->lookahead == '\"' || lexer->lookahead == '\\') { 52 | break; 53 | } 54 | if (lexer->eof(lexer)) { 55 | return false; 56 | } 57 | has_content = true; 58 | advance(lexer); 59 | } 60 | lexer->result_symbol = STRING_CONTENT; 61 | lexer->mark_end(lexer); 62 | return has_content; 63 | } 64 | 65 | static inline bool scan_raw_string_start(Scanner *scanner, TSLexer *lexer) { 66 | if (lexer->lookahead == 'b' || lexer->lookahead == 'c') { 67 | advance(lexer); 68 | } 69 | if (lexer->lookahead != 'r') { 70 | return false; 71 | } 72 | advance(lexer); 73 | 74 | uint8_t opening_hash_count = 0; 75 | while (lexer->lookahead == '#') { 76 | advance(lexer); 77 | opening_hash_count++; 78 | } 79 | 80 | if (lexer->lookahead != '"') { 81 | return false; 82 | } 83 | advance(lexer); 84 | scanner->opening_hash_count = opening_hash_count; 85 | 86 | lexer->result_symbol = RAW_STRING_LITERAL_START; 87 | return true; 88 | } 89 | 90 | static inline bool scan_raw_string_content(Scanner *scanner, TSLexer *lexer) { 91 | for (;;) { 92 | if (lexer->eof(lexer)) { 93 | return false; 94 | } 95 | if (lexer->lookahead == '"') { 96 | lexer->mark_end(lexer); 97 | advance(lexer); 98 | unsigned hash_count = 0; 99 | while (lexer->lookahead == '#' && hash_count < scanner->opening_hash_count) { 100 | advance(lexer); 101 | hash_count++; 102 | } 103 | if (hash_count == scanner->opening_hash_count) { 104 | lexer->result_symbol = RAW_STRING_LITERAL_CONTENT; 105 | return true; 106 | } 107 | } else { 108 | advance(lexer); 109 | } 110 | } 111 | } 112 | 113 | static inline bool scan_raw_string_end(Scanner *scanner, TSLexer *lexer) { 114 | advance(lexer); 115 | for (unsigned i = 0; i < scanner->opening_hash_count; i++) { 116 | advance(lexer); 117 | } 118 | lexer->result_symbol = RAW_STRING_LITERAL_END; 119 | return true; 120 | } 121 | 122 | static inline bool process_float_literal(TSLexer *lexer) { 123 | lexer->result_symbol = FLOAT_LITERAL; 124 | 125 | advance(lexer); 126 | while (is_num_char(lexer->lookahead)) { 127 | advance(lexer); 128 | } 129 | 130 | bool has_fraction = false, has_exponent = false; 131 | 132 | if (lexer->lookahead == '.') { 133 | has_fraction = true; 134 | advance(lexer); 135 | if (iswalpha(lexer->lookahead)) { 136 | // The dot is followed by a letter: 1.max(2) => not a float but an integer 137 | return false; 138 | } 139 | 140 | if (lexer->lookahead == '.') { 141 | return false; 142 | } 143 | while (is_num_char(lexer->lookahead)) { 144 | advance(lexer); 145 | } 146 | } 147 | 148 | lexer->mark_end(lexer); 149 | 150 | if (lexer->lookahead == 'e' || lexer->lookahead == 'E') { 151 | has_exponent = true; 152 | advance(lexer); 153 | if (lexer->lookahead == '+' || lexer->lookahead == '-') { 154 | advance(lexer); 155 | } 156 | if (!is_num_char(lexer->lookahead)) { 157 | return true; 158 | } 159 | advance(lexer); 160 | while (is_num_char(lexer->lookahead)) { 161 | advance(lexer); 162 | } 163 | 164 | lexer->mark_end(lexer); 165 | } 166 | 167 | if (!has_exponent && !has_fraction) { 168 | return false; 169 | } 170 | 171 | if (lexer->lookahead != 'u' && lexer->lookahead != 'i' && lexer->lookahead != 'f') { 172 | return true; 173 | } 174 | advance(lexer); 175 | if (!iswdigit(lexer->lookahead)) { 176 | return true; 177 | } 178 | 179 | while (iswdigit(lexer->lookahead)) { 180 | advance(lexer); 181 | } 182 | 183 | lexer->mark_end(lexer); 184 | return true; 185 | } 186 | 187 | static inline bool process_line_doc_content(TSLexer *lexer) { 188 | lexer->result_symbol = LINE_DOC_CONTENT; 189 | for (;;) { 190 | if (lexer->eof(lexer)) { 191 | return true; 192 | } 193 | if (lexer->lookahead == '\n') { 194 | // Include the newline in the doc content node. 195 | // Line endings are useful for markdown injection. 196 | advance(lexer); 197 | return true; 198 | } 199 | advance(lexer); 200 | } 201 | } 202 | 203 | typedef enum { 204 | LeftForwardSlash, 205 | LeftAsterisk, 206 | Continuing, 207 | } BlockCommentState; 208 | 209 | typedef struct { 210 | BlockCommentState state; 211 | unsigned nestingDepth; 212 | } BlockCommentProcessing; 213 | 214 | static inline void process_left_forward_slash(BlockCommentProcessing *processing, char current) { 215 | if (current == '*') { 216 | processing->nestingDepth += 1; 217 | } 218 | processing->state = Continuing; 219 | }; 220 | 221 | static inline void process_left_asterisk(BlockCommentProcessing *processing, char current, TSLexer *lexer) { 222 | if (current == '*') { 223 | lexer->mark_end(lexer); 224 | processing->state = LeftAsterisk; 225 | return; 226 | } 227 | 228 | if (current == '/') { 229 | processing->nestingDepth -= 1; 230 | } 231 | 232 | processing->state = Continuing; 233 | } 234 | 235 | static inline void process_continuing(BlockCommentProcessing *processing, char current) { 236 | switch (current) { 237 | case '/': 238 | processing->state = LeftForwardSlash; 239 | break; 240 | case '*': 241 | processing->state = LeftAsterisk; 242 | break; 243 | } 244 | } 245 | 246 | static inline bool process_block_comment(TSLexer *lexer, const bool *valid_symbols) { 247 | char first = (char)lexer->lookahead; 248 | // The first character is stored so we can safely advance inside 249 | // these if blocks. However, because we only store one, we can only 250 | // safely advance 1 time. Since there's a chance that an advance could 251 | // happen in one state, we must advance in all states to ensure that 252 | // the program ends up in a sane state prior to processing the block 253 | // comment if need be. 254 | if (valid_symbols[BLOCK_INNER_DOC_MARKER] && first == '!') { 255 | lexer->result_symbol = BLOCK_INNER_DOC_MARKER; 256 | advance(lexer); 257 | return true; 258 | } 259 | if (valid_symbols[BLOCK_OUTER_DOC_MARKER] && first == '*') { 260 | advance(lexer); 261 | lexer->mark_end(lexer); 262 | // If the next token is a / that means that it's an empty block comment. 263 | if (lexer->lookahead == '/') { 264 | return false; 265 | } 266 | // If the next token is a * that means that this isn't a BLOCK_OUTER_DOC_MARKER 267 | // as BLOCK_OUTER_DOC_MARKER's only have 2 * not 3 or more. 268 | if (lexer->lookahead != '*') { 269 | lexer->result_symbol = BLOCK_OUTER_DOC_MARKER; 270 | return true; 271 | } 272 | } else { 273 | advance(lexer); 274 | } 275 | 276 | if (valid_symbols[BLOCK_COMMENT_CONTENT]) { 277 | BlockCommentProcessing processing = {Continuing, 1}; 278 | // Manually set the current state based on the first character 279 | switch (first) { 280 | case '*': 281 | processing.state = LeftAsterisk; 282 | if (lexer->lookahead == '/') { 283 | // This case can happen in an empty doc block comment 284 | // like /*!*/. The comment has no contents, so bail. 285 | return false; 286 | } 287 | break; 288 | case '/': 289 | processing.state = LeftForwardSlash; 290 | break; 291 | default: 292 | processing.state = Continuing; 293 | break; 294 | } 295 | 296 | // For the purposes of actually parsing rust code, this 297 | // is incorrect as it considers an unterminated block comment 298 | // to be an error. However, for the purposes of syntax highlighting 299 | // this should be considered successful as otherwise you are not able 300 | // to syntax highlight a block of code prior to closing the 301 | // block comment 302 | while (!lexer->eof(lexer) && processing.nestingDepth != 0) { 303 | // Set first to the current lookahead as that is the second character 304 | // as we force an advance in the above code when we are checking if we 305 | // need to handle a block comment inner or outer doc comment signifier 306 | // node 307 | first = (char)lexer->lookahead; 308 | switch (processing.state) { 309 | case LeftForwardSlash: 310 | process_left_forward_slash(&processing, first); 311 | break; 312 | case LeftAsterisk: 313 | process_left_asterisk(&processing, first, lexer); 314 | break; 315 | case Continuing: 316 | lexer->mark_end(lexer); 317 | process_continuing(&processing, first); 318 | break; 319 | default: 320 | break; 321 | } 322 | advance(lexer); 323 | if (first == '/' && processing.nestingDepth != 0) { 324 | lexer->mark_end(lexer); 325 | } 326 | } 327 | lexer->result_symbol = BLOCK_COMMENT_CONTENT; 328 | return true; 329 | } 330 | 331 | return false; 332 | } 333 | 334 | bool tree_sitter_rust_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) { 335 | // The documentation states that if the lexical analysis fails for some reason 336 | // they will mark every state as valid and pass it to the external scanner 337 | // However, we can't do anything to help them recover in that case so we 338 | // should just fail. 339 | /* 340 | link: https://tree-sitter.github.io/tree-sitter/creating-parsers#external-scanners 341 | If a syntax error is encountered during regular parsing, Tree-sitter’s 342 | first action during error recovery will be to call the external scanner’s 343 | scan function with all tokens marked valid. The scanner should detect this 344 | case and handle it appropriately. One simple method of detection is to add 345 | an unused token to the end of the externals array, for example 346 | 347 | externals: $ => [$.token1, $.token2, $.error_sentinel], 348 | 349 | then check whether that token is marked valid to determine whether 350 | Tree-sitter is in error correction mode. 351 | */ 352 | if (valid_symbols[ERROR_SENTINEL]) { 353 | return false; 354 | } 355 | 356 | Scanner *scanner = (Scanner *)payload; 357 | 358 | if (valid_symbols[BLOCK_COMMENT_CONTENT] || valid_symbols[BLOCK_INNER_DOC_MARKER] || 359 | valid_symbols[BLOCK_OUTER_DOC_MARKER]) { 360 | return process_block_comment(lexer, valid_symbols); 361 | } 362 | 363 | if (valid_symbols[STRING_CONTENT] && !valid_symbols[FLOAT_LITERAL]) { 364 | return process_string(lexer); 365 | } 366 | 367 | if (valid_symbols[LINE_DOC_CONTENT]) { 368 | return process_line_doc_content(lexer); 369 | } 370 | 371 | while (iswspace(lexer->lookahead)) { 372 | skip(lexer); 373 | } 374 | 375 | if (valid_symbols[RAW_STRING_LITERAL_START] && 376 | (lexer->lookahead == 'r' || lexer->lookahead == 'b' || lexer->lookahead == 'c')) { 377 | return scan_raw_string_start(scanner, lexer); 378 | } 379 | 380 | if (valid_symbols[RAW_STRING_LITERAL_CONTENT]) { 381 | return scan_raw_string_content(scanner, lexer); 382 | } 383 | 384 | if (valid_symbols[RAW_STRING_LITERAL_END] && lexer->lookahead == '"') { 385 | return scan_raw_string_end(scanner, lexer); 386 | } 387 | 388 | if (valid_symbols[FLOAT_LITERAL] && iswdigit(lexer->lookahead)) { 389 | return process_float_literal(lexer); 390 | } 391 | 392 | return false; 393 | } 394 | -------------------------------------------------------------------------------- /src/tree_sitter/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_ALLOC_H_ 2 | #define TREE_SITTER_ALLOC_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // Allow clients to override allocation functions 13 | #ifdef TREE_SITTER_REUSE_ALLOCATOR 14 | 15 | extern void *(*ts_current_malloc)(size_t size); 16 | extern void *(*ts_current_calloc)(size_t count, size_t size); 17 | extern void *(*ts_current_realloc)(void *ptr, size_t size); 18 | extern void (*ts_current_free)(void *ptr); 19 | 20 | #ifndef ts_malloc 21 | #define ts_malloc ts_current_malloc 22 | #endif 23 | #ifndef ts_calloc 24 | #define ts_calloc ts_current_calloc 25 | #endif 26 | #ifndef ts_realloc 27 | #define ts_realloc ts_current_realloc 28 | #endif 29 | #ifndef ts_free 30 | #define ts_free ts_current_free 31 | #endif 32 | 33 | #else 34 | 35 | #ifndef ts_malloc 36 | #define ts_malloc malloc 37 | #endif 38 | #ifndef ts_calloc 39 | #define ts_calloc calloc 40 | #endif 41 | #ifndef ts_realloc 42 | #define ts_realloc realloc 43 | #endif 44 | #ifndef ts_free 45 | #define ts_free free 46 | #endif 47 | 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif // TREE_SITTER_ALLOC_H_ 55 | -------------------------------------------------------------------------------- /src/tree_sitter/array.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_ARRAY_H_ 2 | #define TREE_SITTER_ARRAY_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "./alloc.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifdef _MSC_VER 17 | #pragma warning(push) 18 | #pragma warning(disable : 4101) 19 | #elif defined(__GNUC__) || defined(__clang__) 20 | #pragma GCC diagnostic push 21 | #pragma GCC diagnostic ignored "-Wunused-variable" 22 | #endif 23 | 24 | #define Array(T) \ 25 | struct { \ 26 | T *contents; \ 27 | uint32_t size; \ 28 | uint32_t capacity; \ 29 | } 30 | 31 | /// Initialize an array. 32 | #define array_init(self) \ 33 | ((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL) 34 | 35 | /// Create an empty array. 36 | #define array_new() \ 37 | { NULL, 0, 0 } 38 | 39 | /// Get a pointer to the element at a given `index` in the array. 40 | #define array_get(self, _index) \ 41 | (assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index]) 42 | 43 | /// Get a pointer to the first element in the array. 44 | #define array_front(self) array_get(self, 0) 45 | 46 | /// Get a pointer to the last element in the array. 47 | #define array_back(self) array_get(self, (self)->size - 1) 48 | 49 | /// Clear the array, setting its size to zero. Note that this does not free any 50 | /// memory allocated for the array's contents. 51 | #define array_clear(self) ((self)->size = 0) 52 | 53 | /// Reserve `new_capacity` elements of space in the array. If `new_capacity` is 54 | /// less than the array's current capacity, this function has no effect. 55 | #define array_reserve(self, new_capacity) \ 56 | _array__reserve((Array *)(self), array_elem_size(self), new_capacity) 57 | 58 | /// Free any memory allocated for this array. Note that this does not free any 59 | /// memory allocated for the array's contents. 60 | #define array_delete(self) _array__delete((Array *)(self)) 61 | 62 | /// Push a new `element` onto the end of the array. 63 | #define array_push(self, element) \ 64 | (_array__grow((Array *)(self), 1, array_elem_size(self)), \ 65 | (self)->contents[(self)->size++] = (element)) 66 | 67 | /// Increase the array's size by `count` elements. 68 | /// New elements are zero-initialized. 69 | #define array_grow_by(self, count) \ 70 | do { \ 71 | if ((count) == 0) break; \ 72 | _array__grow((Array *)(self), count, array_elem_size(self)); \ 73 | memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \ 74 | (self)->size += (count); \ 75 | } while (0) 76 | 77 | /// Append all elements from one array to the end of another. 78 | #define array_push_all(self, other) \ 79 | array_extend((self), (other)->size, (other)->contents) 80 | 81 | /// Append `count` elements to the end of the array, reading their values from the 82 | /// `contents` pointer. 83 | #define array_extend(self, count, contents) \ 84 | _array__splice( \ 85 | (Array *)(self), array_elem_size(self), (self)->size, \ 86 | 0, count, contents \ 87 | ) 88 | 89 | /// Remove `old_count` elements from the array starting at the given `index`. At 90 | /// the same index, insert `new_count` new elements, reading their values from the 91 | /// `new_contents` pointer. 92 | #define array_splice(self, _index, old_count, new_count, new_contents) \ 93 | _array__splice( \ 94 | (Array *)(self), array_elem_size(self), _index, \ 95 | old_count, new_count, new_contents \ 96 | ) 97 | 98 | /// Insert one `element` into the array at the given `index`. 99 | #define array_insert(self, _index, element) \ 100 | _array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element)) 101 | 102 | /// Remove one element from the array at the given `index`. 103 | #define array_erase(self, _index) \ 104 | _array__erase((Array *)(self), array_elem_size(self), _index) 105 | 106 | /// Pop the last element off the array, returning the element by value. 107 | #define array_pop(self) ((self)->contents[--(self)->size]) 108 | 109 | /// Assign the contents of one array to another, reallocating if necessary. 110 | #define array_assign(self, other) \ 111 | _array__assign((Array *)(self), (const Array *)(other), array_elem_size(self)) 112 | 113 | /// Swap one array with another 114 | #define array_swap(self, other) \ 115 | _array__swap((Array *)(self), (Array *)(other)) 116 | 117 | /// Get the size of the array contents 118 | #define array_elem_size(self) (sizeof *(self)->contents) 119 | 120 | /// Search a sorted array for a given `needle` value, using the given `compare` 121 | /// callback to determine the order. 122 | /// 123 | /// If an existing element is found to be equal to `needle`, then the `index` 124 | /// out-parameter is set to the existing value's index, and the `exists` 125 | /// out-parameter is set to true. Otherwise, `index` is set to an index where 126 | /// `needle` should be inserted in order to preserve the sorting, and `exists` 127 | /// is set to false. 128 | #define array_search_sorted_with(self, compare, needle, _index, _exists) \ 129 | _array__search_sorted(self, 0, compare, , needle, _index, _exists) 130 | 131 | /// Search a sorted array for a given `needle` value, using integer comparisons 132 | /// of a given struct field (specified with a leading dot) to determine the order. 133 | /// 134 | /// See also `array_search_sorted_with`. 135 | #define array_search_sorted_by(self, field, needle, _index, _exists) \ 136 | _array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists) 137 | 138 | /// Insert a given `value` into a sorted array, using the given `compare` 139 | /// callback to determine the order. 140 | #define array_insert_sorted_with(self, compare, value) \ 141 | do { \ 142 | unsigned _index, _exists; \ 143 | array_search_sorted_with(self, compare, &(value), &_index, &_exists); \ 144 | if (!_exists) array_insert(self, _index, value); \ 145 | } while (0) 146 | 147 | /// Insert a given `value` into a sorted array, using integer comparisons of 148 | /// a given struct field (specified with a leading dot) to determine the order. 149 | /// 150 | /// See also `array_search_sorted_by`. 151 | #define array_insert_sorted_by(self, field, value) \ 152 | do { \ 153 | unsigned _index, _exists; \ 154 | array_search_sorted_by(self, field, (value) field, &_index, &_exists); \ 155 | if (!_exists) array_insert(self, _index, value); \ 156 | } while (0) 157 | 158 | // Private 159 | 160 | typedef Array(void) Array; 161 | 162 | /// This is not what you're looking for, see `array_delete`. 163 | static inline void _array__delete(Array *self) { 164 | if (self->contents) { 165 | ts_free(self->contents); 166 | self->contents = NULL; 167 | self->size = 0; 168 | self->capacity = 0; 169 | } 170 | } 171 | 172 | /// This is not what you're looking for, see `array_erase`. 173 | static inline void _array__erase(Array *self, size_t element_size, 174 | uint32_t index) { 175 | assert(index < self->size); 176 | char *contents = (char *)self->contents; 177 | memmove(contents + index * element_size, contents + (index + 1) * element_size, 178 | (self->size - index - 1) * element_size); 179 | self->size--; 180 | } 181 | 182 | /// This is not what you're looking for, see `array_reserve`. 183 | static inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) { 184 | if (new_capacity > self->capacity) { 185 | if (self->contents) { 186 | self->contents = ts_realloc(self->contents, new_capacity * element_size); 187 | } else { 188 | self->contents = ts_malloc(new_capacity * element_size); 189 | } 190 | self->capacity = new_capacity; 191 | } 192 | } 193 | 194 | /// This is not what you're looking for, see `array_assign`. 195 | static inline void _array__assign(Array *self, const Array *other, size_t element_size) { 196 | _array__reserve(self, element_size, other->size); 197 | self->size = other->size; 198 | memcpy(self->contents, other->contents, self->size * element_size); 199 | } 200 | 201 | /// This is not what you're looking for, see `array_swap`. 202 | static inline void _array__swap(Array *self, Array *other) { 203 | Array swap = *other; 204 | *other = *self; 205 | *self = swap; 206 | } 207 | 208 | /// This is not what you're looking for, see `array_push` or `array_grow_by`. 209 | static inline void _array__grow(Array *self, uint32_t count, size_t element_size) { 210 | uint32_t new_size = self->size + count; 211 | if (new_size > self->capacity) { 212 | uint32_t new_capacity = self->capacity * 2; 213 | if (new_capacity < 8) new_capacity = 8; 214 | if (new_capacity < new_size) new_capacity = new_size; 215 | _array__reserve(self, element_size, new_capacity); 216 | } 217 | } 218 | 219 | /// This is not what you're looking for, see `array_splice`. 220 | static inline void _array__splice(Array *self, size_t element_size, 221 | uint32_t index, uint32_t old_count, 222 | uint32_t new_count, const void *elements) { 223 | uint32_t new_size = self->size + new_count - old_count; 224 | uint32_t old_end = index + old_count; 225 | uint32_t new_end = index + new_count; 226 | assert(old_end <= self->size); 227 | 228 | _array__reserve(self, element_size, new_size); 229 | 230 | char *contents = (char *)self->contents; 231 | if (self->size > old_end) { 232 | memmove( 233 | contents + new_end * element_size, 234 | contents + old_end * element_size, 235 | (self->size - old_end) * element_size 236 | ); 237 | } 238 | if (new_count > 0) { 239 | if (elements) { 240 | memcpy( 241 | (contents + index * element_size), 242 | elements, 243 | new_count * element_size 244 | ); 245 | } else { 246 | memset( 247 | (contents + index * element_size), 248 | 0, 249 | new_count * element_size 250 | ); 251 | } 252 | } 253 | self->size += new_count - old_count; 254 | } 255 | 256 | /// A binary search routine, based on Rust's `std::slice::binary_search_by`. 257 | /// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`. 258 | #define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \ 259 | do { \ 260 | *(_index) = start; \ 261 | *(_exists) = false; \ 262 | uint32_t size = (self)->size - *(_index); \ 263 | if (size == 0) break; \ 264 | int comparison; \ 265 | while (size > 1) { \ 266 | uint32_t half_size = size / 2; \ 267 | uint32_t mid_index = *(_index) + half_size; \ 268 | comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \ 269 | if (comparison <= 0) *(_index) = mid_index; \ 270 | size -= half_size; \ 271 | } \ 272 | comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \ 273 | if (comparison == 0) *(_exists) = true; \ 274 | else if (comparison < 0) *(_index) += 1; \ 275 | } while (0) 276 | 277 | /// Helper macro for the `_sorted_by` routines below. This takes the left (existing) 278 | /// parameter by reference in order to work with the generic sorting function above. 279 | #define _compare_int(a, b) ((int)*(a) - (int)(b)) 280 | 281 | #ifdef _MSC_VER 282 | #pragma warning(pop) 283 | #elif defined(__GNUC__) || defined(__clang__) 284 | #pragma GCC diagnostic pop 285 | #endif 286 | 287 | #ifdef __cplusplus 288 | } 289 | #endif 290 | 291 | #endif // TREE_SITTER_ARRAY_H_ 292 | -------------------------------------------------------------------------------- /src/tree_sitter/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_PARSER_H_ 2 | #define TREE_SITTER_PARSER_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define ts_builtin_sym_error ((TSSymbol)-1) 13 | #define ts_builtin_sym_end 0 14 | #define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024 15 | 16 | #ifndef TREE_SITTER_API_H_ 17 | typedef uint16_t TSStateId; 18 | typedef uint16_t TSSymbol; 19 | typedef uint16_t TSFieldId; 20 | typedef struct TSLanguage TSLanguage; 21 | typedef struct TSLanguageMetadata TSLanguageMetadata; 22 | typedef struct TSLanguageMetadata { 23 | uint8_t major_version; 24 | uint8_t minor_version; 25 | uint8_t patch_version; 26 | } TSLanguageMetadata; 27 | #endif 28 | 29 | typedef struct { 30 | TSFieldId field_id; 31 | uint8_t child_index; 32 | bool inherited; 33 | } TSFieldMapEntry; 34 | 35 | // Used to index the field and supertype maps. 36 | typedef struct { 37 | uint16_t index; 38 | uint16_t length; 39 | } TSMapSlice; 40 | 41 | typedef struct { 42 | bool visible; 43 | bool named; 44 | bool supertype; 45 | } TSSymbolMetadata; 46 | 47 | typedef struct TSLexer TSLexer; 48 | 49 | struct TSLexer { 50 | int32_t lookahead; 51 | TSSymbol result_symbol; 52 | void (*advance)(TSLexer *, bool); 53 | void (*mark_end)(TSLexer *); 54 | uint32_t (*get_column)(TSLexer *); 55 | bool (*is_at_included_range_start)(const TSLexer *); 56 | bool (*eof)(const TSLexer *); 57 | void (*log)(const TSLexer *, const char *, ...); 58 | }; 59 | 60 | typedef enum { 61 | TSParseActionTypeShift, 62 | TSParseActionTypeReduce, 63 | TSParseActionTypeAccept, 64 | TSParseActionTypeRecover, 65 | } TSParseActionType; 66 | 67 | typedef union { 68 | struct { 69 | uint8_t type; 70 | TSStateId state; 71 | bool extra; 72 | bool repetition; 73 | } shift; 74 | struct { 75 | uint8_t type; 76 | uint8_t child_count; 77 | TSSymbol symbol; 78 | int16_t dynamic_precedence; 79 | uint16_t production_id; 80 | } reduce; 81 | uint8_t type; 82 | } TSParseAction; 83 | 84 | typedef struct { 85 | uint16_t lex_state; 86 | uint16_t external_lex_state; 87 | } TSLexMode; 88 | 89 | typedef struct { 90 | uint16_t lex_state; 91 | uint16_t external_lex_state; 92 | uint16_t reserved_word_set_id; 93 | } TSLexerMode; 94 | 95 | typedef union { 96 | TSParseAction action; 97 | struct { 98 | uint8_t count; 99 | bool reusable; 100 | } entry; 101 | } TSParseActionEntry; 102 | 103 | typedef struct { 104 | int32_t start; 105 | int32_t end; 106 | } TSCharacterRange; 107 | 108 | struct TSLanguage { 109 | uint32_t abi_version; 110 | uint32_t symbol_count; 111 | uint32_t alias_count; 112 | uint32_t token_count; 113 | uint32_t external_token_count; 114 | uint32_t state_count; 115 | uint32_t large_state_count; 116 | uint32_t production_id_count; 117 | uint32_t field_count; 118 | uint16_t max_alias_sequence_length; 119 | const uint16_t *parse_table; 120 | const uint16_t *small_parse_table; 121 | const uint32_t *small_parse_table_map; 122 | const TSParseActionEntry *parse_actions; 123 | const char * const *symbol_names; 124 | const char * const *field_names; 125 | const TSMapSlice *field_map_slices; 126 | const TSFieldMapEntry *field_map_entries; 127 | const TSSymbolMetadata *symbol_metadata; 128 | const TSSymbol *public_symbol_map; 129 | const uint16_t *alias_map; 130 | const TSSymbol *alias_sequences; 131 | const TSLexerMode *lex_modes; 132 | bool (*lex_fn)(TSLexer *, TSStateId); 133 | bool (*keyword_lex_fn)(TSLexer *, TSStateId); 134 | TSSymbol keyword_capture_token; 135 | struct { 136 | const bool *states; 137 | const TSSymbol *symbol_map; 138 | void *(*create)(void); 139 | void (*destroy)(void *); 140 | bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist); 141 | unsigned (*serialize)(void *, char *); 142 | void (*deserialize)(void *, const char *, unsigned); 143 | } external_scanner; 144 | const TSStateId *primary_state_ids; 145 | const char *name; 146 | const TSSymbol *reserved_words; 147 | uint16_t max_reserved_word_set_size; 148 | uint32_t supertype_count; 149 | const TSSymbol *supertype_symbols; 150 | const TSMapSlice *supertype_map_slices; 151 | const TSSymbol *supertype_map_entries; 152 | TSLanguageMetadata metadata; 153 | }; 154 | 155 | static inline bool set_contains(const TSCharacterRange *ranges, uint32_t len, int32_t lookahead) { 156 | uint32_t index = 0; 157 | uint32_t size = len - index; 158 | while (size > 1) { 159 | uint32_t half_size = size / 2; 160 | uint32_t mid_index = index + half_size; 161 | const TSCharacterRange *range = &ranges[mid_index]; 162 | if (lookahead >= range->start && lookahead <= range->end) { 163 | return true; 164 | } else if (lookahead > range->end) { 165 | index = mid_index; 166 | } 167 | size -= half_size; 168 | } 169 | const TSCharacterRange *range = &ranges[index]; 170 | return (lookahead >= range->start && lookahead <= range->end); 171 | } 172 | 173 | /* 174 | * Lexer Macros 175 | */ 176 | 177 | #ifdef _MSC_VER 178 | #define UNUSED __pragma(warning(suppress : 4101)) 179 | #else 180 | #define UNUSED __attribute__((unused)) 181 | #endif 182 | 183 | #define START_LEXER() \ 184 | bool result = false; \ 185 | bool skip = false; \ 186 | UNUSED \ 187 | bool eof = false; \ 188 | int32_t lookahead; \ 189 | goto start; \ 190 | next_state: \ 191 | lexer->advance(lexer, skip); \ 192 | start: \ 193 | skip = false; \ 194 | lookahead = lexer->lookahead; 195 | 196 | #define ADVANCE(state_value) \ 197 | { \ 198 | state = state_value; \ 199 | goto next_state; \ 200 | } 201 | 202 | #define ADVANCE_MAP(...) \ 203 | { \ 204 | static const uint16_t map[] = { __VA_ARGS__ }; \ 205 | for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \ 206 | if (map[i] == lookahead) { \ 207 | state = map[i + 1]; \ 208 | goto next_state; \ 209 | } \ 210 | } \ 211 | } 212 | 213 | #define SKIP(state_value) \ 214 | { \ 215 | skip = true; \ 216 | state = state_value; \ 217 | goto next_state; \ 218 | } 219 | 220 | #define ACCEPT_TOKEN(symbol_value) \ 221 | result = true; \ 222 | lexer->result_symbol = symbol_value; \ 223 | lexer->mark_end(lexer); 224 | 225 | #define END_STATE() return result; 226 | 227 | /* 228 | * Parse Table Macros 229 | */ 230 | 231 | #define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT) 232 | 233 | #define STATE(id) id 234 | 235 | #define ACTIONS(id) id 236 | 237 | #define SHIFT(state_value) \ 238 | {{ \ 239 | .shift = { \ 240 | .type = TSParseActionTypeShift, \ 241 | .state = (state_value) \ 242 | } \ 243 | }} 244 | 245 | #define SHIFT_REPEAT(state_value) \ 246 | {{ \ 247 | .shift = { \ 248 | .type = TSParseActionTypeShift, \ 249 | .state = (state_value), \ 250 | .repetition = true \ 251 | } \ 252 | }} 253 | 254 | #define SHIFT_EXTRA() \ 255 | {{ \ 256 | .shift = { \ 257 | .type = TSParseActionTypeShift, \ 258 | .extra = true \ 259 | } \ 260 | }} 261 | 262 | #define REDUCE(symbol_name, children, precedence, prod_id) \ 263 | {{ \ 264 | .reduce = { \ 265 | .type = TSParseActionTypeReduce, \ 266 | .symbol = symbol_name, \ 267 | .child_count = children, \ 268 | .dynamic_precedence = precedence, \ 269 | .production_id = prod_id \ 270 | }, \ 271 | }} 272 | 273 | #define RECOVER() \ 274 | {{ \ 275 | .type = TSParseActionTypeRecover \ 276 | }} 277 | 278 | #define ACCEPT_INPUT() \ 279 | {{ \ 280 | .type = TSParseActionTypeAccept \ 281 | }} 282 | 283 | #ifdef __cplusplus 284 | } 285 | #endif 286 | 287 | #endif // TREE_SITTER_PARSER_H_ 288 | -------------------------------------------------------------------------------- /test/corpus/async.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | Async function 3 | ================================================================================ 4 | 5 | async fn abc() {} 6 | 7 | async fn main() { 8 | let x = futures.await?; 9 | } 10 | 11 | -------------------------------------------------------------------------------- 12 | 13 | (source_file 14 | (function_item 15 | (function_modifiers) 16 | (identifier) 17 | (parameters) 18 | (block)) 19 | (function_item 20 | (function_modifiers) 21 | (identifier) 22 | (parameters) 23 | (block 24 | (let_declaration 25 | (identifier) 26 | (try_expression 27 | (await_expression 28 | (identifier))))))) 29 | 30 | ================================================================================ 31 | Await expression 32 | ================================================================================ 33 | 34 | futures.await; 35 | futures.await?; 36 | futures.await?.await?; 37 | futures.await?.function().await?; 38 | 39 | -------------------------------------------------------------------------------- 40 | 41 | (source_file 42 | (expression_statement 43 | (await_expression 44 | (identifier))) 45 | (expression_statement 46 | (try_expression 47 | (await_expression 48 | (identifier)))) 49 | (expression_statement 50 | (try_expression 51 | (await_expression 52 | (try_expression 53 | (await_expression 54 | (identifier)))))) 55 | (expression_statement 56 | (try_expression 57 | (await_expression 58 | (call_expression 59 | (field_expression 60 | (try_expression 61 | (await_expression 62 | (identifier))) 63 | (field_identifier)) 64 | (arguments)))))) 65 | 66 | ================================================================================ 67 | Async Block 68 | ================================================================================ 69 | 70 | async {} 71 | async { let x = 10; } 72 | async move {} 73 | 74 | -------------------------------------------------------------------------------- 75 | 76 | (source_file 77 | (expression_statement 78 | (async_block 79 | (block))) 80 | (expression_statement 81 | (async_block 82 | (block 83 | (let_declaration 84 | (identifier) 85 | (integer_literal))))) 86 | (expression_statement 87 | (async_block 88 | (block)))) 89 | 90 | ================================================================================ 91 | Async closure 92 | ================================================================================ 93 | 94 | let _ = async || (); 95 | 96 | -------------------------------------------------------------------------------- 97 | 98 | (source_file 99 | (let_declaration 100 | (closure_expression 101 | (closure_parameters) 102 | (unit_expression)))) 103 | 104 | ================================================================================ 105 | Async move async move closure 106 | ================================================================================ 107 | 108 | let a = async move || async move {}; 109 | 110 | -------------------------------------------------------------------------------- 111 | 112 | (source_file 113 | (let_declaration 114 | (identifier) 115 | (closure_expression 116 | (closure_parameters) 117 | (async_block 118 | (block))))) 119 | 120 | 121 | ================================================================================ 122 | Try Block 123 | ================================================================================ 124 | 125 | try {} 126 | 127 | -------------------------------------------------------------------------------- 128 | 129 | (source_file 130 | (expression_statement 131 | (try_block 132 | (block)))) 133 | 134 | ================================================================================ 135 | Gen Block 136 | ================================================================================ 137 | 138 | gen {} 139 | gen { let x = 10; } 140 | gen { yield (); } 141 | gen move {} 142 | 143 | -------------------------------------------------------------------------------- 144 | 145 | (source_file 146 | (expression_statement 147 | (gen_block 148 | (block))) 149 | (expression_statement 150 | (gen_block 151 | (block 152 | (let_declaration 153 | (identifier) 154 | (integer_literal))))) 155 | (expression_statement 156 | (gen_block 157 | (block 158 | (expression_statement 159 | (yield_expression 160 | (unit_expression)))))) 161 | (expression_statement 162 | (gen_block 163 | (block)))) 164 | -------------------------------------------------------------------------------- /test/corpus/expressions.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | Identifiers 3 | ================================================================================ 4 | 5 | fn main() { 6 | abc; 7 | } 8 | 9 | -------------------------------------------------------------------------------- 10 | 11 | (source_file 12 | (function_item 13 | (identifier) 14 | (parameters) 15 | (block 16 | (expression_statement 17 | (identifier))))) 18 | 19 | ================================================================================ 20 | Raw identifiers 21 | ================================================================================ 22 | 23 | fn main() { 24 | (r#abc as r#Def).r#ghi; 25 | } 26 | 27 | -------------------------------------------------------------------------------- 28 | 29 | (source_file 30 | (function_item 31 | (identifier) 32 | (parameters) 33 | (block 34 | (expression_statement 35 | (field_expression 36 | (parenthesized_expression 37 | (type_cast_expression 38 | (identifier) 39 | (type_identifier))) 40 | (field_identifier)))))) 41 | 42 | ================================================================================ 43 | Unary operator expressions 44 | ================================================================================ 45 | 46 | -num; 47 | !bits; 48 | *boxed_thing; 49 | 50 | -------------------------------------------------------------------------------- 51 | 52 | (source_file 53 | (expression_statement 54 | (unary_expression 55 | (identifier))) 56 | (expression_statement 57 | (unary_expression 58 | (identifier))) 59 | (expression_statement 60 | (unary_expression 61 | (identifier)))) 62 | 63 | ================================================================================ 64 | Reference expressions 65 | ================================================================================ 66 | 67 | &a; 68 | &mut self.name; 69 | &raw const b; 70 | &raw mut self.age; 71 | 72 | -------------------------------------------------------------------------------- 73 | 74 | (source_file 75 | (expression_statement 76 | (reference_expression 77 | (identifier))) 78 | (expression_statement 79 | (reference_expression 80 | (mutable_specifier) 81 | (field_expression 82 | (self) 83 | (field_identifier)))) 84 | (expression_statement 85 | (reference_expression 86 | (identifier))) 87 | (expression_statement 88 | (reference_expression 89 | (mutable_specifier) 90 | (field_expression 91 | (self) 92 | (field_identifier))))) 93 | 94 | ================================================================================ 95 | Try expressions 96 | ================================================================================ 97 | 98 | a.unwrap()?; 99 | &a?; 100 | 101 | -------------------------------------------------------------------------------- 102 | 103 | (source_file 104 | (expression_statement 105 | (try_expression 106 | (call_expression 107 | (field_expression 108 | (identifier) 109 | (field_identifier)) 110 | (arguments)))) 111 | (expression_statement 112 | (reference_expression 113 | (try_expression 114 | (identifier))))) 115 | 116 | ================================================================================ 117 | Binary operator expressions 118 | ================================================================================ 119 | 120 | a * b; 121 | a / b; 122 | a % b; 123 | a + b; 124 | a - b; 125 | a >> b; 126 | a << b; 127 | a == b; 128 | a && b; 129 | a || b; 130 | 131 | -------------------------------------------------------------------------------- 132 | 133 | (source_file 134 | (expression_statement 135 | (binary_expression 136 | (identifier) 137 | (identifier))) 138 | (expression_statement 139 | (binary_expression 140 | (identifier) 141 | (identifier))) 142 | (expression_statement 143 | (binary_expression 144 | (identifier) 145 | (identifier))) 146 | (expression_statement 147 | (binary_expression 148 | (identifier) 149 | (identifier))) 150 | (expression_statement 151 | (binary_expression 152 | (identifier) 153 | (identifier))) 154 | (expression_statement 155 | (binary_expression 156 | (identifier) 157 | (identifier))) 158 | (expression_statement 159 | (binary_expression 160 | (identifier) 161 | (identifier))) 162 | (expression_statement 163 | (binary_expression 164 | (identifier) 165 | (identifier))) 166 | (expression_statement 167 | (binary_expression 168 | (identifier) 169 | (identifier))) 170 | (expression_statement 171 | (binary_expression 172 | (identifier) 173 | (identifier)))) 174 | 175 | ================================================================================ 176 | Grouped expressions 177 | ================================================================================ 178 | 179 | (0); 180 | (2 * (3 + 4)); 181 | 182 | -------------------------------------------------------------------------------- 183 | 184 | (source_file 185 | (expression_statement 186 | (parenthesized_expression 187 | (integer_literal))) 188 | (expression_statement 189 | (parenthesized_expression 190 | (binary_expression 191 | (integer_literal) 192 | (parenthesized_expression 193 | (binary_expression 194 | (integer_literal) 195 | (integer_literal))))))) 196 | 197 | ================================================================================ 198 | Range expressions 199 | ================================================================================ 200 | 201 | 1..2; 202 | 3..; 203 | ..4; 204 | ..; 205 | 1..b; 206 | a..b; 207 | 1..(1); 208 | (1)..1; 209 | (1)..(1); 210 | 1..{1}; 211 | for i in 1.. { 212 | } 213 | 214 | -------------------------------------------------------------------------------- 215 | 216 | (source_file 217 | (expression_statement 218 | (range_expression 219 | (integer_literal) 220 | (integer_literal))) 221 | (expression_statement 222 | (range_expression 223 | (integer_literal))) 224 | (expression_statement 225 | (range_expression 226 | (integer_literal))) 227 | (expression_statement 228 | (range_expression)) 229 | (expression_statement 230 | (range_expression 231 | (integer_literal) 232 | (identifier))) 233 | (expression_statement 234 | (range_expression 235 | (identifier) 236 | (identifier))) 237 | (expression_statement 238 | (range_expression 239 | (integer_literal) 240 | (parenthesized_expression 241 | (integer_literal)))) 242 | (expression_statement 243 | (range_expression 244 | (parenthesized_expression 245 | (integer_literal)) 246 | (integer_literal))) 247 | (expression_statement 248 | (range_expression 249 | (parenthesized_expression 250 | (integer_literal)) 251 | (parenthesized_expression 252 | (integer_literal)))) 253 | (expression_statement 254 | (range_expression 255 | (integer_literal) 256 | (block 257 | (integer_literal)))) 258 | (expression_statement 259 | (for_expression 260 | (identifier) 261 | (range_expression 262 | (integer_literal)) 263 | (block)))) 264 | 265 | ================================================================================ 266 | Assignment expressions 267 | ================================================================================ 268 | 269 | x = y; 270 | 271 | -------------------------------------------------------------------------------- 272 | 273 | (source_file 274 | (expression_statement 275 | (assignment_expression 276 | left: (identifier) 277 | right: (identifier)))) 278 | 279 | ================================================================================ 280 | Compound assignment expressions 281 | ================================================================================ 282 | 283 | x += 1; 284 | x += y; 285 | 286 | -------------------------------------------------------------------------------- 287 | 288 | (source_file 289 | (expression_statement 290 | (compound_assignment_expr 291 | left: (identifier) 292 | right: (integer_literal))) 293 | (expression_statement 294 | (compound_assignment_expr 295 | left: (identifier) 296 | right: (identifier)))) 297 | 298 | ================================================================================ 299 | Type cast expressions 300 | ================================================================================ 301 | 302 | 1000 as u8; 303 | let character = integer as char; 304 | let size: f64 = 1.0 + -len(values) as f64 + 1.0; 305 | 306 | -------------------------------------------------------------------------------- 307 | 308 | (source_file 309 | (expression_statement 310 | (type_cast_expression 311 | value: (integer_literal) 312 | type: (primitive_type))) 313 | (let_declaration 314 | pattern: (identifier) 315 | value: (type_cast_expression 316 | value: (identifier) 317 | type: (primitive_type))) 318 | (let_declaration 319 | pattern: (identifier) 320 | type: (primitive_type) 321 | value: (binary_expression 322 | left: (binary_expression 323 | left: (float_literal) 324 | right: (type_cast_expression 325 | value: (unary_expression 326 | (call_expression 327 | function: (identifier) 328 | arguments: (arguments 329 | (identifier)))) 330 | type: (primitive_type))) 331 | right: (float_literal)))) 332 | 333 | ================================================================================ 334 | Call expressions 335 | ================================================================================ 336 | 337 | foo(); 338 | add(1i32, 2i32); 339 | add( 340 | 1i32, 341 | 2i32, 342 | ); 343 | 344 | -------------------------------------------------------------------------------- 345 | 346 | (source_file 347 | (expression_statement 348 | (call_expression 349 | function: (identifier) 350 | arguments: (arguments))) 351 | (expression_statement 352 | (call_expression 353 | function: (identifier) 354 | arguments: (arguments 355 | (integer_literal) 356 | (integer_literal)))) 357 | (expression_statement 358 | (call_expression 359 | function: (identifier) 360 | arguments: (arguments 361 | (integer_literal) 362 | (integer_literal))))) 363 | 364 | ================================================================================ 365 | Array expressions 366 | ================================================================================ 367 | 368 | []; 369 | [1, 2, 3]; 370 | ["a", "b", "c"]; 371 | [0; 128]; 372 | [ 373 | #[cfg(foo)] 374 | "foo", 375 | #[cfg(bar)] 376 | "bar", 377 | ]; 378 | 379 | -------------------------------------------------------------------------------- 380 | 381 | (source_file 382 | (expression_statement 383 | (array_expression)) 384 | (expression_statement 385 | (array_expression 386 | (integer_literal) 387 | (integer_literal) 388 | (integer_literal))) 389 | (expression_statement 390 | (array_expression 391 | (string_literal 392 | (string_content)) 393 | (string_literal 394 | (string_content)) 395 | (string_literal 396 | (string_content)))) 397 | (expression_statement 398 | (array_expression 399 | (integer_literal) 400 | length: (integer_literal))) 401 | (expression_statement 402 | (array_expression 403 | (attribute_item 404 | (attribute 405 | (identifier) 406 | arguments: (token_tree 407 | (identifier)))) 408 | (string_literal 409 | (string_content)) 410 | (attribute_item 411 | (attribute 412 | (identifier) 413 | arguments: (token_tree 414 | (identifier)))) 415 | (string_literal 416 | (string_content))))) 417 | 418 | ================================================================================ 419 | Tuple expressions 420 | ================================================================================ 421 | 422 | (); 423 | (0,); 424 | let (x, y, z) = (1, 2, 3); 425 | 426 | -------------------------------------------------------------------------------- 427 | 428 | (source_file 429 | (expression_statement 430 | (unit_expression)) 431 | (expression_statement 432 | (tuple_expression 433 | (integer_literal))) 434 | (let_declaration 435 | (tuple_pattern 436 | (identifier) 437 | (identifier) 438 | (identifier)) 439 | (tuple_expression 440 | (integer_literal) 441 | (integer_literal) 442 | (integer_literal)))) 443 | 444 | ================================================================================ 445 | Struct expressions 446 | ================================================================================ 447 | 448 | NothingInMe {}; 449 | Point {x: 10.0, y: 20.0}; 450 | let a = SomeStruct { field1, field2: expression, field3, }; 451 | let u = game::User {name: "Joe", age: 35, score: 100_000}; 452 | let i = Instant { 0: Duration::from_millis(0) }; 453 | 454 | -------------------------------------------------------------------------------- 455 | 456 | (source_file 457 | (expression_statement 458 | (struct_expression 459 | (type_identifier) 460 | (field_initializer_list))) 461 | (expression_statement 462 | (struct_expression 463 | (type_identifier) 464 | (field_initializer_list 465 | (field_initializer 466 | (field_identifier) 467 | (float_literal)) 468 | (field_initializer 469 | (field_identifier) 470 | (float_literal))))) 471 | (let_declaration 472 | (identifier) 473 | (struct_expression 474 | (type_identifier) 475 | (field_initializer_list 476 | (shorthand_field_initializer 477 | (identifier)) 478 | (field_initializer 479 | (field_identifier) 480 | (identifier)) 481 | (shorthand_field_initializer 482 | (identifier))))) 483 | (let_declaration 484 | (identifier) 485 | (struct_expression 486 | (scoped_type_identifier 487 | (identifier) 488 | (type_identifier)) 489 | (field_initializer_list 490 | (field_initializer 491 | (field_identifier) 492 | (string_literal 493 | (string_content))) 494 | (field_initializer 495 | (field_identifier) 496 | (integer_literal)) 497 | (field_initializer 498 | (field_identifier) 499 | (integer_literal))))) 500 | (let_declaration 501 | (identifier) 502 | (struct_expression 503 | (type_identifier) 504 | (field_initializer_list 505 | (field_initializer 506 | (integer_literal) 507 | (call_expression 508 | (scoped_identifier 509 | (identifier) 510 | (identifier)) 511 | (arguments 512 | (integer_literal)))))))) 513 | 514 | ================================================================================ 515 | Struct expressions with update initializers 516 | ================================================================================ 517 | 518 | let u = User{name, ..current_user()}; 519 | 520 | -------------------------------------------------------------------------------- 521 | 522 | (source_file 523 | (let_declaration 524 | (identifier) 525 | (struct_expression 526 | (type_identifier) 527 | (field_initializer_list 528 | (shorthand_field_initializer 529 | (identifier)) 530 | (base_field_initializer 531 | (call_expression 532 | (identifier) 533 | (arguments))))))) 534 | 535 | ================================================================================ 536 | If expressions 537 | ================================================================================ 538 | 539 | fn main() { 540 | if n == 1 { 541 | } else if n == 2 { 542 | } else { 543 | } 544 | } 545 | 546 | let y = if x == 5 { 10 } else { 15 }; 547 | 548 | if foo && bar {} 549 | 550 | if foo && bar || baz {} 551 | 552 | -------------------------------------------------------------------------------- 553 | 554 | (source_file 555 | (function_item 556 | name: (identifier) 557 | parameters: (parameters) 558 | body: (block 559 | (expression_statement 560 | (if_expression 561 | condition: (binary_expression 562 | left: (identifier) 563 | right: (integer_literal)) 564 | consequence: (block) 565 | alternative: (else_clause 566 | (if_expression 567 | condition: (binary_expression 568 | left: (identifier) 569 | right: (integer_literal)) 570 | consequence: (block) 571 | alternative: (else_clause 572 | (block)))))))) 573 | (let_declaration 574 | pattern: (identifier) 575 | value: (if_expression 576 | condition: (binary_expression 577 | left: (identifier) 578 | right: (integer_literal)) 579 | consequence: (block 580 | (integer_literal)) 581 | alternative: (else_clause 582 | (block 583 | (integer_literal))))) 584 | (expression_statement 585 | (if_expression 586 | condition: (binary_expression 587 | left: (identifier) 588 | right: (identifier)) 589 | consequence: (block))) 590 | (expression_statement 591 | (if_expression 592 | condition: (binary_expression 593 | left: (binary_expression 594 | left: (identifier) 595 | right: (identifier)) 596 | right: (identifier)) 597 | consequence: (block)))) 598 | 599 | ================================================================================ 600 | Basic if let expressions 601 | ================================================================================ 602 | 603 | if let Some(a) = b 604 | && c 605 | && d 606 | && let Some(e) = f 607 | { 608 | } 609 | 610 | -------------------------------------------------------------------------------- 611 | 612 | (source_file 613 | (expression_statement 614 | (if_expression 615 | condition: (let_chain 616 | (let_condition 617 | pattern: (tuple_struct_pattern 618 | type: (identifier) 619 | (identifier)) 620 | value: (identifier)) 621 | (identifier) 622 | (identifier) 623 | (let_condition 624 | pattern: (tuple_struct_pattern 625 | type: (identifier) 626 | (identifier)) 627 | value: (identifier))) 628 | consequence: (block)))) 629 | 630 | ================================================================================ 631 | If let expressions 632 | ================================================================================ 633 | 634 | if let ("Bacon", b) = dish { 635 | } 636 | 637 | if let Some("chained") = a && b && let (C, D) = e { 638 | } 639 | 640 | if foo && let bar = || baz && quux {} 641 | 642 | if a && let b = || c || d && e {} 643 | 644 | -------------------------------------------------------------------------------- 645 | 646 | (source_file 647 | (expression_statement 648 | (if_expression 649 | condition: (let_condition 650 | pattern: (tuple_pattern 651 | (string_literal 652 | (string_content)) 653 | (identifier)) 654 | value: (identifier)) 655 | consequence: (block))) 656 | (expression_statement 657 | (if_expression 658 | condition: (let_chain 659 | (let_condition 660 | pattern: (tuple_struct_pattern 661 | type: (identifier) 662 | (string_literal 663 | (string_content))) 664 | value: (identifier)) 665 | (identifier) 666 | (let_condition 667 | pattern: (tuple_pattern 668 | (identifier) 669 | (identifier)) 670 | value: (identifier))) 671 | consequence: (block))) 672 | (expression_statement 673 | (if_expression 674 | condition: (let_chain 675 | (identifier) 676 | (let_condition 677 | pattern: (identifier) 678 | value: (closure_expression 679 | parameters: (closure_parameters) 680 | body: (binary_expression 681 | left: (identifier) 682 | right: (identifier))))) 683 | consequence: (block))) 684 | (expression_statement 685 | (if_expression 686 | condition: (let_chain 687 | (identifier) 688 | (let_condition 689 | pattern: (identifier) 690 | value: (closure_expression 691 | parameters: (closure_parameters) 692 | body: (binary_expression 693 | left: (identifier) 694 | right: (binary_expression 695 | left: (identifier) 696 | right: (identifier)))))) 697 | consequence: (block)))) 698 | 699 | ================================================================================ 700 | While let expressions 701 | ================================================================================ 702 | 703 | while let ("Bacon", b) = dish { 704 | } 705 | 706 | -------------------------------------------------------------------------------- 707 | 708 | (source_file 709 | (expression_statement 710 | (while_expression 711 | (let_condition 712 | (tuple_pattern 713 | (string_literal 714 | (string_content)) 715 | (identifier)) 716 | (identifier)) 717 | (block)))) 718 | 719 | ================================================================================ 720 | Match expressions 721 | ================================================================================ 722 | 723 | match x { 724 | 1 => { "one" } 725 | 2 => "two", 726 | -1 => 1, 727 | -3.14 => 3, 728 | 729 | #[attr1] 730 | 3 => "three", 731 | macro!(4) => "four", 732 | _ => "something else", 733 | } 734 | 735 | let msg = match x { 736 | 0 | 1 | 10 => "one of zero, one, or ten", 737 | y if y < 20 => "less than 20, but not zero, one, or ten", 738 | y if y == 200 => 739 | if a { 740 | "200 (but this is not very stylish)" 741 | } 742 | y if let Some(z) = foo && z && let Some(w) = bar => "very chained", 743 | _ => "something else", 744 | }; 745 | 746 | -------------------------------------------------------------------------------- 747 | 748 | (source_file 749 | (expression_statement 750 | (match_expression 751 | value: (identifier) 752 | body: (match_block 753 | (match_arm 754 | pattern: (match_pattern 755 | (integer_literal)) 756 | value: (block 757 | (string_literal 758 | (string_content)))) 759 | (match_arm 760 | pattern: (match_pattern 761 | (integer_literal)) 762 | value: (string_literal 763 | (string_content))) 764 | (match_arm 765 | pattern: (match_pattern 766 | (negative_literal 767 | (integer_literal))) 768 | value: (integer_literal)) 769 | (match_arm 770 | pattern: (match_pattern 771 | (negative_literal 772 | (float_literal))) 773 | value: (integer_literal)) 774 | (match_arm 775 | (attribute_item 776 | (attribute 777 | (identifier))) 778 | pattern: (match_pattern 779 | (integer_literal)) 780 | value: (string_literal 781 | (string_content))) 782 | (match_arm 783 | pattern: (match_pattern 784 | (macro_invocation 785 | macro: (identifier) 786 | (token_tree 787 | (integer_literal)))) 788 | value: (string_literal 789 | (string_content))) 790 | (match_arm 791 | pattern: (match_pattern) 792 | value: (string_literal 793 | (string_content)))))) 794 | (let_declaration 795 | pattern: (identifier) 796 | value: (match_expression 797 | value: (identifier) 798 | body: (match_block 799 | (match_arm 800 | pattern: (match_pattern 801 | (or_pattern 802 | (or_pattern 803 | (integer_literal) 804 | (integer_literal)) 805 | (integer_literal))) 806 | value: (string_literal 807 | (string_content))) 808 | (match_arm 809 | pattern: (match_pattern 810 | (identifier) 811 | condition: (binary_expression 812 | left: (identifier) 813 | right: (integer_literal))) 814 | value: (string_literal 815 | (string_content))) 816 | (match_arm 817 | pattern: (match_pattern 818 | (identifier) 819 | condition: (binary_expression 820 | left: (identifier) 821 | right: (integer_literal))) 822 | value: (if_expression 823 | condition: (identifier) 824 | consequence: (block 825 | (string_literal 826 | (string_content))))) 827 | (match_arm 828 | pattern: (match_pattern 829 | (identifier) 830 | condition: (let_chain 831 | (let_condition 832 | pattern: (tuple_struct_pattern 833 | type: (identifier) 834 | (identifier)) 835 | value: (identifier)) 836 | (identifier) 837 | (let_condition 838 | pattern: (tuple_struct_pattern 839 | type: (identifier) 840 | (identifier)) 841 | value: (identifier)))) 842 | value: (string_literal 843 | (string_content))) 844 | (match_arm 845 | pattern: (match_pattern) 846 | value: (string_literal 847 | (string_content))))))) 848 | 849 | ================================================================================ 850 | While expressions 851 | ================================================================================ 852 | 853 | while !done { 854 | done = true; 855 | } 856 | 857 | -------------------------------------------------------------------------------- 858 | 859 | (source_file 860 | (expression_statement 861 | (while_expression 862 | condition: (unary_expression 863 | (identifier)) 864 | body: (block 865 | (expression_statement 866 | (assignment_expression 867 | left: (identifier) 868 | right: (boolean_literal))))))) 869 | 870 | ================================================================================ 871 | Loop expressions 872 | ================================================================================ 873 | 874 | 'outer: loop { 875 | 'inner: loop { 876 | break 'outer; 877 | break true; 878 | } 879 | } 880 | 881 | -------------------------------------------------------------------------------- 882 | 883 | (source_file 884 | (expression_statement 885 | (loop_expression 886 | (label 887 | (identifier)) 888 | (block 889 | (expression_statement 890 | (loop_expression 891 | (label 892 | (identifier)) 893 | (block 894 | (expression_statement 895 | (break_expression 896 | (label 897 | (identifier)))) 898 | (expression_statement 899 | (break_expression 900 | (boolean_literal)))))))))) 901 | 902 | ================================================================================ 903 | For expressions 904 | ================================================================================ 905 | 906 | for e in v { 907 | bar(e); 908 | } 909 | 910 | for i in 0..256 { 911 | bar(i); 912 | } 913 | 914 | 'outer: for x in 0..10 { 915 | 'inner: for y in 0..10 { 916 | if x % 2 == 0 { continue 'outer; } 917 | if y % 2 == 0 { continue 'inner; } 918 | } 919 | } 920 | 921 | -------------------------------------------------------------------------------- 922 | 923 | (source_file 924 | (expression_statement 925 | (for_expression 926 | (identifier) 927 | (identifier) 928 | (block 929 | (expression_statement 930 | (call_expression 931 | (identifier) 932 | (arguments 933 | (identifier))))))) 934 | (expression_statement 935 | (for_expression 936 | (identifier) 937 | (range_expression 938 | (integer_literal) 939 | (integer_literal)) 940 | (block 941 | (expression_statement 942 | (call_expression 943 | (identifier) 944 | (arguments 945 | (identifier))))))) 946 | (expression_statement 947 | (for_expression 948 | (label 949 | (identifier)) 950 | (identifier) 951 | (range_expression 952 | (integer_literal) 953 | (integer_literal)) 954 | (block 955 | (expression_statement 956 | (for_expression 957 | (label 958 | (identifier)) 959 | (identifier) 960 | (range_expression 961 | (integer_literal) 962 | (integer_literal)) 963 | (block 964 | (expression_statement 965 | (if_expression 966 | (binary_expression 967 | (binary_expression 968 | (identifier) 969 | (integer_literal)) 970 | (integer_literal)) 971 | (block 972 | (expression_statement 973 | (continue_expression 974 | (label 975 | (identifier))))))) 976 | (expression_statement 977 | (if_expression 978 | (binary_expression 979 | (binary_expression 980 | (identifier) 981 | (integer_literal)) 982 | (integer_literal)) 983 | (block 984 | (expression_statement 985 | (continue_expression 986 | (label 987 | (identifier)))))))))))))) 988 | 989 | ================================================================================ 990 | Field expressions 991 | ================================================================================ 992 | 993 | mystruct.myfield; 994 | foo().x; 995 | value.0.1.iter(); 996 | 1.max(2); 997 | 998 | -------------------------------------------------------------------------------- 999 | 1000 | (source_file 1001 | (expression_statement 1002 | (field_expression 1003 | (identifier) 1004 | (field_identifier))) 1005 | (expression_statement 1006 | (field_expression 1007 | (call_expression 1008 | (identifier) 1009 | (arguments)) 1010 | (field_identifier))) 1011 | (expression_statement 1012 | (call_expression 1013 | (field_expression 1014 | (field_expression 1015 | (field_expression 1016 | (identifier) 1017 | (integer_literal)) 1018 | (integer_literal)) 1019 | (field_identifier)) 1020 | (arguments))) 1021 | (expression_statement 1022 | (call_expression 1023 | (field_expression 1024 | (integer_literal) 1025 | (field_identifier)) 1026 | (arguments 1027 | (integer_literal))))) 1028 | 1029 | ================================================================================ 1030 | Method call expressions 1031 | ================================================================================ 1032 | 1033 | mystruct.foo(); 1034 | 1035 | -------------------------------------------------------------------------------- 1036 | 1037 | (source_file 1038 | (expression_statement 1039 | (call_expression 1040 | (field_expression 1041 | (identifier) 1042 | (field_identifier)) 1043 | (arguments)))) 1044 | 1045 | ================================================================================ 1046 | Index expressions 1047 | ================================================================================ 1048 | 1049 | ([1, 2, 3, 4])[0]; 1050 | arr[10]; 1051 | arr[n]; 1052 | 1053 | -------------------------------------------------------------------------------- 1054 | 1055 | (source_file 1056 | (expression_statement 1057 | (index_expression 1058 | (parenthesized_expression 1059 | (array_expression 1060 | (integer_literal) 1061 | (integer_literal) 1062 | (integer_literal) 1063 | (integer_literal))) 1064 | (integer_literal))) 1065 | (expression_statement 1066 | (index_expression 1067 | (identifier) 1068 | (integer_literal))) 1069 | (expression_statement 1070 | (index_expression 1071 | (identifier) 1072 | (identifier)))) 1073 | 1074 | ================================================================================ 1075 | Scoped functions 1076 | ================================================================================ 1077 | 1078 | a::b(); 1079 | C::::e(); 1080 | ::f(); 1081 | ::g::h(); 1082 | 1083 | -------------------------------------------------------------------------------- 1084 | 1085 | (source_file 1086 | (expression_statement 1087 | (call_expression 1088 | (scoped_identifier 1089 | (identifier) 1090 | (identifier)) 1091 | (arguments))) 1092 | (expression_statement 1093 | (call_expression 1094 | (scoped_identifier 1095 | (generic_type 1096 | (type_identifier) 1097 | (type_arguments 1098 | (type_identifier))) 1099 | (identifier)) 1100 | (arguments))) 1101 | (expression_statement 1102 | (call_expression 1103 | (scoped_identifier 1104 | (identifier)) 1105 | (arguments))) 1106 | (expression_statement 1107 | (call_expression 1108 | (scoped_identifier 1109 | (scoped_identifier 1110 | (identifier)) 1111 | (identifier)) 1112 | (arguments)))) 1113 | 1114 | ================================================================================ 1115 | Scoped functions with fully qualified syntax 1116 | ================================================================================ 1117 | 1118 | ::eat(d); 1119 | 1120 | -------------------------------------------------------------------------------- 1121 | 1122 | (source_file 1123 | (expression_statement 1124 | (call_expression 1125 | (scoped_identifier 1126 | (bracketed_type 1127 | (qualified_type 1128 | (type_identifier) 1129 | (type_identifier))) 1130 | (identifier)) 1131 | (arguments 1132 | (identifier))))) 1133 | 1134 | ================================================================================ 1135 | Scoped functions with macros as types 1136 | ================================================================================ 1137 | 1138 | ::foo(); 1139 | 1140 | -------------------------------------------------------------------------------- 1141 | 1142 | (source_file 1143 | (expression_statement 1144 | (call_expression 1145 | (scoped_identifier 1146 | (bracketed_type 1147 | (macro_invocation 1148 | (identifier) 1149 | (token_tree))) 1150 | (identifier)) 1151 | (arguments)))) 1152 | 1153 | ================================================================================ 1154 | Scoped identifier with nested super 1155 | ================================================================================ 1156 | 1157 | super::super::foo(); 1158 | 1159 | -------------------------------------------------------------------------------- 1160 | 1161 | (source_file 1162 | (expression_statement 1163 | (call_expression 1164 | (scoped_identifier 1165 | (scoped_identifier 1166 | (super) 1167 | (super)) 1168 | (identifier)) 1169 | (arguments)))) 1170 | 1171 | ================================================================================ 1172 | Generic functions 1173 | ================================================================================ 1174 | 1175 | std::sizeof::(); 1176 | foo::<8>(); 1177 | 1178 | -------------------------------------------------------------------------------- 1179 | 1180 | (source_file 1181 | (expression_statement 1182 | (call_expression 1183 | function: (generic_function 1184 | function: (scoped_identifier 1185 | path: (identifier) 1186 | name: (identifier)) 1187 | type_arguments: (type_arguments 1188 | (primitive_type))) 1189 | arguments: (arguments))) 1190 | (expression_statement 1191 | (call_expression 1192 | function: (generic_function 1193 | function: (identifier) 1194 | type_arguments: (type_arguments 1195 | (integer_literal))) 1196 | arguments: (arguments)))) 1197 | 1198 | ================================================================================ 1199 | Closures 1200 | ================================================================================ 1201 | 1202 | a.map(|(b, c)| b.push(c)); 1203 | d.map(move |mut e| { 1204 | f(e); 1205 | g(e) 1206 | }); 1207 | h(|| -> i { j }); 1208 | 1209 | -------------------------------------------------------------------------------- 1210 | 1211 | (source_file 1212 | (expression_statement 1213 | (call_expression 1214 | (field_expression 1215 | (identifier) 1216 | (field_identifier)) 1217 | (arguments 1218 | (closure_expression 1219 | (closure_parameters 1220 | (tuple_pattern 1221 | (identifier) 1222 | (identifier))) 1223 | (call_expression 1224 | (field_expression 1225 | (identifier) 1226 | (field_identifier)) 1227 | (arguments 1228 | (identifier))))))) 1229 | (expression_statement 1230 | (call_expression 1231 | (field_expression 1232 | (identifier) 1233 | (field_identifier)) 1234 | (arguments 1235 | (closure_expression 1236 | (closure_parameters 1237 | (mut_pattern 1238 | (mutable_specifier) 1239 | (identifier))) 1240 | (block 1241 | (expression_statement 1242 | (call_expression 1243 | (identifier) 1244 | (arguments 1245 | (identifier)))) 1246 | (call_expression 1247 | (identifier) 1248 | (arguments 1249 | (identifier)))))))) 1250 | (expression_statement 1251 | (call_expression 1252 | (identifier) 1253 | (arguments 1254 | (closure_expression 1255 | (closure_parameters) 1256 | (type_identifier) 1257 | (block 1258 | (identifier))))))) 1259 | 1260 | ================================================================================ 1261 | Closures with typed parameteres 1262 | ================================================================================ 1263 | 1264 | a.map(|b: usize| b.push(c)); 1265 | 1266 | -------------------------------------------------------------------------------- 1267 | 1268 | (source_file 1269 | (expression_statement 1270 | (call_expression 1271 | (field_expression 1272 | (identifier) 1273 | (field_identifier)) 1274 | (arguments 1275 | (closure_expression 1276 | (closure_parameters 1277 | (parameter 1278 | (identifier) 1279 | (primitive_type))) 1280 | (call_expression 1281 | (field_expression 1282 | (identifier) 1283 | (field_identifier)) 1284 | (arguments 1285 | (identifier)))))))) 1286 | 1287 | ================================================================================ 1288 | Generators 1289 | ================================================================================ 1290 | 1291 | move || { 1292 | while i <= n { 1293 | yield i; 1294 | i += 1; 1295 | } 1296 | return; 1297 | }; 1298 | 1299 | -------------------------------------------------------------------------------- 1300 | 1301 | (source_file 1302 | (expression_statement 1303 | (closure_expression 1304 | (closure_parameters) 1305 | (block 1306 | (expression_statement 1307 | (while_expression 1308 | (binary_expression 1309 | (identifier) 1310 | (identifier)) 1311 | (block 1312 | (expression_statement 1313 | (yield_expression 1314 | (identifier))) 1315 | (expression_statement 1316 | (compound_assignment_expr 1317 | (identifier) 1318 | (integer_literal)))))) 1319 | (expression_statement 1320 | (return_expression)))))) 1321 | 1322 | ================================================================================ 1323 | Unsafe blocks 1324 | ================================================================================ 1325 | 1326 | const a : A = unsafe { foo() }; 1327 | 1328 | -------------------------------------------------------------------------------- 1329 | 1330 | (source_file 1331 | (const_item 1332 | (identifier) 1333 | (type_identifier) 1334 | (unsafe_block 1335 | (block 1336 | (call_expression 1337 | (identifier) 1338 | (arguments)))))) 1339 | 1340 | ================================================================================ 1341 | Inline const or Const blocks as expression 1342 | ================================================================================ 1343 | 1344 | const { 1 + 3 }; 1345 | if *x < 0 { const { &4i32.pow(4) } } else { x } 1346 | let three_ranges = [const { (0..=5).into_inner() }; 3]; 1347 | 1348 | -------------------------------------------------------------------------------- 1349 | 1350 | (source_file 1351 | (expression_statement 1352 | (const_block 1353 | body: (block 1354 | (binary_expression 1355 | left: (integer_literal) 1356 | right: (integer_literal))))) 1357 | (empty_statement) 1358 | (expression_statement 1359 | (if_expression 1360 | condition: (binary_expression 1361 | left: (unary_expression 1362 | (identifier)) 1363 | right: (integer_literal)) 1364 | consequence: (block 1365 | (expression_statement 1366 | (const_block 1367 | body: (block 1368 | (reference_expression 1369 | value: (call_expression 1370 | function: (field_expression 1371 | value: (integer_literal) 1372 | field: (field_identifier)) 1373 | arguments: (arguments 1374 | (integer_literal)))))))) 1375 | alternative: (else_clause 1376 | (block 1377 | (identifier))))) 1378 | (let_declaration 1379 | pattern: (identifier) 1380 | value: (array_expression 1381 | (const_block 1382 | body: (block 1383 | (call_expression 1384 | function: (field_expression 1385 | value: (parenthesized_expression 1386 | (range_expression 1387 | (integer_literal) 1388 | (integer_literal))) 1389 | field: (field_identifier)) 1390 | arguments: (arguments)))) 1391 | length: (integer_literal)))) 1392 | -------------------------------------------------------------------------------- /test/corpus/literals.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | Integer literals 3 | ================================================================================ 4 | 5 | 0; 6 | 0___0; 7 | 123; 8 | 0usize; 9 | 123i32; 10 | 123u32; 11 | 123_u32; 12 | 0xff_u8; 13 | 0o70_i16; 14 | 0b1111_1111_1001_0000_i32; 15 | 1u128; 16 | 17 | -------------------------------------------------------------------------------- 18 | 19 | (source_file 20 | (expression_statement 21 | (integer_literal)) 22 | (expression_statement 23 | (integer_literal)) 24 | (expression_statement 25 | (integer_literal)) 26 | (expression_statement 27 | (integer_literal)) 28 | (expression_statement 29 | (integer_literal)) 30 | (expression_statement 31 | (integer_literal)) 32 | (expression_statement 33 | (integer_literal)) 34 | (expression_statement 35 | (integer_literal)) 36 | (expression_statement 37 | (integer_literal)) 38 | (expression_statement 39 | (integer_literal)) 40 | (expression_statement 41 | (integer_literal))) 42 | 43 | ================================================================================ 44 | Floating-point literals 45 | ================================================================================ 46 | 47 | 123.123; 48 | 2.; 49 | 123.0f64; 50 | 0.1f64; 51 | 0.1f32; 52 | 12E+99_f64; 53 | 54 | -------------------------------------------------------------------------------- 55 | 56 | (source_file 57 | (expression_statement 58 | (float_literal)) 59 | (expression_statement 60 | (float_literal)) 61 | (expression_statement 62 | (float_literal)) 63 | (expression_statement 64 | (float_literal)) 65 | (expression_statement 66 | (float_literal)) 67 | (expression_statement 68 | (float_literal))) 69 | 70 | ================================================================================ 71 | String literals 72 | ================================================================================ 73 | 74 | ""; 75 | "abc"; 76 | c"foo"; 77 | b"foo\nbar"; 78 | "foo\ 79 | bar"; 80 | "\"foo\""; 81 | "/* foo bar */ foo bar"; 82 | "foo\x42\x43bar"; 83 | "foo \x42 \x43 bar"; 84 | 85 | -------------------------------------------------------------------------------- 86 | 87 | (source_file 88 | (expression_statement 89 | (string_literal)) 90 | (expression_statement 91 | (string_literal 92 | (string_content))) 93 | (expression_statement 94 | (string_literal 95 | (string_content))) 96 | (expression_statement 97 | (string_literal 98 | (string_content) 99 | (escape_sequence) 100 | (string_content))) 101 | (expression_statement 102 | (string_literal 103 | (string_content) 104 | (escape_sequence) 105 | (string_content))) 106 | (expression_statement 107 | (string_literal 108 | (escape_sequence) 109 | (string_content) 110 | (escape_sequence))) 111 | (expression_statement 112 | (string_literal 113 | (string_content))) 114 | (expression_statement 115 | (string_literal 116 | (string_content) 117 | (escape_sequence) 118 | (escape_sequence) 119 | (string_content))) 120 | (expression_statement 121 | (string_literal 122 | (string_content) 123 | (escape_sequence) 124 | (string_content) 125 | (escape_sequence) 126 | (string_content)))) 127 | 128 | ================================================================================ 129 | Raw string literals 130 | ================================================================================ 131 | 132 | r#"abc"#; r##"ok"##; 133 | r##"foo #"# bar"##; 134 | r###"foo ##"## bar"###; 135 | r######"foo ##### bar"######; 136 | 137 | -------------------------------------------------------------------------------- 138 | 139 | (source_file 140 | (expression_statement 141 | (raw_string_literal 142 | (string_content))) 143 | (expression_statement 144 | (raw_string_literal 145 | (string_content))) 146 | (expression_statement 147 | (raw_string_literal 148 | (string_content))) 149 | (expression_statement 150 | (raw_string_literal 151 | (string_content))) 152 | (expression_statement 153 | (raw_string_literal 154 | (string_content)))) 155 | 156 | ================================================================================ 157 | Raw byte string literals 158 | ================================================================================ 159 | 160 | br#"abc"#; 161 | br##"abc"##; 162 | 163 | -------------------------------------------------------------------------------- 164 | 165 | (source_file 166 | (expression_statement 167 | (raw_string_literal 168 | (string_content))) 169 | (expression_statement 170 | (raw_string_literal 171 | (string_content)))) 172 | 173 | ================================================================================ 174 | Raw C string literals 175 | ================================================================================ 176 | 177 | cr#"abc"#; 178 | cr##"abc"##; 179 | 180 | -------------------------------------------------------------------------------- 181 | 182 | (source_file 183 | (expression_statement 184 | (raw_string_literal 185 | (string_content))) 186 | (expression_statement 187 | (raw_string_literal 188 | (string_content)))) 189 | 190 | ================================================================================ 191 | Character literals 192 | ================================================================================ 193 | 194 | 'a'; 195 | '\''; 196 | '\0'; 197 | b'x'; 198 | '\t'; 199 | '\xff'; 200 | '\\'; 201 | 202 | -------------------------------------------------------------------------------- 203 | 204 | (source_file 205 | (expression_statement 206 | (char_literal)) 207 | (expression_statement 208 | (char_literal)) 209 | (expression_statement 210 | (char_literal)) 211 | (expression_statement 212 | (char_literal)) 213 | (expression_statement 214 | (char_literal)) 215 | (expression_statement 216 | (char_literal)) 217 | (expression_statement 218 | (char_literal))) 219 | 220 | ================================================================================ 221 | Boolean literals 222 | ================================================================================ 223 | 224 | true; 225 | false; 226 | 227 | -------------------------------------------------------------------------------- 228 | 229 | (source_file 230 | (expression_statement 231 | (boolean_literal)) 232 | (expression_statement 233 | (boolean_literal))) 234 | -------------------------------------------------------------------------------- /test/corpus/macros.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | Macro invocation - no arguments 3 | ================================================================================ 4 | 5 | a!(); 6 | b![]; 7 | c!{}; 8 | d::e!(); 9 | f::g::h!{}; 10 | 11 | -------------------------------------------------------------------------------- 12 | 13 | (source_file 14 | (expression_statement 15 | (macro_invocation 16 | (identifier) 17 | (token_tree))) 18 | (expression_statement 19 | (macro_invocation 20 | (identifier) 21 | (token_tree))) 22 | (expression_statement 23 | (macro_invocation 24 | (identifier) 25 | (token_tree))) 26 | (expression_statement 27 | (macro_invocation 28 | (scoped_identifier 29 | (identifier) 30 | (identifier)) 31 | (token_tree))) 32 | (expression_statement 33 | (macro_invocation 34 | (scoped_identifier 35 | (scoped_identifier 36 | (identifier) 37 | (identifier)) 38 | (identifier)) 39 | (token_tree)))) 40 | 41 | ================================================================================ 42 | Macro invocation - arbitrary tokens 43 | ================================================================================ 44 | 45 | a!(* a *); 46 | a!(& a &); 47 | a!(- a -); 48 | a!(b + c + +); 49 | a!('a'..='z'); 50 | a!('\u{0}'..='\u{2}'); 51 | a!('lifetime) 52 | default!(a); 53 | union!(a); 54 | a!($); 55 | a!($()); 56 | a!($ a $); 57 | a!(${$([ a ])}); 58 | a!($a $a:ident $($a);*); 59 | 60 | -------------------------------------------------------------------------------- 61 | 62 | (source_file 63 | (expression_statement 64 | (macro_invocation 65 | (identifier) 66 | (token_tree 67 | (identifier)))) 68 | (expression_statement 69 | (macro_invocation 70 | (identifier) 71 | (token_tree 72 | (identifier)))) 73 | (expression_statement 74 | (macro_invocation 75 | (identifier) 76 | (token_tree 77 | (identifier)))) 78 | (expression_statement 79 | (macro_invocation 80 | (identifier) 81 | (token_tree 82 | (identifier) 83 | (identifier)))) 84 | (expression_statement 85 | (macro_invocation 86 | (identifier) 87 | (token_tree 88 | (char_literal) 89 | (char_literal)))) 90 | (expression_statement 91 | (macro_invocation 92 | (identifier) 93 | (token_tree 94 | (char_literal) 95 | (char_literal)))) 96 | (macro_invocation 97 | (identifier) 98 | (token_tree 99 | (identifier))) 100 | (expression_statement 101 | (macro_invocation 102 | (identifier) 103 | (token_tree 104 | (identifier)))) 105 | (expression_statement 106 | (macro_invocation 107 | (identifier) 108 | (token_tree 109 | (identifier)))) 110 | (expression_statement 111 | (macro_invocation 112 | (identifier) 113 | (token_tree))) 114 | (expression_statement 115 | (macro_invocation 116 | (identifier) 117 | (token_tree 118 | (token_tree)))) 119 | (expression_statement 120 | (macro_invocation 121 | (identifier) 122 | (token_tree 123 | (identifier)))) 124 | (expression_statement 125 | (macro_invocation 126 | (identifier) 127 | (token_tree 128 | (token_tree 129 | (token_tree 130 | (token_tree 131 | (identifier))))))) 132 | (expression_statement 133 | (macro_invocation 134 | (identifier) 135 | (token_tree 136 | (identifier) 137 | (identifier) 138 | (identifier) 139 | (token_tree 140 | (identifier)))))) 141 | 142 | ================================================================================ 143 | Macro invocation with comments 144 | ================================================================================ 145 | 146 | ok! { 147 | // one 148 | /* two */ 149 | } 150 | 151 | -------------------------------------------------------------------------------- 152 | 153 | (source_file 154 | (macro_invocation 155 | (identifier) 156 | (token_tree 157 | (line_comment) 158 | (block_comment)))) 159 | 160 | ================================================================================ 161 | Macro definition 162 | ================================================================================ 163 | 164 | macro_rules! say_hello { 165 | () => ( 166 | println!("Hello!"); 167 | ) 168 | } 169 | 170 | macro_rules! four { 171 | () => {1 + 3}; 172 | } 173 | 174 | macro_rules! foo { 175 | (x => $e:expr) => (println!("mode X: {}", $e)); 176 | (y => $e:expr) => (println!("mode Y: {}", $e)) 177 | } 178 | 179 | macro_rules! o_O { 180 | ( 181 | $($x:expr; [ $( $y:expr ),* ]);* 182 | ) => { 183 | $($($x + $e),*),* 184 | } 185 | } 186 | 187 | macro_rules! zero_or_one { 188 | ($($e:expr),?) => { 189 | $($e),? 190 | }; 191 | } 192 | 193 | macro_rules! empty [ 194 | () => {}; 195 | ]; 196 | 197 | -------------------------------------------------------------------------------- 198 | 199 | (source_file 200 | (macro_definition 201 | name: (identifier) 202 | (macro_rule 203 | left: (token_tree_pattern) 204 | right: (token_tree 205 | (identifier) 206 | (token_tree 207 | (string_literal 208 | (string_content)))))) 209 | (macro_definition 210 | name: (identifier) 211 | (macro_rule 212 | left: (token_tree_pattern) 213 | right: (token_tree 214 | (integer_literal) 215 | (integer_literal)))) 216 | (macro_definition 217 | name: (identifier) 218 | (macro_rule 219 | left: (token_tree_pattern 220 | (identifier) 221 | (token_binding_pattern 222 | name: (metavariable) 223 | type: (fragment_specifier))) 224 | right: (token_tree 225 | (identifier) 226 | (token_tree 227 | (string_literal 228 | (string_content)) 229 | (metavariable)))) 230 | (macro_rule 231 | left: (token_tree_pattern 232 | (identifier) 233 | (token_binding_pattern 234 | name: (metavariable) 235 | type: (fragment_specifier))) 236 | right: (token_tree 237 | (identifier) 238 | (token_tree 239 | (string_literal 240 | (string_content)) 241 | (metavariable))))) 242 | (macro_definition 243 | name: (identifier) 244 | (macro_rule 245 | left: (token_tree_pattern 246 | (token_repetition_pattern 247 | (token_binding_pattern 248 | name: (metavariable) 249 | type: (fragment_specifier)) 250 | (token_tree_pattern 251 | (token_repetition_pattern 252 | (token_binding_pattern 253 | name: (metavariable) 254 | type: (fragment_specifier)))))) 255 | right: (token_tree 256 | (token_repetition 257 | (token_repetition 258 | (metavariable) 259 | (metavariable)))))) 260 | (macro_definition 261 | name: (identifier) 262 | (macro_rule 263 | left: (token_tree_pattern 264 | (token_repetition_pattern 265 | (token_binding_pattern 266 | name: (metavariable) 267 | type: (fragment_specifier)))) 268 | right: (token_tree 269 | (token_repetition 270 | (metavariable))))) 271 | (macro_definition 272 | name: (identifier) 273 | (macro_rule 274 | left: (token_tree_pattern) 275 | right: (token_tree)))) 276 | -------------------------------------------------------------------------------- /test/corpus/patterns.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | Tuple struct patterns 3 | ================================================================================ 4 | 5 | match x { 6 | Some(x) => "some", 7 | std::None() => "none" 8 | } 9 | 10 | -------------------------------------------------------------------------------- 11 | 12 | (source_file 13 | (expression_statement 14 | (match_expression 15 | (identifier) 16 | (match_block 17 | (match_arm 18 | (match_pattern 19 | (tuple_struct_pattern 20 | (identifier) 21 | (identifier))) 22 | (string_literal 23 | (string_content))) 24 | (match_arm 25 | (match_pattern 26 | (tuple_struct_pattern 27 | (scoped_identifier 28 | (identifier) 29 | (identifier)))) 30 | (string_literal 31 | (string_content))))))) 32 | 33 | ================================================================================ 34 | Reference patterns 35 | ================================================================================ 36 | 37 | match x { 38 | A(ref x) => x.0, 39 | ref mut y => y, 40 | & mut z => z, 41 | } 42 | 43 | -------------------------------------------------------------------------------- 44 | 45 | (source_file 46 | (expression_statement 47 | (match_expression 48 | (identifier) 49 | (match_block 50 | (match_arm 51 | (match_pattern 52 | (tuple_struct_pattern 53 | (identifier) 54 | (ref_pattern 55 | (identifier)))) 56 | (field_expression 57 | (identifier) 58 | (integer_literal))) 59 | (match_arm 60 | (match_pattern 61 | (ref_pattern 62 | (mut_pattern 63 | (mutable_specifier) 64 | (identifier)))) 65 | (identifier)) 66 | (match_arm 67 | (match_pattern 68 | (reference_pattern 69 | (mutable_specifier) 70 | (identifier))) 71 | (identifier)))))) 72 | 73 | ================================================================================ 74 | Struct patterns 75 | ================================================================================ 76 | 77 | match x { 78 | Person{name, age} if age < 5 => ("toddler", name), 79 | Person{name: adult_name, age: _} => ("adult", adult_name), 80 | } 81 | 82 | match y { 83 | Bar::T1(_, Some::(x)) => println!("{x}"), 84 | } 85 | 86 | -------------------------------------------------------------------------------- 87 | 88 | (source_file 89 | (expression_statement 90 | (match_expression 91 | (identifier) 92 | (match_block 93 | (match_arm 94 | (match_pattern 95 | (struct_pattern 96 | (type_identifier) 97 | (field_pattern 98 | (shorthand_field_identifier)) 99 | (field_pattern 100 | (shorthand_field_identifier))) 101 | (binary_expression 102 | (identifier) 103 | (integer_literal))) 104 | (tuple_expression 105 | (string_literal 106 | (string_content)) 107 | (identifier))) 108 | (match_arm 109 | (match_pattern 110 | (struct_pattern 111 | (type_identifier) 112 | (field_pattern 113 | (field_identifier) 114 | (identifier)) 115 | (field_pattern 116 | (field_identifier)))) 117 | (tuple_expression 118 | (string_literal 119 | (string_content)) 120 | (identifier)))))) 121 | (expression_statement 122 | (match_expression 123 | (identifier) 124 | (match_block 125 | (match_arm 126 | (match_pattern 127 | (tuple_struct_pattern 128 | (scoped_identifier 129 | (identifier) 130 | (identifier)) 131 | (tuple_struct_pattern 132 | (generic_type 133 | (type_identifier) 134 | (type_arguments 135 | (primitive_type))) 136 | (identifier)))) 137 | (macro_invocation 138 | (identifier) 139 | (token_tree 140 | (string_literal 141 | (string_content))))))))) 142 | 143 | ================================================================================ 144 | Ignored patterns 145 | ================================================================================ 146 | 147 | match x { 148 | (a, ..) => a, 149 | B(..) => c, 150 | D::E{f: g, ..} => g 151 | } 152 | 153 | -------------------------------------------------------------------------------- 154 | 155 | (source_file 156 | (expression_statement 157 | (match_expression 158 | (identifier) 159 | (match_block 160 | (match_arm 161 | (match_pattern 162 | (tuple_pattern 163 | (identifier) 164 | (remaining_field_pattern))) 165 | (identifier)) 166 | (match_arm 167 | (match_pattern 168 | (tuple_struct_pattern 169 | (identifier) 170 | (remaining_field_pattern))) 171 | (identifier)) 172 | (match_arm 173 | (match_pattern 174 | (struct_pattern 175 | (scoped_type_identifier 176 | (identifier) 177 | (type_identifier)) 178 | (field_pattern 179 | (field_identifier) 180 | (identifier)) 181 | (remaining_field_pattern))) 182 | (identifier)))))) 183 | 184 | ================================================================================ 185 | Captured patterns 186 | ================================================================================ 187 | 188 | match x { 189 | a @ A(_) | b @ B(..) => a, 190 | a @ 1 ... 5 => a, 191 | Some(1 ... 5) => a, 192 | a @ b...c => a, 193 | a @ b..=c => a, 194 | d.. => a, 195 | ..d => d, 196 | a @ ..=5 => a 197 | } 198 | 199 | match name { 200 | | "IPV6_FLOWINFO" 201 | | "IPV6_FLOWLABEL_MGR" 202 | | "IPV6_FLOWINFO_SEND" => true, 203 | _ => false, 204 | } 205 | 206 | -------------------------------------------------------------------------------- 207 | 208 | (source_file 209 | (expression_statement 210 | (match_expression 211 | value: (identifier) 212 | body: (match_block 213 | (match_arm 214 | pattern: (match_pattern 215 | (or_pattern 216 | (captured_pattern 217 | (identifier) 218 | (tuple_struct_pattern 219 | type: (identifier))) 220 | (captured_pattern 221 | (identifier) 222 | (tuple_struct_pattern 223 | type: (identifier) 224 | (remaining_field_pattern))))) 225 | value: (identifier)) 226 | (match_arm 227 | pattern: (match_pattern 228 | (captured_pattern 229 | (identifier) 230 | (range_pattern 231 | left: (integer_literal) 232 | right: (integer_literal)))) 233 | value: (identifier)) 234 | (match_arm 235 | pattern: (match_pattern 236 | (tuple_struct_pattern 237 | type: (identifier) 238 | (range_pattern 239 | left: (integer_literal) 240 | right: (integer_literal)))) 241 | value: (identifier)) 242 | (match_arm 243 | pattern: (match_pattern 244 | (captured_pattern 245 | (identifier) 246 | (range_pattern 247 | left: (identifier) 248 | right: (identifier)))) 249 | value: (identifier)) 250 | (match_arm 251 | pattern: (match_pattern 252 | (captured_pattern 253 | (identifier) 254 | (range_pattern 255 | left: (identifier) 256 | right: (identifier)))) 257 | value: (identifier)) 258 | (match_arm 259 | pattern: (match_pattern 260 | (range_pattern 261 | left: (identifier))) 262 | value: (identifier)) 263 | (match_arm 264 | pattern: (match_pattern 265 | (range_pattern 266 | right: (identifier))) 267 | value: (identifier)) 268 | (match_arm 269 | pattern: (match_pattern 270 | (captured_pattern 271 | (identifier) 272 | (range_pattern 273 | right: (integer_literal)))) 274 | value: (identifier))))) 275 | (expression_statement 276 | (match_expression 277 | value: (identifier) 278 | body: (match_block 279 | (match_arm 280 | pattern: (match_pattern 281 | (or_pattern 282 | (or_pattern 283 | (or_pattern 284 | (string_literal 285 | (string_content))) 286 | (string_literal 287 | (string_content))) 288 | (string_literal 289 | (string_content)))) 290 | value: (boolean_literal)) 291 | (match_arm 292 | pattern: (match_pattern) 293 | value: (boolean_literal)))))) 294 | 295 | ================================================================================ 296 | Or patterns 297 | ================================================================================ 298 | 299 | if let A(x) | B(x) = expr { 300 | do_stuff_with(x); 301 | } 302 | 303 | while let A(x) | B(x) = expr { 304 | do_stuff_with(x); 305 | } 306 | 307 | let Ok(index) | Err(index) = slice.binary_search(&x); 308 | 309 | for ref a | b in c {} 310 | 311 | let Ok(x) | Err(x) = binary_search(x); 312 | 313 | for A | B | C in c {} 314 | 315 | |(Ok(x) | Err(x))| expr(); 316 | 317 | let ref mut x @ (A | B | C); 318 | 319 | fn foo((1 | 2 | 3): u8) {} 320 | 321 | if let x!() | y!() = () {} 322 | 323 | -------------------------------------------------------------------------------- 324 | 325 | (source_file 326 | (expression_statement 327 | (if_expression 328 | condition: (let_condition 329 | pattern: (or_pattern 330 | (tuple_struct_pattern 331 | type: (identifier) 332 | (identifier)) 333 | (tuple_struct_pattern 334 | type: (identifier) 335 | (identifier))) 336 | value: (identifier)) 337 | consequence: (block 338 | (expression_statement 339 | (call_expression 340 | function: (identifier) 341 | arguments: (arguments 342 | (identifier))))))) 343 | (expression_statement 344 | (while_expression 345 | condition: (let_condition 346 | pattern: (or_pattern 347 | (tuple_struct_pattern 348 | type: (identifier) 349 | (identifier)) 350 | (tuple_struct_pattern 351 | type: (identifier) 352 | (identifier))) 353 | value: (identifier)) 354 | body: (block 355 | (expression_statement 356 | (call_expression 357 | function: (identifier) 358 | arguments: (arguments 359 | (identifier))))))) 360 | (let_declaration 361 | pattern: (or_pattern 362 | (tuple_struct_pattern 363 | type: (identifier) 364 | (identifier)) 365 | (tuple_struct_pattern 366 | type: (identifier) 367 | (identifier))) 368 | value: (call_expression 369 | function: (field_expression 370 | value: (identifier) 371 | field: (field_identifier)) 372 | arguments: (arguments 373 | (reference_expression 374 | value: (identifier))))) 375 | (expression_statement 376 | (for_expression 377 | pattern: (or_pattern 378 | (ref_pattern 379 | (identifier)) 380 | (identifier)) 381 | value: (identifier) 382 | body: (block))) 383 | (let_declaration 384 | pattern: (or_pattern 385 | (tuple_struct_pattern 386 | type: (identifier) 387 | (identifier)) 388 | (tuple_struct_pattern 389 | type: (identifier) 390 | (identifier))) 391 | value: (call_expression 392 | function: (identifier) 393 | arguments: (arguments 394 | (identifier)))) 395 | (expression_statement 396 | (for_expression 397 | pattern: (or_pattern 398 | (or_pattern 399 | (identifier) 400 | (identifier)) 401 | (identifier)) 402 | value: (identifier) 403 | body: (block))) 404 | (expression_statement 405 | (closure_expression 406 | parameters: (closure_parameters 407 | (tuple_pattern 408 | (or_pattern 409 | (tuple_struct_pattern 410 | type: (identifier) 411 | (identifier)) 412 | (tuple_struct_pattern 413 | type: (identifier) 414 | (identifier))))) 415 | body: (call_expression 416 | function: (identifier) 417 | arguments: (arguments)))) 418 | (let_declaration 419 | pattern: (ref_pattern 420 | (mut_pattern 421 | (mutable_specifier) 422 | (captured_pattern 423 | (identifier) 424 | (tuple_pattern 425 | (or_pattern 426 | (or_pattern 427 | (identifier) 428 | (identifier)) 429 | (identifier))))))) 430 | (function_item 431 | name: (identifier) 432 | parameters: (parameters 433 | (parameter 434 | pattern: (tuple_pattern 435 | (or_pattern 436 | (or_pattern 437 | (integer_literal) 438 | (integer_literal)) 439 | (integer_literal))) 440 | type: (primitive_type))) 441 | body: (block)) 442 | (expression_statement 443 | (if_expression 444 | condition: (let_condition 445 | pattern: (or_pattern 446 | (macro_invocation 447 | macro: (identifier) 448 | (token_tree)) 449 | (macro_invocation 450 | macro: (identifier) 451 | (token_tree))) 452 | value: (unit_expression)) 453 | consequence: (block)))) 454 | 455 | ================================================================================ 456 | Inline const or Const blocks as pattern 457 | ================================================================================ 458 | 459 | fn foo(x: i32) { 460 | const CUBE: i32 = 3.pow(3); 461 | match x { 462 | CUBE => println!("three cubed"), 463 | _ => {} 464 | } 465 | } 466 | 467 | fn foo(x: i32) { 468 | match x { 469 | const { 3.pow(3) } => println!("three cubed"), 470 | _ => {} 471 | } 472 | } 473 | 474 | -------------------------------------------------------------------------------- 475 | 476 | (source_file 477 | (function_item 478 | name: (identifier) 479 | parameters: (parameters 480 | (parameter 481 | pattern: (identifier) 482 | type: (primitive_type))) 483 | body: (block 484 | (const_item 485 | name: (identifier) 486 | type: (primitive_type) 487 | value: (call_expression 488 | function: (field_expression 489 | value: (integer_literal) 490 | field: (field_identifier)) 491 | arguments: (arguments 492 | (integer_literal)))) 493 | (expression_statement 494 | (match_expression 495 | value: (identifier) 496 | body: (match_block 497 | (match_arm 498 | pattern: (match_pattern 499 | (identifier)) 500 | value: (macro_invocation 501 | macro: (identifier) 502 | (token_tree 503 | (string_literal 504 | (string_content))))) 505 | (match_arm 506 | pattern: (match_pattern) 507 | value: (block))))))) 508 | (function_item 509 | name: (identifier) 510 | parameters: (parameters 511 | (parameter 512 | pattern: (identifier) 513 | type: (primitive_type))) 514 | body: (block 515 | (expression_statement 516 | (match_expression 517 | value: (identifier) 518 | body: (match_block 519 | (match_arm 520 | pattern: (match_pattern 521 | (const_block 522 | body: (block 523 | (call_expression 524 | function: (field_expression 525 | value: (integer_literal) 526 | field: (field_identifier)) 527 | arguments: (arguments 528 | (integer_literal)))))) 529 | value: (macro_invocation 530 | macro: (identifier) 531 | (token_tree 532 | (string_literal 533 | (string_content))))) 534 | (match_arm 535 | pattern: (match_pattern) 536 | value: (block)))))))) 537 | 538 | ================================================================================ 539 | Pattern with turbofish 540 | ================================================================================ 541 | 542 | match y { 543 | None:: => 17, 544 | _ => 42, 545 | } 546 | 547 | -------------------------------------------------------------------------------- 548 | 549 | (source_file 550 | (expression_statement 551 | (match_expression 552 | (identifier) 553 | (match_block 554 | (match_arm 555 | (match_pattern 556 | (generic_pattern 557 | (identifier) 558 | (type_arguments 559 | (type_identifier)))) 560 | (integer_literal)) 561 | (match_arm 562 | (match_pattern) 563 | (integer_literal)))))) 564 | -------------------------------------------------------------------------------- /test/corpus/source_files.txt: -------------------------------------------------------------------------------- 1 | ============================================ 2 | Block comments 3 | ============================================ 4 | 5 | /* 6 | * Block comments 7 | */ 8 | 9 | /* Comment with asterisks **/ 10 | 11 | /** Outer block comment */ 12 | 13 | 14 | /*! Inner block comment */ 15 | /**/ 16 | 17 | ---- 18 | 19 | (source_file 20 | (block_comment) 21 | (block_comment) 22 | (block_comment 23 | outer: (outer_doc_comment_marker) 24 | doc: (doc_comment)) 25 | (block_comment 26 | inner: (inner_doc_comment_marker) 27 | doc: (doc_comment)) 28 | (block_comment)) 29 | 30 | ============================================ 31 | Nested block comments 32 | ============================================ 33 | 34 | /* /* double nested */ */ 35 | 36 | // --- 37 | 38 | /*/*/* triple nested */*/*/ 39 | 40 | // --- 41 | 42 | /**** 43 | /**** 44 | nested with extra stars which makes it a regular block comment 45 | and not a block doc comment 46 | ****/ 47 | ****/ 48 | 49 | // --- 50 | 51 | ---- 52 | 53 | (source_file 54 | (block_comment) 55 | (line_comment) 56 | (block_comment) 57 | (line_comment) 58 | (block_comment) 59 | (line_comment)) 60 | 61 | ============================================ 62 | Line comments 63 | ============================================ 64 | 65 | // Comment 66 | 67 | /// Outer line doc comment 68 | 69 | //! Inner line doc comment 70 | 71 | ---- 72 | 73 | (source_file 74 | (line_comment) 75 | (line_comment 76 | outer: (outer_doc_comment_marker) 77 | doc: (doc_comment)) 78 | (line_comment 79 | inner: (inner_doc_comment_marker) 80 | doc: (doc_comment))) 81 | 82 | ==================================== 83 | Line doc comments 84 | ==================================== 85 | //! - Inner line doc 86 | //!! - Still an inner line doc (but with a bang at the beginning) 87 | 88 | // - Only a comment 89 | /// - Outer line doc (exactly 3 slashes) 90 | /// 91 | //// - Only a comment 92 | 93 | --- 94 | 95 | (source_file 96 | (line_comment 97 | inner: (inner_doc_comment_marker) 98 | doc: (doc_comment)) 99 | (line_comment 100 | inner: (inner_doc_comment_marker) 101 | doc: (doc_comment)) 102 | (line_comment) 103 | (line_comment 104 | outer: (outer_doc_comment_marker) 105 | doc: (doc_comment)) 106 | (line_comment 107 | outer: (outer_doc_comment_marker) 108 | doc: (doc_comment)) 109 | (line_comment)) 110 | 111 | ==================================== 112 | Block doc comments 113 | ==================================== 114 | 115 | /*! - Inner block doc */ 116 | /*!! - Still an inner block doc (but with a bang at the beginning) */ 117 | 118 | /* - Only a comment */ 119 | /** - Outer block doc (exactly) 2 asterisks */ 120 | /*** - Only a comment */ 121 | 122 | ---- 123 | 124 | (source_file 125 | (block_comment 126 | inner: (inner_doc_comment_marker) 127 | doc: (doc_comment)) 128 | (block_comment 129 | inner: (inner_doc_comment_marker) 130 | doc: (doc_comment)) 131 | (block_comment) 132 | (block_comment 133 | outer: (outer_doc_comment_marker) 134 | doc: (doc_comment)) 135 | (block_comment)) 136 | 137 | ===================================== 138 | Nested doc block comments 139 | ===================================== 140 | 141 | /* /* */ /** */ /*! */ */ 142 | /*! /* */ /** */ /*! */ */ 143 | /** /* */ /** */ /*! */ */ 144 | 145 | ---- 146 | 147 | (source_file 148 | (block_comment) 149 | (block_comment 150 | inner: (inner_doc_comment_marker) 151 | doc: (doc_comment)) 152 | (block_comment 153 | outer: (outer_doc_comment_marker) 154 | doc: (doc_comment))) 155 | 156 | ==================================== 157 | Comments degenerate cases 158 | ==================================== 159 | 160 | //! 161 | 162 | /*!*/ 163 | 164 | // 165 | 166 | /// 167 | let x; // <- immediate item after an empty line doc comment 168 | 169 | /**/ 170 | 171 | /***/ 172 | 173 | ---- 174 | 175 | (source_file 176 | (line_comment 177 | (inner_doc_comment_marker) 178 | (doc_comment)) 179 | (block_comment 180 | (inner_doc_comment_marker)) 181 | (line_comment) 182 | (line_comment 183 | (outer_doc_comment_marker) 184 | (doc_comment)) 185 | (let_declaration 186 | (identifier)) 187 | (line_comment) 188 | (block_comment) 189 | (block_comment)) 190 | 191 | ================================================================================ 192 | Line doc comment with no EOL 193 | ================================================================================ 194 | 195 | //! Doc comment 196 | -------------------------------------------------------------------------------- 197 | 198 | (source_file 199 | (line_comment 200 | (inner_doc_comment_marker) 201 | (doc_comment))) 202 | 203 | ===================================== 204 | Greek letters in identifiers 205 | ===================================== 206 | 207 | const σ1 : Σ = 0; 208 | const ψ_2 : Ψ = 1; 209 | 210 | --- 211 | 212 | (source_file 213 | (const_item 214 | (identifier) 215 | (type_identifier) 216 | (integer_literal)) 217 | (const_item 218 | (identifier) 219 | (type_identifier) 220 | (integer_literal))) 221 | 222 | ================================================================================ 223 | Shebang line containing spaces 224 | ================================================================================ 225 | 226 | #!/usr/bin/env -S cargo +nightly -Zscript 227 | 228 | -------------------------------------------------------------------------------- 229 | 230 | (source_file 231 | (shebang)) 232 | 233 | ================================================================================ 234 | Empty shebang with code after 235 | ================================================================================ 236 | 237 | #! 238 | fn main() {} 239 | 240 | -------------------------------------------------------------------------------- 241 | 242 | (source_file 243 | (shebang) 244 | (function_item 245 | (identifier) 246 | (parameters) 247 | (block))) 248 | 249 | ================================================================================ 250 | Immediate inner attribute 251 | ================================================================================ 252 | 253 | #![feature(thing)] 254 | fn main() {} 255 | 256 | -------------------------------------------------------------------------------- 257 | 258 | (source_file 259 | (inner_attribute_item 260 | (attribute 261 | (identifier) 262 | (token_tree 263 | (identifier)))) 264 | (function_item 265 | (identifier) 266 | (parameters) 267 | (block))) 268 | -------------------------------------------------------------------------------- /test/corpus/types.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | The unit type 3 | ================================================================================ 4 | 5 | type A = (); 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (source_file 10 | (type_item 11 | (type_identifier) 12 | (unit_type))) 13 | 14 | ================================================================================ 15 | Tuple types 16 | ================================================================================ 17 | 18 | type A = (i32, String); 19 | 20 | -------------------------------------------------------------------------------- 21 | 22 | (source_file 23 | (type_item 24 | (type_identifier) 25 | (tuple_type 26 | (primitive_type) 27 | (type_identifier)))) 28 | 29 | ================================================================================ 30 | Reference types 31 | ================================================================================ 32 | 33 | type A = &B; 34 | type C = &'a str; 35 | type D = &'a mut str; 36 | 37 | -------------------------------------------------------------------------------- 38 | 39 | (source_file 40 | (type_item 41 | (type_identifier) 42 | (reference_type 43 | (type_identifier))) 44 | (type_item 45 | (type_identifier) 46 | (reference_type 47 | (lifetime 48 | (identifier)) 49 | (primitive_type))) 50 | (type_item 51 | (type_identifier) 52 | (reference_type 53 | (lifetime 54 | (identifier)) 55 | (mutable_specifier) 56 | (primitive_type)))) 57 | 58 | ================================================================================ 59 | Raw pointer types 60 | ================================================================================ 61 | 62 | type A = *mut B; 63 | type C = *const str; 64 | 65 | -------------------------------------------------------------------------------- 66 | 67 | (source_file 68 | (type_item 69 | (type_identifier) 70 | (pointer_type 71 | (mutable_specifier) 72 | (type_identifier))) 73 | (type_item 74 | (type_identifier) 75 | (pointer_type 76 | (primitive_type)))) 77 | 78 | ================================================================================ 79 | Generic types 80 | ================================================================================ 81 | 82 | type A = B; 83 | type D = E; 84 | type G = H<'a, I>; 85 | type J = H; 86 | 87 | -------------------------------------------------------------------------------- 88 | 89 | (source_file 90 | (type_item 91 | (type_identifier) 92 | (generic_type 93 | (type_identifier) 94 | (type_arguments 95 | (type_identifier)))) 96 | (type_item 97 | (type_identifier) 98 | (generic_type 99 | (type_identifier) 100 | (type_arguments 101 | (type_identifier) 102 | (primitive_type)))) 103 | (type_item 104 | (type_identifier) 105 | (generic_type 106 | (type_identifier) 107 | (type_arguments 108 | (lifetime 109 | (identifier)) 110 | (type_identifier)))) 111 | (type_item 112 | (type_identifier) 113 | (generic_type 114 | (type_identifier) 115 | (type_arguments 116 | (type_binding 117 | (type_identifier) 118 | (type_identifier)))))) 119 | 120 | ================================================================================ 121 | Scoped types 122 | ================================================================================ 123 | 124 | type A = B::C; 125 | type D = E::F::G; 126 | type H = I::J; 127 | type L = M::O; 128 | 129 | -------------------------------------------------------------------------------- 130 | 131 | (source_file 132 | (type_item 133 | (type_identifier) 134 | (scoped_type_identifier 135 | (identifier) 136 | (type_identifier))) 137 | (type_item 138 | (type_identifier) 139 | (scoped_type_identifier 140 | (scoped_identifier 141 | (identifier) 142 | (identifier)) 143 | (type_identifier))) 144 | (type_item 145 | (type_identifier) 146 | (generic_type 147 | (scoped_type_identifier 148 | (identifier) 149 | (type_identifier)) 150 | (type_arguments 151 | (type_identifier)))) 152 | (type_item 153 | (type_identifier) 154 | (scoped_type_identifier 155 | (generic_type 156 | (type_identifier) 157 | (type_arguments 158 | (type_identifier))) 159 | (type_identifier)))) 160 | 161 | ================================================================================ 162 | Array types 163 | ================================================================================ 164 | 165 | type A = [B; 4]; 166 | type C = &[D]; 167 | 168 | -------------------------------------------------------------------------------- 169 | 170 | (source_file 171 | (type_item 172 | (type_identifier) 173 | (array_type 174 | (type_identifier) 175 | (integer_literal))) 176 | (type_item 177 | (type_identifier) 178 | (reference_type 179 | (array_type 180 | (type_identifier))))) 181 | 182 | ================================================================================ 183 | Function types 184 | ================================================================================ 185 | 186 | fn high_order1(value: i32, f: fn(i32)) -> i32 {} 187 | 188 | fn high_order2(value: i32, f: fn(i32) -> i32) -> i32 { 189 | f(value) 190 | } 191 | 192 | fn high_order3(value: i32, f: &FnOnce(i32) -> i32) -> i32 { 193 | f(value) 194 | } 195 | 196 | type F = for<'a, 'b> fn(x: &'a A, y: &'a mut B<'i, 't>,) -> C; 197 | 198 | -------------------------------------------------------------------------------- 199 | 200 | (source_file 201 | (function_item 202 | (identifier) 203 | (parameters 204 | (parameter 205 | (identifier) 206 | (primitive_type)) 207 | (parameter 208 | (identifier) 209 | (function_type 210 | (parameters 211 | (primitive_type))))) 212 | (primitive_type) 213 | (block)) 214 | (function_item 215 | (identifier) 216 | (parameters 217 | (parameter 218 | (identifier) 219 | (primitive_type)) 220 | (parameter 221 | (identifier) 222 | (function_type 223 | (parameters 224 | (primitive_type)) 225 | (primitive_type)))) 226 | (primitive_type) 227 | (block 228 | (call_expression 229 | (identifier) 230 | (arguments 231 | (identifier))))) 232 | (function_item 233 | (identifier) 234 | (parameters 235 | (parameter 236 | (identifier) 237 | (primitive_type)) 238 | (parameter 239 | (identifier) 240 | (reference_type 241 | (function_type 242 | (type_identifier) 243 | (parameters 244 | (primitive_type)) 245 | (primitive_type))))) 246 | (primitive_type) 247 | (block 248 | (call_expression 249 | (identifier) 250 | (arguments 251 | (identifier))))) 252 | (type_item 253 | (type_identifier) 254 | (function_type 255 | (for_lifetimes 256 | (lifetime 257 | (identifier)) 258 | (lifetime 259 | (identifier))) 260 | (parameters 261 | (parameter 262 | (identifier) 263 | (reference_type 264 | (lifetime 265 | (identifier)) 266 | (type_identifier))) 267 | (parameter 268 | (identifier) 269 | (reference_type 270 | (lifetime 271 | (identifier)) 272 | (mutable_specifier) 273 | (generic_type 274 | (type_identifier) 275 | (type_arguments 276 | (lifetime 277 | (identifier)) 278 | (lifetime 279 | (identifier))))))) 280 | (type_identifier)))) 281 | 282 | ================================================================================ 283 | Unsafe and extern function types 284 | ================================================================================ 285 | 286 | type a = extern "C" fn(*mut c_void); 287 | type b = unsafe extern "C" fn() -> *mut c_void; 288 | 289 | -------------------------------------------------------------------------------- 290 | 291 | (source_file 292 | (type_item 293 | (type_identifier) 294 | (function_type 295 | (function_modifiers 296 | (extern_modifier 297 | (string_literal 298 | (string_content)))) 299 | (parameters 300 | (pointer_type 301 | (mutable_specifier) 302 | (type_identifier))))) 303 | (type_item 304 | (type_identifier) 305 | (function_type 306 | (function_modifiers 307 | (extern_modifier 308 | (string_literal 309 | (string_content)))) 310 | (parameters) 311 | (pointer_type 312 | (mutable_specifier) 313 | (type_identifier))))) 314 | 315 | ================================================================================ 316 | Trait objects 317 | ================================================================================ 318 | 319 | type a = Box; 320 | type b = Rc; 321 | type c = A<&dyn Fn(&B) -> C>; 322 | 323 | -------------------------------------------------------------------------------- 324 | 325 | (source_file 326 | (type_item 327 | (type_identifier) 328 | (generic_type 329 | (type_identifier) 330 | (type_arguments 331 | (bounded_type 332 | (type_identifier) 333 | (lifetime 334 | (identifier)))))) 335 | (type_item 336 | (type_identifier) 337 | (generic_type 338 | (type_identifier) 339 | (type_arguments 340 | (dynamic_type 341 | (type_identifier))))) 342 | (type_item 343 | (type_identifier) 344 | (generic_type 345 | (type_identifier) 346 | (type_arguments 347 | (reference_type 348 | (dynamic_type 349 | (function_type 350 | (type_identifier) 351 | (parameters 352 | (reference_type 353 | (type_identifier))) 354 | (type_identifier)))))))) 355 | 356 | ================================================================================ 357 | Type cast expressions with generics 358 | ================================================================================ 359 | 360 | a as B; 361 | d as *mut E<::G>; 362 | 363 | -------------------------------------------------------------------------------- 364 | 365 | (source_file 366 | (expression_statement 367 | (type_cast_expression 368 | (identifier) 369 | (generic_type 370 | (type_identifier) 371 | (type_arguments 372 | (type_identifier))))) 373 | (expression_statement 374 | (type_cast_expression 375 | (identifier) 376 | (pointer_type 377 | (mutable_specifier) 378 | (generic_type 379 | (type_identifier) 380 | (type_arguments 381 | (scoped_type_identifier 382 | (bracketed_type 383 | (qualified_type 384 | (type_identifier) 385 | (type_identifier))) 386 | (type_identifier)))))))) 387 | -------------------------------------------------------------------------------- /tree-sitter.json: -------------------------------------------------------------------------------- 1 | { 2 | "grammars": [ 3 | { 4 | "name": "rust", 5 | "camelcase": "Rust", 6 | "scope": "source.rust", 7 | "path": ".", 8 | "file-types": [ 9 | "rs" 10 | ], 11 | "highlights": [ 12 | "queries/highlights.scm" 13 | ], 14 | "injections": [ 15 | "queries/injections.scm" 16 | ], 17 | "tags": [ 18 | "queries/tags.scm" 19 | ], 20 | "injection-regex": "rust" 21 | } 22 | ], 23 | "metadata": { 24 | "version": "0.24.0", 25 | "license": "MIT", 26 | "description": "Rust grammar for tree-sitter", 27 | "authors": [ 28 | { 29 | "name": "Maxim Sokolov", 30 | "email": "maxim0xff@gmail.com" 31 | }, 32 | { 33 | "name": "Max Brunsfeld", 34 | "email": "maxbrunsfeld@gmail.com" 35 | }, 36 | { 37 | "name": "Amaan Qureshi", 38 | "email": "amaanq12@gmail.com" 39 | } 40 | ], 41 | "links": { 42 | "repository": "https://github.com/tree-sitter/tree-sitter-rust" 43 | } 44 | }, 45 | "bindings": { 46 | "c": true, 47 | "go": true, 48 | "node": true, 49 | "python": true, 50 | "rust": true, 51 | "swift": true 52 | } 53 | } 54 | --------------------------------------------------------------------------------