├── .editorconfig ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── dependabot.yml └── workflows │ ├── ci.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-c.pc.in │ └── tree_sitter │ │ └── tree-sitter-c.h ├── go │ ├── binding.go │ └── binding_test.go ├── node │ ├── binding.cc │ ├── binding_test.js │ ├── index.d.ts │ └── index.js ├── python │ ├── tests │ │ └── test_binding.py │ └── tree_sitter_c │ │ ├── __init__.py │ │ ├── __init__.pyi │ │ ├── binding.c │ │ └── py.typed ├── rust │ ├── build.rs │ └── lib.rs └── swift │ ├── TreeSitterC │ └── c.h │ └── TreeSitterCTests │ └── TreeSitterCTests.swift ├── eslint.config.mjs ├── examples ├── cluster.c ├── malloc.c └── parser.c ├── go.mod ├── go.sum ├── grammar.js ├── package-lock.json ├── package.json ├── pyproject.toml ├── queries ├── highlights.scm └── tags.scm ├── setup.py ├── src ├── grammar.json ├── node-types.json ├── parser.c └── tree_sitter │ ├── alloc.h │ ├── array.h │ └── parser.h ├── test ├── corpus │ ├── ambiguities.txt │ ├── crlf.txt │ ├── declarations.txt │ ├── expressions.txt │ ├── microsoft.txt │ ├── preprocessor.txt │ ├── statements.txt │ └── types.txt └── highlight │ ├── keywords.c │ └── names.c └── 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 | 39 | # Zig bindings 40 | build.zig linguist-generated 41 | build.zig.zon linguist-generated 42 | -------------------------------------------------------------------------------- /.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-c/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-c 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 | void foo() { 55 | // Code that fails to parse, or causes an error 56 | } 57 | render: C 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 C spec 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 C feature, please include a link to the relevant **official** C 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 | pull_request: 7 | branches: [master] 8 | 9 | concurrency: 10 | group: ${{github.workflow}}-${{github.ref}} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | test: 15 | name: Test parser 16 | runs-on: ${{matrix.os}} 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | os: [ubuntu-latest, windows-latest, macos-14] 21 | steps: 22 | - name: Checkout repository 23 | uses: actions/checkout@v4 24 | - name: Set up tree-sitter 25 | uses: tree-sitter/setup-action/cli@v2 26 | - name: Run tests 27 | uses: tree-sitter/parser-test-action@v2 28 | with: 29 | test-rust: true 30 | # test-node: true 31 | # test-python: true 32 | # test-go: true 33 | # test-swift: true 34 | - name: Parse examples 35 | uses: tree-sitter/parse-action@v4 36 | with: 37 | files: examples/* 38 | -------------------------------------------------------------------------------- /.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 | *.exp 29 | *.lib 30 | 31 | # Zig artifacts 32 | .zig-cache/ 33 | zig-cache/ 34 | zig-out/ 35 | 36 | # Example dirs 37 | /examples/*/ 38 | 39 | # Grammar volatiles 40 | *.wasm 41 | *.obj 42 | *.o 43 | 44 | # Archives 45 | *.tar.gz 46 | *.tgz 47 | *.zip 48 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | project(tree-sitter-c 4 | VERSION "0.24.1" 5 | DESCRIPTION "C grammar for tree-sitter" 6 | HOMEPAGE_URL "https://github.com/tree-sitter/tree-sitter-c" 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-c src/parser.c) 28 | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/scanner.c) 29 | target_sources(tree-sitter-c PRIVATE src/scanner.c) 30 | endif() 31 | target_include_directories(tree-sitter-c 32 | PRIVATE src 33 | INTERFACE $ 34 | $) 35 | 36 | 37 | target_compile_definitions(tree-sitter-c PRIVATE 38 | $<$:TREE_SITTER_REUSE_ALLOCATOR> 39 | $<$:TREE_SITTER_DEBUG>) 40 | 41 | set_target_properties(tree-sitter-c 42 | PROPERTIES 43 | C_STANDARD 11 44 | POSITION_INDEPENDENT_CODE ON 45 | SOVERSION "${TREE_SITTER_ABI_VERSION}.${PROJECT_VERSION_MAJOR}" 46 | DEFINE_SYMBOL "") 47 | 48 | configure_file(bindings/c/tree-sitter-c.pc.in 49 | "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-c.pc" @ONLY) 50 | 51 | include(GNUInstallDirs) 52 | 53 | install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bindings/c/tree_sitter" 54 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" 55 | FILES_MATCHING PATTERN "*.h") 56 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-c.pc" 57 | DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig") 58 | install(TARGETS tree-sitter-c 59 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") 60 | 61 | add_custom_target(ts-test "${TREE_SITTER_CLI}" test 62 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 63 | COMMENT "tree-sitter test") 64 | -------------------------------------------------------------------------------- /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.24" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "16595d3be041c03b09d08d0858631facccee9221e579704070e6e9e4915d3bc7" 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.3" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" 34 | 35 | [[package]] 36 | name = "indexmap" 37 | version = "2.9.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 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.95" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 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.101" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" 160 | dependencies = [ 161 | "proc-macro2", 162 | "quote", 163 | "unicode-ident", 164 | ] 165 | 166 | [[package]] 167 | name = "tree-sitter" 168 | version = "0.25.4" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "69aff09fea9a41fb061ae6b206cb87cac1b8db07df31be3ba271fbc26760f213" 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-c" 182 | version = "0.24.1" 183 | dependencies = [ 184 | "cc", 185 | "tree-sitter", 186 | "tree-sitter-language", 187 | ] 188 | 189 | [[package]] 190 | name = "tree-sitter-language" 191 | version = "0.1.5" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "c4013970217383f67b18aef68f6fb2e8d409bc5755227092d32efb0422ba24b8" 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-c" 3 | description = "C grammar for tree-sitter" 4 | version = "0.24.1" 5 | authors = [ 6 | "Max Brunsfeld ", 7 | "Amaan Qureshi ", 8 | ] 9 | license = "MIT" 10 | readme = "README.md" 11 | keywords = ["incremental", "parsing", "tree-sitter", "c"] 12 | categories = ["parsing", "text-editors"] 13 | repository = "https://github.com/tree-sitter/tree-sitter-c" 14 | edition = "2021" 15 | autoexamples = false 16 | 17 | build = "bindings/rust/build.rs" 18 | include = ["LICENSE", "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.2" 28 | 29 | [dev-dependencies] 30 | tree-sitter = "0.25.4" 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Max Brunsfeld 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-c 6 | HOMEPAGE_URL := https://github.com/tree-sitter/tree-sitter-c 7 | VERSION := 0.24.1 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/tree_sitter/$(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: "TreeSitterC", 6 | products: [ 7 | .library(name: "TreeSitterC", targets: ["TreeSitterC"]), 8 | ], 9 | dependencies: [ 10 | .package(url: "https://github.com/tree-sitter/swift-tree-sitter", from: "0.8.0"), 11 | ], 12 | targets: [ 13 | .target( 14 | name: "TreeSitterC", 15 | dependencies: [], 16 | path: ".", 17 | sources: [ 18 | "src/parser.c", 19 | ], 20 | resources: [ 21 | .copy("queries") 22 | ], 23 | publicHeadersPath: "bindings/swift", 24 | cSettings: [.headerSearchPath("src")] 25 | ), 26 | .testTarget( 27 | name: "TreeSitterCTests", 28 | dependencies: [ 29 | "SwiftTreeSitter", 30 | "TreeSitterC", 31 | ], 32 | path: "bindings/swift/TreeSitterCTests" 33 | ) 34 | ], 35 | cLanguageStandard: .c11 36 | ) 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tree-sitter-c 2 | 3 | [![CI][ci]](https://github.com/tree-sitter/tree-sitter-c/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-c) 7 | [![npm][npm]](https://www.npmjs.com/package/tree-sitter-c) 8 | [![pypi][pypi]](https://pypi.org/project/tree-sitter-c) 9 | 10 | C grammar for [tree-sitter](https://github.com/tree-sitter/tree-sitter). 11 | Adapted from [this C99 grammar](http://slps.github.io/zoo/c/iso-9899-tc3.html). 12 | 13 | [ci]: https://img.shields.io/github/actions/workflow/status/tree-sitter/tree-sitter-c/ci.yml?logo=github&label=CI 14 | [discord]: https://img.shields.io/discord/1063097320771698699?logo=discord&label=discord 15 | [matrix]: https://img.shields.io/matrix/tree-sitter-chat%3Amatrix.org?logo=matrix&label=matrix 16 | [npm]: https://img.shields.io/npm/v/tree-sitter-c?logo=npm 17 | [crates]: https://img.shields.io/crates/v/tree-sitter-c?logo=rust 18 | [pypi]: https://img.shields.io/pypi/v/tree-sitter-c?logo=pypi&logoColor=ffd242 19 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_c_binding", 5 | "dependencies": [ 6 | " 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | extern "C" TSLanguage *tree_sitter_c(); 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, "c"); 14 | auto language = Napi::External::New(env, tree_sitter_c()); 15 | language.TypeTag(&LANGUAGE_TYPE_TAG); 16 | exports["language"] = language; 17 | return exports; 18 | } 19 | 20 | NODE_API_MODULE(tree_sitter_c_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-c.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_c 4 | 5 | 6 | class TestLanguage(TestCase): 7 | def test_can_load_grammar(self): 8 | try: 9 | tree_sitter.Language(tree_sitter_c.language()) 10 | except Exception: 11 | self.fail("Error loading C grammar") 12 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_c/__init__.py: -------------------------------------------------------------------------------- 1 | """C 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 == "TAGS_QUERY": 18 | return _get_query("TAGS_QUERY", "tags.scm") 19 | 20 | raise AttributeError(f"module {__name__!r} has no attribute {name!r}") 21 | 22 | 23 | __all__ = [ 24 | "language", 25 | "HIGHLIGHTS_QUERY", 26 | "TAGS_QUERY", 27 | ] 28 | 29 | 30 | def __dir__(): 31 | return sorted(__all__ + [ 32 | "__all__", "__builtins__", "__cached__", "__doc__", "__file__", 33 | "__loader__", "__name__", "__package__", "__path__", "__spec__", 34 | ]) 35 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_c/__init__.pyi: -------------------------------------------------------------------------------- 1 | from typing import Final 2 | 3 | HIGHLIGHTS_QUERY: Final[str] 4 | TAGS_QUERY: Final[str] 5 | 6 | def language() -> object: ... 7 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_c/binding.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | TSLanguage *tree_sitter_c(void); 6 | 7 | static PyObject* _binding_language(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { 8 | return PyCapsule_New(tree_sitter_c(), "tree_sitter.Language", NULL); 9 | } 10 | 11 | static struct PyModuleDef_Slot slots[] = { 12 | #ifdef Py_GIL_DISABLED 13 | {Py_mod_gil, Py_MOD_GIL_NOT_USED}, 14 | #endif 15 | {0, NULL} 16 | }; 17 | 18 | static PyMethodDef methods[] = { 19 | {"language", _binding_language, METH_NOARGS, 20 | "Get the tree-sitter language for this grammar."}, 21 | {NULL, NULL, 0, NULL} 22 | }; 23 | 24 | static struct PyModuleDef module = { 25 | .m_base = PyModuleDef_HEAD_INIT, 26 | .m_name = "_binding", 27 | .m_doc = NULL, 28 | .m_size = 0, 29 | .m_methods = methods, 30 | .m_slots = slots, 31 | }; 32 | 33 | PyMODINIT_FUNC PyInit__binding(void) { 34 | return PyModuleDef_Init(&module); 35 | } 36 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_c/py.typed: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tree-sitter/tree-sitter-c/7fa1be1b694b6e763686793d97da01f36a0e5c12/bindings/python/tree_sitter_c/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 | c_config.compile("tree-sitter-c"); 15 | } 16 | -------------------------------------------------------------------------------- /bindings/rust/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate provides C language support for the [tree-sitter][] parsing library. 2 | //! 3 | //! Typically, you will use the [language][language func] function 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 | //! int double(int x) { 11 | //! return x * 2; 12 | //! } 13 | //! "#; 14 | //! let mut parser = Parser::new(); 15 | //! let language = tree_sitter_c::LANGUAGE; 16 | //! parser 17 | //! .set_language(&language.into()) 18 | //! .expect("Error loading C parser"); 19 | //! let tree = parser.parse(code, None).unwrap(); 20 | //! assert!(!tree.root_node().has_error()); 21 | //! ``` 22 | //! 23 | //! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html 24 | //! [language func]: fn.language.html 25 | //! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html 26 | //! [tree-sitter]: https://tree-sitter.github.io/ 27 | 28 | use tree_sitter_language::LanguageFn; 29 | 30 | extern "C" { 31 | fn tree_sitter_c() -> *const (); 32 | } 33 | 34 | /// The tree-sitter [`LanguageFn`] for this grammar. 35 | pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_c) }; 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 HIGHLIGHT_QUERY: &str = include_str!("../../queries/highlights.scm"); 44 | 45 | /// The symbol tagging query for this language. 46 | pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm"); 47 | 48 | #[cfg(test)] 49 | mod tests { 50 | #[test] 51 | fn test_can_load_grammar() { 52 | let mut parser = tree_sitter::Parser::new(); 53 | parser 54 | .set_language(&super::LANGUAGE.into()) 55 | .expect("Error loading C parser"); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /bindings/swift/TreeSitterC/c.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_C_H_ 2 | #define TREE_SITTER_C_H_ 3 | 4 | typedef struct TSLanguage TSLanguage; 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | const TSLanguage *tree_sitter_c(void); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif // TREE_SITTER_C_H_ 17 | -------------------------------------------------------------------------------- /bindings/swift/TreeSitterCTests/TreeSitterCTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import SwiftTreeSitter 3 | import TreeSitterC 4 | 5 | final class TreeSitterCTests: XCTestCase { 6 | func testCanLoadGrammar() throws { 7 | let parser = Parser() 8 | let language = Language(language: tree_sitter_c()) 9 | XCTAssertNoThrow(try parser.setLanguage(language), 10 | "Error loading C grammar") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import treesitter from 'eslint-config-treesitter'; 2 | 3 | export default [ 4 | ...treesitter, 5 | ]; 6 | -------------------------------------------------------------------------------- /examples/malloc.c: -------------------------------------------------------------------------------- 1 | #define _GNU_SOURCE 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "libc.h" 9 | #include "atomic.h" 10 | #include "pthread_impl.h" 11 | 12 | #if defined(__GNUC__) && defined(__PIC__) 13 | #define inline inline __attribute__((always_inline)) 14 | #endif 15 | 16 | void *__mmap(void *, size_t, int, int, int, off_t); 17 | int __munmap(void *, size_t); 18 | void *__mremap(void *, size_t, size_t, int, ...); 19 | int __madvise(void *, size_t, int); 20 | 21 | struct chunk { 22 | size_t psize, csize; 23 | struct chunk *next, *prev; 24 | }; 25 | 26 | struct bin { 27 | volatile int lock[2]; 28 | struct chunk *head; 29 | struct chunk *tail; 30 | }; 31 | 32 | static struct { 33 | volatile uint64_t binmap; 34 | struct bin bins[64]; 35 | volatile int free_lock[2]; 36 | } mal; 37 | 38 | 39 | #define SIZE_ALIGN (4*sizeof(size_t)) 40 | #define SIZE_MASK (-SIZE_ALIGN) 41 | #define OVERHEAD (2*sizeof(size_t)) 42 | #define MMAP_THRESHOLD (0x1c00*SIZE_ALIGN) 43 | #define DONTCARE 16 44 | #define RECLAIM 163840 45 | 46 | #define CHUNK_SIZE(c) ((c)->csize & -2) 47 | #define CHUNK_PSIZE(c) ((c)->psize & -2) 48 | #define PREV_CHUNK(c) ((struct chunk *)((char *)(c) - CHUNK_PSIZE(c))) 49 | #define NEXT_CHUNK(c) ((struct chunk *)((char *)(c) + CHUNK_SIZE(c))) 50 | #define MEM_TO_CHUNK(p) (struct chunk *)((char *)(p) - OVERHEAD) 51 | #define CHUNK_TO_MEM(c) (void *)((char *)(c) + OVERHEAD) 52 | #define BIN_TO_CHUNK(i) (MEM_TO_CHUNK(&mal.bins[i].head)) 53 | 54 | #define C_INUSE ((size_t)1) 55 | 56 | #define IS_MMAPPED(c) !((c)->csize & (C_INUSE)) 57 | 58 | 59 | /* Synchronization tools */ 60 | 61 | static inline void lock(volatile int *lk) 62 | { 63 | if (libc.threads_minus_1) 64 | while(a_swap(lk, 1)) __wait(lk, lk+1, 1, 1); 65 | } 66 | 67 | static inline void unlock(volatile int *lk) 68 | { 69 | if (lk[0]) { 70 | a_store(lk, 0); 71 | if (lk[1]) __wake(lk, 1, 1); 72 | } 73 | } 74 | 75 | static inline void lock_bin(int i) 76 | { 77 | lock(mal.bins[i].lock); 78 | if (!mal.bins[i].head) 79 | mal.bins[i].head = mal.bins[i].tail = BIN_TO_CHUNK(i); 80 | } 81 | 82 | static inline void unlock_bin(int i) 83 | { 84 | unlock(mal.bins[i].lock); 85 | } 86 | 87 | static int first_set(uint64_t x) 88 | { 89 | #if 1 90 | return a_ctz_64(x); 91 | #else 92 | static const char debruijn64[64] = { 93 | 0, 1, 2, 53, 3, 7, 54, 27, 4, 38, 41, 8, 34, 55, 48, 28, 94 | 62, 5, 39, 46, 44, 42, 22, 9, 24, 35, 59, 56, 49, 18, 29, 11, 95 | 63, 52, 6, 26, 37, 40, 33, 47, 61, 45, 43, 21, 23, 58, 17, 10, 96 | 51, 25, 36, 32, 60, 20, 57, 16, 50, 31, 19, 15, 30, 14, 13, 12 97 | }; 98 | static const char debruijn32[32] = { 99 | 0, 1, 23, 2, 29, 24, 19, 3, 30, 27, 25, 11, 20, 8, 4, 13, 100 | 31, 22, 28, 18, 26, 10, 7, 12, 21, 17, 9, 6, 16, 5, 15, 14 101 | }; 102 | if (sizeof(long) < 8) { 103 | uint32_t y = x; 104 | if (!y) { 105 | y = x>>32; 106 | return 32 + debruijn32[(y&-y)*0x076be629 >> 27]; 107 | } 108 | return debruijn32[(y&-y)*0x076be629 >> 27]; 109 | } 110 | return debruijn64[(x&-x)*0x022fdd63cc95386dull >> 58]; 111 | #endif 112 | } 113 | 114 | static const unsigned char bin_tab[60] = { 115 | 32,33,34,35,36,36,37,37,38,38,39,39, 116 | 40,40,40,40,41,41,41,41,42,42,42,42,43,43,43,43, 117 | 44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45, 118 | 46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47, 119 | }; 120 | 121 | static int bin_index(size_t x) 122 | { 123 | x = x / SIZE_ALIGN - 1; 124 | if (x <= 32) return x; 125 | if (x < 512) return bin_tab[x/8-4]; 126 | if (x > 0x1c00) return 63; 127 | return bin_tab[x/128-4] + 16; 128 | } 129 | 130 | static int bin_index_up(size_t x) 131 | { 132 | x = x / SIZE_ALIGN - 1; 133 | if (x <= 32) return x; 134 | x--; 135 | if (x < 512) return bin_tab[x/8-4] + 1; 136 | return bin_tab[x/128-4] + 17; 137 | } 138 | 139 | #if 0 140 | void __dump_heap(int x) 141 | { 142 | struct chunk *c; 143 | int i; 144 | for (c = (void *)mal.heap; CHUNK_SIZE(c); c = NEXT_CHUNK(c)) 145 | fprintf(stderr, "base %p size %zu (%d) flags %d/%d\n", 146 | c, CHUNK_SIZE(c), bin_index(CHUNK_SIZE(c)), 147 | c->csize & 15, 148 | NEXT_CHUNK(c)->psize & 15); 149 | for (i=0; i<64; i++) { 150 | if (mal.bins[i].head != BIN_TO_CHUNK(i) && mal.bins[i].head) { 151 | fprintf(stderr, "bin %d: %p\n", i, mal.bins[i].head); 152 | if (!(mal.binmap & 1ULL<psize = 0 | C_INUSE; 190 | } 191 | 192 | /* Record new heap end and fill in footer. */ 193 | end = (char *)p + n; 194 | w = MEM_TO_CHUNK(end); 195 | w->psize = n | C_INUSE; 196 | w->csize = 0 | C_INUSE; 197 | 198 | /* Fill in header, which may be new or may be replacing a 199 | * zero-size sentinel header at the old end-of-heap. */ 200 | w = MEM_TO_CHUNK(p); 201 | w->csize = n | C_INUSE; 202 | 203 | unlock(heap_lock); 204 | 205 | return w; 206 | } 207 | 208 | static int adjust_size(size_t *n) 209 | { 210 | /* Result of pointer difference must fit in ptrdiff_t. */ 211 | if (*n-1 > PTRDIFF_MAX - SIZE_ALIGN - PAGE_SIZE) { 212 | if (*n) { 213 | errno = ENOMEM; 214 | return -1; 215 | } else { 216 | *n = SIZE_ALIGN; 217 | return 0; 218 | } 219 | } 220 | *n = (*n + OVERHEAD + SIZE_ALIGN - 1) & SIZE_MASK; 221 | return 0; 222 | } 223 | 224 | static void unbin(struct chunk *c, int i) 225 | { 226 | if (c->prev == c->next) 227 | a_and_64(&mal.binmap, ~(1ULL<prev->next = c->next; 229 | c->next->prev = c->prev; 230 | c->csize |= C_INUSE; 231 | NEXT_CHUNK(c)->psize |= C_INUSE; 232 | } 233 | 234 | static int alloc_fwd(struct chunk *c) 235 | { 236 | int i; 237 | size_t k; 238 | while (!((k=c->csize) & C_INUSE)) { 239 | i = bin_index(k); 240 | lock_bin(i); 241 | if (c->csize == k) { 242 | unbin(c, i); 243 | unlock_bin(i); 244 | return 1; 245 | } 246 | unlock_bin(i); 247 | } 248 | return 0; 249 | } 250 | 251 | static int alloc_rev(struct chunk *c) 252 | { 253 | int i; 254 | size_t k; 255 | while (!((k=c->psize) & C_INUSE)) { 256 | i = bin_index(k); 257 | lock_bin(i); 258 | if (c->psize == k) { 259 | unbin(PREV_CHUNK(c), i); 260 | unlock_bin(i); 261 | return 1; 262 | } 263 | unlock_bin(i); 264 | } 265 | return 0; 266 | } 267 | 268 | 269 | /* pretrim - trims a chunk _prior_ to removing it from its bin. 270 | * Must be called with i as the ideal bin for size n, j the bin 271 | * for the _free_ chunk self, and bin j locked. */ 272 | static int pretrim(struct chunk *self, size_t n, int i, int j) 273 | { 274 | size_t n1; 275 | struct chunk *next, *split; 276 | 277 | /* We cannot pretrim if it would require re-binning. */ 278 | if (j < 40) return 0; 279 | if (j < i+3) { 280 | if (j != 63) return 0; 281 | n1 = CHUNK_SIZE(self); 282 | if (n1-n <= MMAP_THRESHOLD) return 0; 283 | } else { 284 | n1 = CHUNK_SIZE(self); 285 | } 286 | if (bin_index(n1-n) != j) return 0; 287 | 288 | next = NEXT_CHUNK(self); 289 | split = (void *)((char *)self + n); 290 | 291 | split->prev = self->prev; 292 | split->next = self->next; 293 | split->prev->next = split; 294 | split->next->prev = split; 295 | split->psize = n | C_INUSE; 296 | split->csize = n1-n; 297 | next->psize = n1-n; 298 | self->csize = n | C_INUSE; 299 | return 1; 300 | } 301 | 302 | static void trim(struct chunk *self, size_t n) 303 | { 304 | size_t n1 = CHUNK_SIZE(self); 305 | struct chunk *next, *split; 306 | 307 | if (n >= n1 - DONTCARE) return; 308 | 309 | next = NEXT_CHUNK(self); 310 | split = (void *)((char *)self + n); 311 | 312 | split->psize = n | C_INUSE; 313 | split->csize = n1-n | C_INUSE; 314 | next->psize = n1-n | C_INUSE; 315 | self->csize = n | C_INUSE; 316 | 317 | free(CHUNK_TO_MEM(split)); 318 | } 319 | 320 | void *malloc(size_t n) 321 | { 322 | struct chunk *c; 323 | int i, j; 324 | 325 | if (adjust_size(&n) < 0) return 0; 326 | 327 | if (n > MMAP_THRESHOLD) { 328 | size_t len = n + OVERHEAD + PAGE_SIZE - 1 & -PAGE_SIZE; 329 | char *base = __mmap(0, len, PROT_READ|PROT_WRITE, 330 | MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); 331 | if (base == (void *)-1) return 0; 332 | c = (void *)(base + SIZE_ALIGN - OVERHEAD); 333 | c->csize = len - (SIZE_ALIGN - OVERHEAD); 334 | c->psize = SIZE_ALIGN - OVERHEAD; 335 | return CHUNK_TO_MEM(c); 336 | } 337 | 338 | i = bin_index_up(n); 339 | for (;;) { 340 | uint64_t mask = mal.binmap & -(1ULL<psize = c->csize = 348 | x->csize + CHUNK_SIZE(c); 349 | } 350 | break; 351 | } 352 | j = first_set(mask); 353 | lock_bin(j); 354 | c = mal.bins[j].head; 355 | if (c != BIN_TO_CHUNK(j)) { 356 | if (!pretrim(c, n, i, j)) unbin(c, j); 357 | unlock_bin(j); 358 | break; 359 | } 360 | unlock_bin(j); 361 | } 362 | 363 | /* Now patch up in case we over-allocated */ 364 | trim(c, n); 365 | 366 | return CHUNK_TO_MEM(c); 367 | } 368 | 369 | void *__malloc0(size_t n) 370 | { 371 | void *p = malloc(n); 372 | if (p && !IS_MMAPPED(MEM_TO_CHUNK(p))) { 373 | size_t *z; 374 | n = (n + sizeof *z - 1)/sizeof *z; 375 | for (z=p; n; n--, z++) if (*z) *z=0; 376 | } 377 | return p; 378 | } 379 | 380 | void *realloc(void *p, size_t n) 381 | { 382 | struct chunk *self, *next; 383 | size_t n0, n1; 384 | void *new; 385 | 386 | if (!p) return malloc(n); 387 | 388 | if (adjust_size(&n) < 0) return 0; 389 | 390 | self = MEM_TO_CHUNK(p); 391 | n1 = n0 = CHUNK_SIZE(self); 392 | 393 | if (IS_MMAPPED(self)) { 394 | size_t extra = self->psize; 395 | char *base = (char *)self - extra; 396 | size_t oldlen = n0 + extra; 397 | size_t newlen = n + extra; 398 | /* Crash on realloc of freed chunk */ 399 | if (extra & 1) a_crash(); 400 | if (newlen < PAGE_SIZE && (new = malloc(n))) { 401 | memcpy(new, p, n-OVERHEAD); 402 | free(p); 403 | return new; 404 | } 405 | newlen = (newlen + PAGE_SIZE-1) & -PAGE_SIZE; 406 | if (oldlen == newlen) return p; 407 | base = __mremap(base, oldlen, newlen, MREMAP_MAYMOVE); 408 | if (base == (void *)-1) 409 | goto copy_realloc; 410 | self = (void *)(base + extra); 411 | self->csize = newlen - extra; 412 | return CHUNK_TO_MEM(self); 413 | } 414 | 415 | next = NEXT_CHUNK(self); 416 | 417 | /* Crash on corrupted footer (likely from buffer overflow) */ 418 | if (next->psize != self->csize) a_crash(); 419 | 420 | /* Merge adjacent chunks if we need more space. This is not 421 | * a waste of time even if we fail to get enough space, because our 422 | * subsequent call to free would otherwise have to do the merge. */ 423 | if (n > n1 && alloc_fwd(next)) { 424 | n1 += CHUNK_SIZE(next); 425 | next = NEXT_CHUNK(next); 426 | } 427 | /* FIXME: find what's wrong here and reenable it..? */ 428 | if (0 && n > n1 && alloc_rev(self)) { 429 | self = PREV_CHUNK(self); 430 | n1 += CHUNK_SIZE(self); 431 | } 432 | self->csize = n1 | C_INUSE; 433 | next->psize = n1 | C_INUSE; 434 | 435 | /* If we got enough space, split off the excess and return */ 436 | if (n <= n1) { 437 | //memmove(CHUNK_TO_MEM(self), p, n0-OVERHEAD); 438 | trim(self, n); 439 | return CHUNK_TO_MEM(self); 440 | } 441 | 442 | copy_realloc: 443 | /* As a last resort, allocate a new chunk and copy to it. */ 444 | new = malloc(n-OVERHEAD); 445 | if (!new) return 0; 446 | memcpy(new, p, n0-OVERHEAD); 447 | free(CHUNK_TO_MEM(self)); 448 | return new; 449 | } 450 | 451 | void free(void *p) 452 | { 453 | struct chunk *self = MEM_TO_CHUNK(p); 454 | struct chunk *next; 455 | size_t final_size, new_size, size; 456 | int reclaim=0; 457 | int i; 458 | 459 | if (!p) return; 460 | 461 | if (IS_MMAPPED(self)) { 462 | size_t extra = self->psize; 463 | char *base = (char *)self - extra; 464 | size_t len = CHUNK_SIZE(self) + extra; 465 | /* Crash on double free */ 466 | if (extra & 1) a_crash(); 467 | __munmap(base, len); 468 | return; 469 | } 470 | 471 | final_size = new_size = CHUNK_SIZE(self); 472 | next = NEXT_CHUNK(self); 473 | 474 | /* Crash on corrupted footer (likely from buffer overflow) */ 475 | if (next->psize != self->csize) a_crash(); 476 | 477 | for (;;) { 478 | if (self->psize & next->csize & C_INUSE) { 479 | self->csize = final_size | C_INUSE; 480 | next->psize = final_size | C_INUSE; 481 | i = bin_index(final_size); 482 | lock_bin(i); 483 | lock(mal.free_lock); 484 | if (self->psize & next->csize & C_INUSE) 485 | break; 486 | unlock(mal.free_lock); 487 | unlock_bin(i); 488 | } 489 | 490 | if (alloc_rev(self)) { 491 | self = PREV_CHUNK(self); 492 | size = CHUNK_SIZE(self); 493 | final_size += size; 494 | if (new_size+size > RECLAIM && (new_size+size^size) > size) 495 | reclaim = 1; 496 | } 497 | 498 | if (alloc_fwd(next)) { 499 | size = CHUNK_SIZE(next); 500 | final_size += size; 501 | if (new_size+size > RECLAIM && (new_size+size^size) > size) 502 | reclaim = 1; 503 | next = NEXT_CHUNK(next); 504 | } 505 | } 506 | 507 | if (!(mal.binmap & 1ULL<csize = final_size; 511 | next->psize = final_size; 512 | unlock(mal.free_lock); 513 | 514 | self->next = BIN_TO_CHUNK(i); 515 | self->prev = mal.bins[i].tail; 516 | self->next->prev = self; 517 | self->prev->next = self; 518 | 519 | /* Replace middle of large chunks with fresh zero pages */ 520 | if (reclaim) { 521 | uintptr_t a = (uintptr_t)self + SIZE_ALIGN+PAGE_SIZE-1 & -PAGE_SIZE; 522 | uintptr_t b = (uintptr_t)next - SIZE_ALIGN & -PAGE_SIZE; 523 | #if 1 524 | __madvise((void *)a, b-a, MADV_DONTNEED); 525 | #else 526 | __mmap((void *)a, b-a, PROT_READ|PROT_WRITE, 527 | MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0); 528 | #endif 529 | } 530 | 531 | unlock_bin(i); 532 | } 533 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tree-sitter/tree-sitter-c 2 | 3 | go 1.22 4 | 5 | require github.com/tree-sitter/go-tree-sitter v0.24.1 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-cpp v0.22.4-0.20240818224355-b1a4e2b25148 h1:AfFPZwtwGN01BW1jDdqBVqscTwetvMpydqYZz57RSlc= 12 | github.com/tree-sitter/tree-sitter-cpp v0.22.4-0.20240818224355-b1a4e2b25148/go.mod h1:Bh6U3viD57rFXRYIQ+kmiYtr+1Bx0AceypDLJJSyi9s= 13 | github.com/tree-sitter/tree-sitter-embedded-template v0.21.1-0.20240819044651-ffbf64942c33 h1:TwqSV3qLp3tKSqirGLRHnjFk9Tc2oy57LIl+FQ4GjI4= 14 | github.com/tree-sitter/tree-sitter-embedded-template v0.21.1-0.20240819044651-ffbf64942c33/go.mod h1:CvCKCt3v04Ufos1zZnNCelBDeCGRpPucaN8QczoUsN4= 15 | github.com/tree-sitter/tree-sitter-go v0.21.3-0.20240818010209-8c0f0e7a6012 h1:Xvxck3tE5FW7F7bTS97iNM2ADMyCMJztVqn5HYKdJGo= 16 | github.com/tree-sitter/tree-sitter-go v0.21.3-0.20240818010209-8c0f0e7a6012/go.mod h1:T40D0O1cPvUU/+AmiXVXy1cncYQT6wem4Z0g4SfAYvY= 17 | github.com/tree-sitter/tree-sitter-html v0.20.5-0.20240818004741-d11201a263d0 h1:c46K6uh5Dz00zJeU9BfjXdb8I+E4RkUdfnWJpQADXFo= 18 | github.com/tree-sitter/tree-sitter-html v0.20.5-0.20240818004741-d11201a263d0/go.mod h1:hcNt/kOJHcIcuMvouE7LJcYdeFUFbVpBJ6d4wmOA+tU= 19 | github.com/tree-sitter/tree-sitter-java v0.21.1-0.20240824015150-576d8097e495 h1:jrt4qbJVEFs4H93/ITxygHc6u0TGqAkkate7TQ4wFSA= 20 | github.com/tree-sitter/tree-sitter-java v0.21.1-0.20240824015150-576d8097e495/go.mod h1:oyaR7fLnRV0hT9z6qwE9GkaeTom/hTDwK3H2idcOJFc= 21 | github.com/tree-sitter/tree-sitter-javascript v0.21.5-0.20240818005344-15887341e5b5 h1:om4X9AVg3asL8gxNJDcz4e/Wp+VpQj1PY3uJXKr6EOg= 22 | github.com/tree-sitter/tree-sitter-javascript v0.21.5-0.20240818005344-15887341e5b5/go.mod h1:nNqgPoV/h9uYWk6kYEFdEAhNVOacpfpRW5SFmdaP4tU= 23 | github.com/tree-sitter/tree-sitter-json v0.21.1-0.20240818005659-bdd69eb8c8a5 h1:pfV3G3k7NCKqKk8THBmyuh2zA33lgYHS3GVrzRR8ry4= 24 | github.com/tree-sitter/tree-sitter-json v0.21.1-0.20240818005659-bdd69eb8c8a5/go.mod h1:GbMKRjLfk0H+PI7nLi1Sx5lHf5wCpLz9al8tQYSxpEk= 25 | github.com/tree-sitter/tree-sitter-php v0.22.9-0.20240819002312-a552625b56c1 h1:ZXZMDwE+IhUtGug4Brv6NjJWUU3rfkZBKpemf6RY8/g= 26 | github.com/tree-sitter/tree-sitter-php v0.22.9-0.20240819002312-a552625b56c1/go.mod h1:UKCLuYnJ312Mei+3cyTmGOHzn0YAnaPRECgJmHtzrqs= 27 | github.com/tree-sitter/tree-sitter-python v0.21.1-0.20240818005537-55a9b8a4fbfb h1:EXEM82lFM7JjJb6qiKZXkpIDaCcbV2obNn82ghwj9lw= 28 | github.com/tree-sitter/tree-sitter-python v0.21.1-0.20240818005537-55a9b8a4fbfb/go.mod h1:lXCF1nGG5Dr4J3BTS0ObN4xJCCICiSu/b+Xe/VqMV7g= 29 | github.com/tree-sitter/tree-sitter-ruby v0.21.1-0.20240818211811-7dbc1e2d0e2d h1:fcYCvoXdcP1uRQYXqJHRy6Hec+uKScQdKVtMwK9JeCI= 30 | github.com/tree-sitter/tree-sitter-ruby v0.21.1-0.20240818211811-7dbc1e2d0e2d/go.mod h1:T1nShQ4v5AJtozZ8YyAS4uzUtDAJj/iv4YfwXSbUHzg= 31 | github.com/tree-sitter/tree-sitter-rust v0.21.3-0.20240818005432-2b43eafe6447 h1:o9alBu1J/WjrcTKEthYtXmdkDc5OVXD+PqlvnEZ0Lzc= 32 | github.com/tree-sitter/tree-sitter-rust v0.21.3-0.20240818005432-2b43eafe6447/go.mod h1:1Oh95COkkTn6Ezp0vcMbvfhRP5gLeqqljR0BYnBzWvc= 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 | -------------------------------------------------------------------------------- /grammar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file C grammar for tree-sitter 3 | * @author Max Brunsfeld 4 | * @author Amaan Qureshi 5 | * @license MIT 6 | */ 7 | 8 | /// 9 | // @ts-check 10 | 11 | const PREC = { 12 | PAREN_DECLARATOR: -10, 13 | ASSIGNMENT: -2, 14 | CONDITIONAL: -1, 15 | DEFAULT: 0, 16 | LOGICAL_OR: 1, 17 | LOGICAL_AND: 2, 18 | INCLUSIVE_OR: 3, 19 | EXCLUSIVE_OR: 4, 20 | BITWISE_AND: 5, 21 | EQUAL: 6, 22 | RELATIONAL: 7, 23 | OFFSETOF: 8, 24 | SHIFT: 9, 25 | ADD: 10, 26 | MULTIPLY: 11, 27 | CAST: 12, 28 | SIZEOF: 13, 29 | UNARY: 14, 30 | CALL: 15, 31 | FIELD: 16, 32 | SUBSCRIPT: 17, 33 | }; 34 | 35 | module.exports = grammar({ 36 | name: 'c', 37 | 38 | conflicts: $ => [ 39 | [$.type_specifier, $._declarator], 40 | [$.type_specifier, $._declarator, $.macro_type_specifier], 41 | [$.type_specifier, $.expression], 42 | [$.type_specifier, $.expression, $.macro_type_specifier], 43 | [$.type_specifier, $.macro_type_specifier], 44 | [$.type_specifier, $.sized_type_specifier], 45 | [$.sized_type_specifier], 46 | [$.attributed_statement], 47 | [$._declaration_modifiers, $.attributed_statement], 48 | [$.enum_specifier], 49 | [$.type_specifier, $._old_style_parameter_list], 50 | [$.parameter_list, $._old_style_parameter_list], 51 | [$.function_declarator, $._function_declaration_declarator], 52 | [$._block_item, $.statement], 53 | [$._top_level_item, $._top_level_statement], 54 | [$.type_specifier, $._top_level_expression_statement], 55 | [$.type_qualifier, $.extension_expression], 56 | ], 57 | 58 | extras: $ => [ 59 | /\s|\\\r?\n/, 60 | $.comment, 61 | ], 62 | 63 | inline: $ => [ 64 | $._type_identifier, 65 | $._field_identifier, 66 | $._statement_identifier, 67 | $._non_case_statement, 68 | $._assignment_left_expression, 69 | $._expression_not_binary, 70 | ], 71 | 72 | supertypes: $ => [ 73 | $.expression, 74 | $.statement, 75 | $.type_specifier, 76 | $._declarator, 77 | $._field_declarator, 78 | $._type_declarator, 79 | $._abstract_declarator, 80 | ], 81 | 82 | word: $ => $.identifier, 83 | 84 | rules: { 85 | translation_unit: $ => repeat($._top_level_item), 86 | 87 | // Top level items are block items with the exception of the expression statement 88 | _top_level_item: $ => choice( 89 | $.function_definition, 90 | alias($._old_style_function_definition, $.function_definition), 91 | $.linkage_specification, 92 | $.declaration, 93 | $._top_level_statement, 94 | $.attributed_statement, 95 | $.type_definition, 96 | $._empty_declaration, 97 | $.preproc_if, 98 | $.preproc_ifdef, 99 | $.preproc_include, 100 | $.preproc_def, 101 | $.preproc_function_def, 102 | $.preproc_call, 103 | ), 104 | 105 | _block_item: $ => choice( 106 | $.function_definition, 107 | alias($._old_style_function_definition, $.function_definition), 108 | $.linkage_specification, 109 | $.declaration, 110 | $.statement, 111 | $.attributed_statement, 112 | $.type_definition, 113 | $._empty_declaration, 114 | $.preproc_if, 115 | $.preproc_ifdef, 116 | $.preproc_include, 117 | $.preproc_def, 118 | $.preproc_function_def, 119 | $.preproc_call, 120 | ), 121 | 122 | // Preprocesser 123 | 124 | preproc_include: $ => seq( 125 | preprocessor('include'), 126 | field('path', choice( 127 | $.string_literal, 128 | $.system_lib_string, 129 | $.identifier, 130 | alias($.preproc_call_expression, $.call_expression), 131 | )), 132 | token.immediate(/\r?\n/), 133 | ), 134 | 135 | preproc_def: $ => seq( 136 | preprocessor('define'), 137 | field('name', $.identifier), 138 | field('value', optional($.preproc_arg)), 139 | token.immediate(/\r?\n/), 140 | ), 141 | 142 | preproc_function_def: $ => seq( 143 | preprocessor('define'), 144 | field('name', $.identifier), 145 | field('parameters', $.preproc_params), 146 | field('value', optional($.preproc_arg)), 147 | token.immediate(/\r?\n/), 148 | ), 149 | 150 | preproc_params: $ => seq( 151 | token.immediate('('), commaSep(choice($.identifier, '...')), ')', 152 | ), 153 | 154 | preproc_call: $ => seq( 155 | field('directive', $.preproc_directive), 156 | field('argument', optional($.preproc_arg)), 157 | token.immediate(/\r?\n/), 158 | ), 159 | 160 | ...preprocIf('', $ => $._block_item), 161 | ...preprocIf('_in_field_declaration_list', $ => $._field_declaration_list_item), 162 | ...preprocIf('_in_enumerator_list', $ => seq($.enumerator, ',')), 163 | ...preprocIf('_in_enumerator_list_no_comma', $ => $.enumerator, -1), 164 | 165 | preproc_arg: _ => token(prec(-1, /\S([^/\n]|\/[^*]|\\\r?\n)*/)), 166 | preproc_directive: _ => /#[ \t]*[a-zA-Z0-9]\w*/, 167 | 168 | _preproc_expression: $ => choice( 169 | $.identifier, 170 | alias($.preproc_call_expression, $.call_expression), 171 | $.number_literal, 172 | $.char_literal, 173 | $.preproc_defined, 174 | alias($.preproc_unary_expression, $.unary_expression), 175 | alias($.preproc_binary_expression, $.binary_expression), 176 | alias($.preproc_parenthesized_expression, $.parenthesized_expression), 177 | ), 178 | 179 | preproc_parenthesized_expression: $ => seq( 180 | '(', 181 | $._preproc_expression, 182 | ')', 183 | ), 184 | 185 | preproc_defined: $ => choice( 186 | prec(PREC.CALL, seq('defined', '(', $.identifier, ')')), 187 | seq('defined', $.identifier), 188 | ), 189 | 190 | preproc_unary_expression: $ => prec.left(PREC.UNARY, seq( 191 | field('operator', choice('!', '~', '-', '+')), 192 | field('argument', $._preproc_expression), 193 | )), 194 | 195 | preproc_call_expression: $ => prec(PREC.CALL, seq( 196 | field('function', $.identifier), 197 | field('arguments', alias($.preproc_argument_list, $.argument_list)), 198 | )), 199 | 200 | preproc_argument_list: $ => seq( 201 | '(', 202 | commaSep($._preproc_expression), 203 | ')', 204 | ), 205 | 206 | preproc_binary_expression: $ => { 207 | const table = [ 208 | ['+', PREC.ADD], 209 | ['-', PREC.ADD], 210 | ['*', PREC.MULTIPLY], 211 | ['/', PREC.MULTIPLY], 212 | ['%', PREC.MULTIPLY], 213 | ['||', PREC.LOGICAL_OR], 214 | ['&&', PREC.LOGICAL_AND], 215 | ['|', PREC.INCLUSIVE_OR], 216 | ['^', PREC.EXCLUSIVE_OR], 217 | ['&', PREC.BITWISE_AND], 218 | ['==', PREC.EQUAL], 219 | ['!=', PREC.EQUAL], 220 | ['>', PREC.RELATIONAL], 221 | ['>=', PREC.RELATIONAL], 222 | ['<=', PREC.RELATIONAL], 223 | ['<', PREC.RELATIONAL], 224 | ['<<', PREC.SHIFT], 225 | ['>>', PREC.SHIFT], 226 | ]; 227 | 228 | return choice(...table.map(([operator, precedence]) => { 229 | return prec.left(precedence, seq( 230 | field('left', $._preproc_expression), 231 | // @ts-ignore 232 | field('operator', operator), 233 | field('right', $._preproc_expression), 234 | )); 235 | })); 236 | }, 237 | 238 | // Main Grammar 239 | 240 | function_definition: $ => seq( 241 | optional($.ms_call_modifier), 242 | $._declaration_specifiers, 243 | optional($.ms_call_modifier), 244 | field('declarator', $._declarator), 245 | field('body', $.compound_statement), 246 | ), 247 | 248 | _old_style_function_definition: $ => seq( 249 | optional($.ms_call_modifier), 250 | $._declaration_specifiers, 251 | field('declarator', alias($._old_style_function_declarator, $.function_declarator)), 252 | repeat1($.declaration), 253 | field('body', $.compound_statement), 254 | ), 255 | 256 | declaration: $ => seq( 257 | $._declaration_specifiers, 258 | commaSep1(field('declarator', choice( 259 | seq( 260 | optional($.ms_call_modifier), 261 | $._declaration_declarator, 262 | optional($.gnu_asm_expression), 263 | ), 264 | $.init_declarator, 265 | ))), 266 | ';', 267 | ), 268 | 269 | type_definition: $ => seq( 270 | optional('__extension__'), 271 | 'typedef', 272 | $._type_definition_type, 273 | $._type_definition_declarators, 274 | repeat($.attribute_specifier), 275 | ';', 276 | ), 277 | _type_definition_type: $ => seq(repeat($.type_qualifier), field('type', $.type_specifier), repeat($.type_qualifier)), 278 | _type_definition_declarators: $ => commaSep1(field('declarator', $._type_declarator)), 279 | 280 | _declaration_modifiers: $ => choice( 281 | $.storage_class_specifier, 282 | $.type_qualifier, 283 | $.attribute_specifier, 284 | $.attribute_declaration, 285 | $.ms_declspec_modifier, 286 | ), 287 | 288 | _declaration_specifiers: $ => prec.right(seq( 289 | repeat($._declaration_modifiers), 290 | field('type', $.type_specifier), 291 | repeat($._declaration_modifiers), 292 | )), 293 | 294 | linkage_specification: $ => seq( 295 | 'extern', 296 | field('value', $.string_literal), 297 | field('body', choice( 298 | $.function_definition, 299 | $.declaration, 300 | $.declaration_list, 301 | )), 302 | ), 303 | 304 | attribute_specifier: $ => seq( 305 | choice('__attribute__', '__attribute'), 306 | '(', 307 | $.argument_list, 308 | ')', 309 | ), 310 | 311 | attribute: $ => seq( 312 | optional(seq(field('prefix', $.identifier), '::')), 313 | field('name', $.identifier), 314 | optional($.argument_list), 315 | ), 316 | 317 | attribute_declaration: $ => seq( 318 | '[[', 319 | commaSep1($.attribute), 320 | ']]', 321 | ), 322 | 323 | ms_declspec_modifier: $ => seq( 324 | '__declspec', 325 | '(', 326 | $.identifier, 327 | ')', 328 | ), 329 | 330 | ms_based_modifier: $ => seq( 331 | '__based', 332 | $.argument_list, 333 | ), 334 | 335 | ms_call_modifier: _ => choice( 336 | '__cdecl', 337 | '__clrcall', 338 | '__stdcall', 339 | '__fastcall', 340 | '__thiscall', 341 | '__vectorcall', 342 | ), 343 | 344 | ms_restrict_modifier: _ => '__restrict', 345 | 346 | ms_unsigned_ptr_modifier: _ => '__uptr', 347 | 348 | ms_signed_ptr_modifier: _ => '__sptr', 349 | 350 | ms_unaligned_ptr_modifier: _ => choice('_unaligned', '__unaligned'), 351 | 352 | ms_pointer_modifier: $ => choice( 353 | $.ms_unaligned_ptr_modifier, 354 | $.ms_restrict_modifier, 355 | $.ms_unsigned_ptr_modifier, 356 | $.ms_signed_ptr_modifier, 357 | ), 358 | 359 | declaration_list: $ => seq( 360 | '{', 361 | repeat($._block_item), 362 | '}', 363 | ), 364 | 365 | _declarator: $ => choice( 366 | $.attributed_declarator, 367 | $.pointer_declarator, 368 | $.function_declarator, 369 | $.array_declarator, 370 | $.parenthesized_declarator, 371 | $.identifier, 372 | ), 373 | 374 | _declaration_declarator: $ => choice( 375 | $.attributed_declarator, 376 | $.pointer_declarator, 377 | alias($._function_declaration_declarator, $.function_declarator), 378 | $.array_declarator, 379 | $.parenthesized_declarator, 380 | $.identifier, 381 | ), 382 | 383 | _field_declarator: $ => choice( 384 | alias($.attributed_field_declarator, $.attributed_declarator), 385 | alias($.pointer_field_declarator, $.pointer_declarator), 386 | alias($.function_field_declarator, $.function_declarator), 387 | alias($.array_field_declarator, $.array_declarator), 388 | alias($.parenthesized_field_declarator, $.parenthesized_declarator), 389 | $._field_identifier, 390 | ), 391 | 392 | _type_declarator: $ => choice( 393 | alias($.attributed_type_declarator, $.attributed_declarator), 394 | alias($.pointer_type_declarator, $.pointer_declarator), 395 | alias($.function_type_declarator, $.function_declarator), 396 | alias($.array_type_declarator, $.array_declarator), 397 | alias($.parenthesized_type_declarator, $.parenthesized_declarator), 398 | $._type_identifier, 399 | alias(choice('signed', 'unsigned', 'long', 'short'), $.primitive_type), 400 | $.primitive_type, 401 | ), 402 | 403 | _abstract_declarator: $ => choice( 404 | $.abstract_pointer_declarator, 405 | $.abstract_function_declarator, 406 | $.abstract_array_declarator, 407 | $.abstract_parenthesized_declarator, 408 | ), 409 | 410 | parenthesized_declarator: $ => prec.dynamic(PREC.PAREN_DECLARATOR, seq( 411 | '(', 412 | optional($.ms_call_modifier), 413 | $._declarator, 414 | ')', 415 | )), 416 | parenthesized_field_declarator: $ => prec.dynamic(PREC.PAREN_DECLARATOR, seq( 417 | '(', 418 | optional($.ms_call_modifier), 419 | $._field_declarator, 420 | ')', 421 | )), 422 | parenthesized_type_declarator: $ => prec.dynamic(PREC.PAREN_DECLARATOR, seq( 423 | '(', 424 | optional($.ms_call_modifier), 425 | $._type_declarator, 426 | ')', 427 | )), 428 | abstract_parenthesized_declarator: $ => prec(1, seq( 429 | '(', 430 | optional($.ms_call_modifier), 431 | $._abstract_declarator, 432 | ')', 433 | )), 434 | 435 | 436 | attributed_declarator: $ => prec.right(seq( 437 | $._declarator, 438 | repeat1($.attribute_declaration), 439 | )), 440 | attributed_field_declarator: $ => prec.right(seq( 441 | $._field_declarator, 442 | repeat1($.attribute_declaration), 443 | )), 444 | attributed_type_declarator: $ => prec.right(seq( 445 | $._type_declarator, 446 | repeat1($.attribute_declaration), 447 | )), 448 | 449 | pointer_declarator: $ => prec.dynamic(1, prec.right(seq( 450 | optional($.ms_based_modifier), 451 | '*', 452 | repeat($.ms_pointer_modifier), 453 | repeat($.type_qualifier), 454 | field('declarator', $._declarator), 455 | ))), 456 | pointer_field_declarator: $ => prec.dynamic(1, prec.right(seq( 457 | optional($.ms_based_modifier), 458 | '*', 459 | repeat($.ms_pointer_modifier), 460 | repeat($.type_qualifier), 461 | field('declarator', $._field_declarator), 462 | ))), 463 | pointer_type_declarator: $ => prec.dynamic(1, prec.right(seq( 464 | optional($.ms_based_modifier), 465 | '*', 466 | repeat($.ms_pointer_modifier), 467 | repeat($.type_qualifier), 468 | field('declarator', $._type_declarator), 469 | ))), 470 | abstract_pointer_declarator: $ => prec.dynamic(1, prec.right(seq('*', 471 | repeat($.ms_pointer_modifier), 472 | repeat($.type_qualifier), 473 | field('declarator', optional($._abstract_declarator)), 474 | ))), 475 | 476 | function_declarator: $ => prec.right(1, 477 | seq( 478 | field('declarator', $._declarator), 479 | field('parameters', $.parameter_list), 480 | optional($.gnu_asm_expression), 481 | repeat(choice( 482 | $.attribute_specifier, 483 | $.identifier, 484 | alias($.preproc_call_expression, $.call_expression), 485 | )), 486 | ), 487 | ), 488 | 489 | _function_declaration_declarator: $ => prec.right(1, 490 | seq( 491 | field('declarator', $._declarator), 492 | field('parameters', $.parameter_list), 493 | optional($.gnu_asm_expression), 494 | repeat($.attribute_specifier), 495 | )), 496 | 497 | function_field_declarator: $ => prec(1, seq( 498 | field('declarator', $._field_declarator), 499 | field('parameters', $.parameter_list), 500 | )), 501 | function_type_declarator: $ => prec(1, seq( 502 | field('declarator', $._type_declarator), 503 | field('parameters', $.parameter_list), 504 | )), 505 | abstract_function_declarator: $ => prec(1, seq( 506 | field('declarator', optional($._abstract_declarator)), 507 | field('parameters', $.parameter_list), 508 | )), 509 | 510 | _old_style_function_declarator: $ => seq( 511 | field('declarator', $._declarator), 512 | field('parameters', alias($._old_style_parameter_list, $.parameter_list)), 513 | ), 514 | 515 | array_declarator: $ => prec(1, seq( 516 | field('declarator', $._declarator), 517 | '[', 518 | repeat(choice($.type_qualifier, 'static')), 519 | field('size', optional(choice($.expression, '*'))), 520 | ']', 521 | )), 522 | array_field_declarator: $ => prec(1, seq( 523 | field('declarator', $._field_declarator), 524 | '[', 525 | repeat(choice($.type_qualifier, 'static')), 526 | field('size', optional(choice($.expression, '*'))), 527 | ']', 528 | )), 529 | array_type_declarator: $ => prec(1, seq( 530 | field('declarator', $._type_declarator), 531 | '[', 532 | repeat(choice($.type_qualifier, 'static')), 533 | field('size', optional(choice($.expression, '*'))), 534 | ']', 535 | )), 536 | abstract_array_declarator: $ => prec(1, seq( 537 | field('declarator', optional($._abstract_declarator)), 538 | '[', 539 | repeat(choice($.type_qualifier, 'static')), 540 | field('size', optional(choice($.expression, '*'))), 541 | ']', 542 | )), 543 | 544 | init_declarator: $ => seq( 545 | field('declarator', $._declarator), 546 | '=', 547 | field('value', choice($.initializer_list, $.expression)), 548 | ), 549 | 550 | compound_statement: $ => seq( 551 | '{', 552 | repeat($._block_item), 553 | '}', 554 | ), 555 | 556 | storage_class_specifier: _ => choice( 557 | 'extern', 558 | 'static', 559 | 'auto', 560 | 'register', 561 | 'inline', 562 | '__inline', 563 | '__inline__', 564 | '__forceinline', 565 | 'thread_local', 566 | '__thread', 567 | ), 568 | 569 | type_qualifier: $ => choice( 570 | 'const', 571 | 'constexpr', 572 | 'volatile', 573 | 'restrict', 574 | '__restrict__', 575 | '__extension__', 576 | '_Atomic', 577 | '_Noreturn', 578 | 'noreturn', 579 | '_Nonnull', 580 | $.alignas_qualifier, 581 | ), 582 | 583 | alignas_qualifier: $ => seq( 584 | choice('alignas', '_Alignas'), 585 | '(', 586 | choice($.expression, $.type_descriptor), 587 | ')', 588 | ), 589 | 590 | type_specifier: $ => choice( 591 | $.struct_specifier, 592 | $.union_specifier, 593 | $.enum_specifier, 594 | $.macro_type_specifier, 595 | $.sized_type_specifier, 596 | $.primitive_type, 597 | $._type_identifier, 598 | ), 599 | 600 | sized_type_specifier: $ => choice( 601 | seq( 602 | repeat(choice( 603 | 'signed', 604 | 'unsigned', 605 | 'long', 606 | 'short', 607 | )), 608 | field('type', optional(choice( 609 | prec.dynamic(-1, $._type_identifier), 610 | $.primitive_type, 611 | ))), 612 | repeat1(choice( 613 | 'signed', 614 | 'unsigned', 615 | 'long', 616 | 'short', 617 | )), 618 | ), 619 | seq( 620 | repeat1(choice( 621 | 'signed', 622 | 'unsigned', 623 | 'long', 624 | 'short', 625 | )), 626 | repeat($.type_qualifier), 627 | field('type', optional(choice( 628 | prec.dynamic(-1, $._type_identifier), 629 | $.primitive_type, 630 | ))), 631 | repeat(choice( 632 | 'signed', 633 | 'unsigned', 634 | 'long', 635 | 'short', 636 | )), 637 | ), 638 | ), 639 | 640 | primitive_type: _ => token(choice( 641 | 'bool', 642 | 'char', 643 | 'int', 644 | 'float', 645 | 'double', 646 | 'void', 647 | 'size_t', 648 | 'ssize_t', 649 | 'ptrdiff_t', 650 | 'intptr_t', 651 | 'uintptr_t', 652 | 'charptr_t', 653 | 'nullptr_t', 654 | 'max_align_t', 655 | ...[8, 16, 32, 64].map(n => `int${n}_t`), 656 | ...[8, 16, 32, 64].map(n => `uint${n}_t`), 657 | ...[8, 16, 32, 64].map(n => `char${n}_t`), 658 | )), 659 | 660 | enum_specifier: $ => seq( 661 | 'enum', 662 | choice( 663 | seq( 664 | field('name', $._type_identifier), 665 | optional(seq(':', field('underlying_type', $.primitive_type))), 666 | field('body', optional($.enumerator_list)), 667 | ), 668 | field('body', $.enumerator_list), 669 | ), 670 | optional($.attribute_specifier), 671 | ), 672 | 673 | enumerator_list: $ => seq( 674 | '{', 675 | repeat(choice( 676 | seq($.enumerator, ','), 677 | alias($.preproc_if_in_enumerator_list, $.preproc_if), 678 | alias($.preproc_ifdef_in_enumerator_list, $.preproc_ifdef), 679 | seq($.preproc_call, ','), 680 | )), 681 | optional(seq( 682 | choice( 683 | $.enumerator, 684 | alias($.preproc_if_in_enumerator_list_no_comma, $.preproc_if), 685 | alias($.preproc_ifdef_in_enumerator_list_no_comma, $.preproc_ifdef), 686 | $.preproc_call, 687 | ), 688 | )), 689 | '}', 690 | ), 691 | 692 | struct_specifier: $ => prec.right(seq( 693 | 'struct', 694 | optional($.attribute_specifier), 695 | optional($.ms_declspec_modifier), 696 | choice( 697 | seq( 698 | field('name', $._type_identifier), 699 | field('body', optional($.field_declaration_list)), 700 | ), 701 | field('body', $.field_declaration_list), 702 | ), 703 | optional($.attribute_specifier), 704 | )), 705 | 706 | union_specifier: $ => prec.right(seq( 707 | 'union', 708 | optional($.ms_declspec_modifier), 709 | choice( 710 | seq( 711 | field('name', $._type_identifier), 712 | field('body', optional($.field_declaration_list)), 713 | ), 714 | field('body', $.field_declaration_list), 715 | ), 716 | optional($.attribute_specifier), 717 | )), 718 | 719 | field_declaration_list: $ => seq( 720 | '{', 721 | repeat($._field_declaration_list_item), 722 | '}', 723 | ), 724 | 725 | _field_declaration_list_item: $ => choice( 726 | $.field_declaration, 727 | $.preproc_def, 728 | $.preproc_function_def, 729 | $.preproc_call, 730 | alias($.preproc_if_in_field_declaration_list, $.preproc_if), 731 | alias($.preproc_ifdef_in_field_declaration_list, $.preproc_ifdef), 732 | ), 733 | 734 | field_declaration: $ => seq( 735 | $._declaration_specifiers, 736 | optional($._field_declaration_declarator), 737 | optional($.attribute_specifier), 738 | ';', 739 | ), 740 | _field_declaration_declarator: $ => commaSep1(seq( 741 | field('declarator', $._field_declarator), 742 | optional($.bitfield_clause), 743 | )), 744 | 745 | bitfield_clause: $ => seq(':', $.expression), 746 | 747 | enumerator: $ => seq( 748 | field('name', $.identifier), 749 | optional(seq('=', field('value', $.expression))), 750 | ), 751 | 752 | variadic_parameter: _ => '...', 753 | 754 | parameter_list: $ => seq( 755 | '(', 756 | choice( 757 | commaSep(choice($.parameter_declaration, $.variadic_parameter)), 758 | $.compound_statement, 759 | ), 760 | ')', 761 | ), 762 | _old_style_parameter_list: $ => seq( 763 | '(', 764 | commaSep(choice($.identifier, $.variadic_parameter)), 765 | ')', 766 | ), 767 | 768 | parameter_declaration: $ => seq( 769 | $._declaration_specifiers, 770 | optional(field('declarator', choice( 771 | $._declarator, 772 | $._abstract_declarator, 773 | ))), 774 | repeat($.attribute_specifier), 775 | ), 776 | 777 | // Statements 778 | 779 | attributed_statement: $ => seq( 780 | repeat1($.attribute_declaration), 781 | $.statement, 782 | ), 783 | 784 | statement: $ => choice( 785 | $.case_statement, 786 | $._non_case_statement, 787 | ), 788 | 789 | _non_case_statement: $ => choice( 790 | $.attributed_statement, 791 | $.labeled_statement, 792 | $.compound_statement, 793 | $.expression_statement, 794 | $.if_statement, 795 | $.switch_statement, 796 | $.do_statement, 797 | $.while_statement, 798 | $.for_statement, 799 | $.return_statement, 800 | $.break_statement, 801 | $.continue_statement, 802 | $.goto_statement, 803 | $.seh_try_statement, 804 | $.seh_leave_statement, 805 | ), 806 | 807 | _top_level_statement: $ => choice( 808 | $.case_statement, 809 | $.attributed_statement, 810 | $.labeled_statement, 811 | $.compound_statement, 812 | alias($._top_level_expression_statement, $.expression_statement), 813 | $.if_statement, 814 | $.switch_statement, 815 | $.do_statement, 816 | $.while_statement, 817 | $.for_statement, 818 | $.return_statement, 819 | $.break_statement, 820 | $.continue_statement, 821 | $.goto_statement, 822 | ), 823 | 824 | labeled_statement: $ => seq( 825 | field('label', $._statement_identifier), 826 | ':', 827 | choice($.declaration, $.statement), 828 | ), 829 | 830 | // This is missing binary expressions, others were kept so that macro code can be parsed better and code examples 831 | _top_level_expression_statement: $ => seq( 832 | optional($._expression_not_binary), 833 | ';', 834 | ), 835 | 836 | expression_statement: $ => seq( 837 | optional(choice( 838 | $.expression, 839 | $.comma_expression, 840 | )), 841 | ';', 842 | ), 843 | 844 | if_statement: $ => prec.right(seq( 845 | 'if', 846 | field('condition', $.parenthesized_expression), 847 | field('consequence', $.statement), 848 | optional(field('alternative', $.else_clause)), 849 | )), 850 | 851 | else_clause: $ => seq('else', $.statement), 852 | 853 | switch_statement: $ => seq( 854 | 'switch', 855 | field('condition', $.parenthesized_expression), 856 | field('body', $.compound_statement), 857 | ), 858 | 859 | case_statement: $ => prec.right(seq( 860 | choice( 861 | seq('case', field('value', $.expression)), 862 | 'default', 863 | ), 864 | ':', 865 | repeat(choice( 866 | $._non_case_statement, 867 | $.declaration, 868 | $.type_definition, 869 | )), 870 | )), 871 | 872 | while_statement: $ => seq( 873 | 'while', 874 | field('condition', $.parenthesized_expression), 875 | field('body', $.statement), 876 | ), 877 | 878 | do_statement: $ => seq( 879 | 'do', 880 | field('body', $.statement), 881 | 'while', 882 | field('condition', $.parenthesized_expression), 883 | ';', 884 | ), 885 | 886 | for_statement: $ => seq( 887 | 'for', 888 | '(', 889 | $._for_statement_body, 890 | ')', 891 | field('body', $.statement), 892 | ), 893 | _for_statement_body: $ => seq( 894 | choice( 895 | field('initializer', $.declaration), 896 | seq(field('initializer', optional(choice($.expression, $.comma_expression))), ';'), 897 | ), 898 | field('condition', optional(choice($.expression, $.comma_expression))), 899 | ';', 900 | field('update', optional(choice($.expression, $.comma_expression))), 901 | ), 902 | 903 | return_statement: $ => seq( 904 | 'return', 905 | optional(choice($.expression, $.comma_expression)), 906 | ';', 907 | ), 908 | 909 | break_statement: _ => seq( 910 | 'break', ';', 911 | ), 912 | 913 | continue_statement: _ => seq( 914 | 'continue', ';', 915 | ), 916 | 917 | goto_statement: $ => seq( 918 | 'goto', 919 | field('label', $._statement_identifier), 920 | ';', 921 | ), 922 | 923 | seh_try_statement: $ => seq( 924 | '__try', 925 | field('body', $.compound_statement), 926 | choice($.seh_except_clause, $.seh_finally_clause), 927 | ), 928 | 929 | seh_except_clause: $ => seq( 930 | '__except', 931 | field('filter', $.parenthesized_expression), 932 | field('body', $.compound_statement), 933 | ), 934 | 935 | seh_finally_clause: $ => seq( 936 | '__finally', 937 | field('body', $.compound_statement), 938 | ), 939 | 940 | seh_leave_statement: _ => seq( 941 | '__leave', ';', 942 | ), 943 | 944 | // Expressions 945 | 946 | expression: $ => choice( 947 | $._expression_not_binary, 948 | $.binary_expression, 949 | ), 950 | 951 | _expression_not_binary: $ => choice( 952 | $.conditional_expression, 953 | $.assignment_expression, 954 | $.unary_expression, 955 | $.update_expression, 956 | $.cast_expression, 957 | $.pointer_expression, 958 | $.sizeof_expression, 959 | $.alignof_expression, 960 | $.offsetof_expression, 961 | $.generic_expression, 962 | $.subscript_expression, 963 | $.call_expression, 964 | $.field_expression, 965 | $.compound_literal_expression, 966 | $.identifier, 967 | $.number_literal, 968 | $._string, 969 | $.true, 970 | $.false, 971 | $.null, 972 | $.char_literal, 973 | $.parenthesized_expression, 974 | $.gnu_asm_expression, 975 | $.extension_expression, 976 | ), 977 | 978 | _string: $ => prec.left(choice( 979 | $.string_literal, 980 | $.concatenated_string, 981 | )), 982 | 983 | comma_expression: $ => seq( 984 | field('left', $.expression), 985 | ',', 986 | field('right', choice($.expression, $.comma_expression)), 987 | ), 988 | 989 | conditional_expression: $ => prec.right(PREC.CONDITIONAL, seq( 990 | field('condition', $.expression), 991 | '?', 992 | optional(field('consequence', choice($.expression, $.comma_expression))), 993 | ':', 994 | field('alternative', $.expression), 995 | )), 996 | 997 | _assignment_left_expression: $ => choice( 998 | $.identifier, 999 | $.call_expression, 1000 | $.field_expression, 1001 | $.pointer_expression, 1002 | $.subscript_expression, 1003 | $.parenthesized_expression, 1004 | ), 1005 | 1006 | assignment_expression: $ => prec.right(PREC.ASSIGNMENT, seq( 1007 | field('left', $._assignment_left_expression), 1008 | field('operator', choice( 1009 | '=', 1010 | '*=', 1011 | '/=', 1012 | '%=', 1013 | '+=', 1014 | '-=', 1015 | '<<=', 1016 | '>>=', 1017 | '&=', 1018 | '^=', 1019 | '|=', 1020 | )), 1021 | field('right', $.expression), 1022 | )), 1023 | 1024 | pointer_expression: $ => prec.left(PREC.CAST, seq( 1025 | field('operator', choice('*', '&')), 1026 | field('argument', $.expression), 1027 | )), 1028 | 1029 | unary_expression: $ => prec.left(PREC.UNARY, seq( 1030 | field('operator', choice('!', '~', '-', '+')), 1031 | field('argument', $.expression), 1032 | )), 1033 | 1034 | binary_expression: $ => { 1035 | const table = [ 1036 | ['+', PREC.ADD], 1037 | ['-', PREC.ADD], 1038 | ['*', PREC.MULTIPLY], 1039 | ['/', PREC.MULTIPLY], 1040 | ['%', PREC.MULTIPLY], 1041 | ['||', PREC.LOGICAL_OR], 1042 | ['&&', PREC.LOGICAL_AND], 1043 | ['|', PREC.INCLUSIVE_OR], 1044 | ['^', PREC.EXCLUSIVE_OR], 1045 | ['&', PREC.BITWISE_AND], 1046 | ['==', PREC.EQUAL], 1047 | ['!=', PREC.EQUAL], 1048 | ['>', PREC.RELATIONAL], 1049 | ['>=', PREC.RELATIONAL], 1050 | ['<=', PREC.RELATIONAL], 1051 | ['<', PREC.RELATIONAL], 1052 | ['<<', PREC.SHIFT], 1053 | ['>>', PREC.SHIFT], 1054 | ]; 1055 | 1056 | return choice(...table.map(([operator, precedence]) => { 1057 | return prec.left(precedence, seq( 1058 | field('left', $.expression), 1059 | // @ts-ignore 1060 | field('operator', operator), 1061 | field('right', $.expression), 1062 | )); 1063 | })); 1064 | }, 1065 | 1066 | update_expression: $ => { 1067 | const argument = field('argument', $.expression); 1068 | const operator = field('operator', choice('--', '++')); 1069 | return prec.right(PREC.UNARY, choice( 1070 | seq(operator, argument), 1071 | seq(argument, operator), 1072 | )); 1073 | }, 1074 | 1075 | cast_expression: $ => prec(PREC.CAST, seq( 1076 | '(', 1077 | field('type', $.type_descriptor), 1078 | ')', 1079 | field('value', $.expression), 1080 | )), 1081 | 1082 | type_descriptor: $ => seq( 1083 | repeat($.type_qualifier), 1084 | field('type', $.type_specifier), 1085 | repeat($.type_qualifier), 1086 | field('declarator', optional($._abstract_declarator)), 1087 | ), 1088 | 1089 | sizeof_expression: $ => prec(PREC.SIZEOF, seq( 1090 | 'sizeof', 1091 | choice( 1092 | field('value', $.expression), 1093 | seq('(', field('type', $.type_descriptor), ')'), 1094 | ), 1095 | )), 1096 | 1097 | alignof_expression: $ => prec(PREC.SIZEOF, seq( 1098 | choice('__alignof__', '__alignof', '_alignof', 'alignof', '_Alignof'), 1099 | seq('(', field('type', $.type_descriptor), ')'), 1100 | )), 1101 | 1102 | offsetof_expression: $ => prec(PREC.OFFSETOF, seq( 1103 | 'offsetof', 1104 | seq('(', field('type', $.type_descriptor), ',', field('member', $._field_identifier), ')'), 1105 | )), 1106 | 1107 | generic_expression: $ => prec(PREC.CALL, seq( 1108 | '_Generic', 1109 | '(', 1110 | $.expression, 1111 | ',', 1112 | commaSep1(seq($.type_descriptor, ':', $.expression)), 1113 | ')', 1114 | )), 1115 | 1116 | subscript_expression: $ => prec(PREC.SUBSCRIPT, seq( 1117 | field('argument', $.expression), 1118 | '[', 1119 | field('index', $.expression), 1120 | ']', 1121 | )), 1122 | 1123 | call_expression: $ => prec(PREC.CALL, seq( 1124 | field('function', $.expression), 1125 | field('arguments', $.argument_list), 1126 | )), 1127 | 1128 | gnu_asm_expression: $ => prec(PREC.CALL, seq( 1129 | choice('asm', '__asm__', '__asm'), 1130 | repeat($.gnu_asm_qualifier), 1131 | '(', 1132 | field('assembly_code', $._string), 1133 | optional(seq( 1134 | field('output_operands', $.gnu_asm_output_operand_list), 1135 | optional(seq( 1136 | field('input_operands', $.gnu_asm_input_operand_list), 1137 | optional(seq( 1138 | field('clobbers', $.gnu_asm_clobber_list), 1139 | optional(field('goto_labels', $.gnu_asm_goto_list)), 1140 | )), 1141 | )), 1142 | )), 1143 | ')', 1144 | )), 1145 | 1146 | gnu_asm_qualifier: _ => choice( 1147 | 'volatile', 1148 | '__volatile__', 1149 | 'inline', 1150 | 'goto', 1151 | ), 1152 | 1153 | gnu_asm_output_operand_list: $ => seq( 1154 | ':', 1155 | commaSep(field('operand', $.gnu_asm_output_operand)), 1156 | ), 1157 | 1158 | gnu_asm_output_operand: $ => seq( 1159 | optional(seq( 1160 | '[', 1161 | field('symbol', $.identifier), 1162 | ']', 1163 | )), 1164 | field('constraint', $.string_literal), 1165 | '(', 1166 | field('value', $.expression), 1167 | ')', 1168 | ), 1169 | 1170 | gnu_asm_input_operand_list: $ => seq( 1171 | ':', 1172 | commaSep(field('operand', $.gnu_asm_input_operand)), 1173 | ), 1174 | 1175 | gnu_asm_input_operand: $ => seq( 1176 | optional(seq( 1177 | '[', 1178 | field('symbol', $.identifier), 1179 | ']', 1180 | )), 1181 | field('constraint', $.string_literal), 1182 | '(', 1183 | field('value', $.expression), 1184 | ')', 1185 | ), 1186 | 1187 | gnu_asm_clobber_list: $ => seq( 1188 | ':', 1189 | commaSep(field('register', $._string)), 1190 | ), 1191 | 1192 | gnu_asm_goto_list: $ => seq( 1193 | ':', 1194 | commaSep(field('label', $.identifier)), 1195 | ), 1196 | 1197 | extension_expression: $ => seq('__extension__', $.expression), 1198 | 1199 | // The compound_statement is added to parse macros taking statements as arguments, e.g. MYFORLOOP(1, 10, i, { foo(i); bar(i); }) 1200 | argument_list: $ => seq('(', commaSep(choice($.expression, $.compound_statement)), ')'), 1201 | 1202 | field_expression: $ => seq( 1203 | prec(PREC.FIELD, seq( 1204 | field('argument', $.expression), 1205 | field('operator', choice('.', '->')), 1206 | )), 1207 | field('field', $._field_identifier), 1208 | ), 1209 | 1210 | compound_literal_expression: $ => seq( 1211 | '(', 1212 | field('type', $.type_descriptor), 1213 | ')', 1214 | field('value', $.initializer_list), 1215 | ), 1216 | 1217 | parenthesized_expression: $ => seq( 1218 | '(', 1219 | choice($.expression, $.comma_expression, $.compound_statement), 1220 | ')', 1221 | ), 1222 | 1223 | initializer_list: $ => seq( 1224 | '{', 1225 | commaSep(choice( 1226 | $.initializer_pair, 1227 | $.expression, 1228 | $.initializer_list, 1229 | )), 1230 | optional(','), 1231 | '}', 1232 | ), 1233 | 1234 | initializer_pair: $ => choice( 1235 | seq( 1236 | field('designator', repeat1(choice( 1237 | $.subscript_designator, 1238 | $.field_designator, 1239 | $.subscript_range_designator, 1240 | ))), 1241 | '=', 1242 | field('value', choice($.expression, $.initializer_list)), 1243 | ), 1244 | seq( 1245 | field('designator', $._field_identifier), 1246 | ':', 1247 | field('value', choice($.expression, $.initializer_list)), 1248 | ), 1249 | ), 1250 | 1251 | subscript_designator: $ => seq('[', $.expression, ']'), 1252 | 1253 | subscript_range_designator: $ => seq('[', field('start', $.expression), '...', field('end', $.expression), ']'), 1254 | 1255 | field_designator: $ => seq('.', $._field_identifier), 1256 | 1257 | number_literal: _ => { 1258 | const separator = '\''; 1259 | const hex = /[0-9a-fA-F]/; 1260 | const decimal = /[0-9]/; 1261 | const hexDigits = seq(repeat1(hex), repeat(seq(separator, repeat1(hex)))); 1262 | const decimalDigits = seq(repeat1(decimal), repeat(seq(separator, repeat1(decimal)))); 1263 | return token(seq( 1264 | optional(/[-\+]/), 1265 | optional(choice(/0[xX]/, /0[bB]/)), 1266 | choice( 1267 | seq( 1268 | choice( 1269 | decimalDigits, 1270 | seq(/0[bB]/, decimalDigits), 1271 | seq(/0[xX]/, hexDigits), 1272 | ), 1273 | optional(seq('.', optional(hexDigits))), 1274 | ), 1275 | seq('.', decimalDigits), 1276 | ), 1277 | optional(seq( 1278 | /[eEpP]/, 1279 | optional(seq( 1280 | optional(/[-\+]/), 1281 | hexDigits, 1282 | )), 1283 | )), 1284 | /[uUlLwWfFbBdD]*/, 1285 | )); 1286 | }, 1287 | 1288 | char_literal: $ => seq( 1289 | choice('L\'', 'u\'', 'U\'', 'u8\'', '\''), 1290 | repeat1(choice( 1291 | $.escape_sequence, 1292 | alias(token.immediate(/[^\n']/), $.character), 1293 | )), 1294 | '\'', 1295 | ), 1296 | 1297 | // Must concatenate at least 2 nodes, one of which must be a string_literal. 1298 | // Identifier is added to parse macros that are strings, like PRIu64. 1299 | concatenated_string: $ => prec.right(seq( 1300 | choice( 1301 | seq($.identifier, $.string_literal), 1302 | seq($.string_literal, $.string_literal), 1303 | seq($.string_literal, $.identifier), 1304 | ), 1305 | repeat(choice($.string_literal, $.identifier)), 1306 | )), 1307 | 1308 | string_literal: $ => seq( 1309 | choice('L"', 'u"', 'U"', 'u8"', '"'), 1310 | repeat(choice( 1311 | alias(token.immediate(prec(1, /[^\\"\n]+/)), $.string_content), 1312 | $.escape_sequence, 1313 | )), 1314 | '"', 1315 | ), 1316 | 1317 | escape_sequence: _ => token(prec(1, seq( 1318 | '\\', 1319 | choice( 1320 | /[^xuU]/, 1321 | /\d{2,3}/, 1322 | /x[0-9a-fA-F]{1,4}/, 1323 | /u[0-9a-fA-F]{4}/, 1324 | /U[0-9a-fA-F]{8}/, 1325 | ), 1326 | ))), 1327 | 1328 | system_lib_string: _ => token(seq( 1329 | '<', 1330 | repeat(choice(/[^>\n]/, '\\>')), 1331 | '>', 1332 | )), 1333 | 1334 | true: _ => token(choice('TRUE', 'true')), 1335 | false: _ => token(choice('FALSE', 'false')), 1336 | null: _ => choice('NULL', 'nullptr'), 1337 | 1338 | identifier: _ => 1339 | /(\p{XID_Start}|\$|_|\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8})(\p{XID_Continue}|\$|\\u[0-9A-Fa-f]{4}|\\U[0-9A-Fa-f]{8})*/, 1340 | 1341 | _type_identifier: $ => alias( 1342 | $.identifier, 1343 | $.type_identifier, 1344 | ), 1345 | _field_identifier: $ => alias($.identifier, $.field_identifier), 1346 | _statement_identifier: $ => alias($.identifier, $.statement_identifier), 1347 | 1348 | _empty_declaration: $ => seq( 1349 | $.type_specifier, 1350 | ';', 1351 | ), 1352 | 1353 | macro_type_specifier: $ => prec.dynamic(-1, seq( 1354 | field('name', $.identifier), 1355 | '(', 1356 | field('type', $.type_descriptor), 1357 | ')', 1358 | )), 1359 | 1360 | // http://stackoverflow.com/questions/13014947/regex-to-match-a-c-style-multiline-comment/36328890#36328890 1361 | comment: _ => token(choice( 1362 | seq('//', /(\\+(.|\r?\n)|[^\\\n])*/), 1363 | seq( 1364 | '/*', 1365 | /[^*]*\*+([^/*][^*]*\*+)*/, 1366 | '/', 1367 | ), 1368 | )), 1369 | }, 1370 | }); 1371 | 1372 | /** 1373 | * 1374 | * @param {string} suffix 1375 | * 1376 | * @param {RuleBuilder} content 1377 | * 1378 | * @param {number} precedence 1379 | * 1380 | * @returns {RuleBuilders} 1381 | */ 1382 | function preprocIf(suffix, content, precedence = 0) { 1383 | /** 1384 | * 1385 | * @param {GrammarSymbols} $ 1386 | * 1387 | * @returns {ChoiceRule} 1388 | */ 1389 | function alternativeBlock($) { 1390 | return choice( 1391 | suffix ? alias($['preproc_else' + suffix], $.preproc_else) : $.preproc_else, 1392 | suffix ? alias($['preproc_elif' + suffix], $.preproc_elif) : $.preproc_elif, 1393 | suffix ? alias($['preproc_elifdef' + suffix], $.preproc_elifdef) : $.preproc_elifdef, 1394 | ); 1395 | } 1396 | 1397 | return { 1398 | ['preproc_if' + suffix]: $ => prec(precedence, seq( 1399 | preprocessor('if'), 1400 | field('condition', $._preproc_expression), 1401 | '\n', 1402 | repeat(content($)), 1403 | field('alternative', optional(alternativeBlock($))), 1404 | preprocessor('endif'), 1405 | )), 1406 | 1407 | ['preproc_ifdef' + suffix]: $ => prec(precedence, seq( 1408 | choice(preprocessor('ifdef'), preprocessor('ifndef')), 1409 | field('name', $.identifier), 1410 | repeat(content($)), 1411 | field('alternative', optional(alternativeBlock($))), 1412 | preprocessor('endif'), 1413 | )), 1414 | 1415 | ['preproc_else' + suffix]: $ => prec(precedence, seq( 1416 | preprocessor('else'), 1417 | repeat(content($)), 1418 | )), 1419 | 1420 | ['preproc_elif' + suffix]: $ => prec(precedence, seq( 1421 | preprocessor('elif'), 1422 | field('condition', $._preproc_expression), 1423 | '\n', 1424 | repeat(content($)), 1425 | field('alternative', optional(alternativeBlock($))), 1426 | )), 1427 | 1428 | ['preproc_elifdef' + suffix]: $ => prec(precedence, seq( 1429 | choice(preprocessor('elifdef'), preprocessor('elifndef')), 1430 | field('name', $.identifier), 1431 | repeat(content($)), 1432 | field('alternative', optional(alternativeBlock($))), 1433 | )), 1434 | }; 1435 | } 1436 | 1437 | /** 1438 | * Creates a preprocessor regex rule 1439 | * 1440 | * @param {RegExp | Rule | string} command 1441 | * 1442 | * @returns {AliasRule} 1443 | */ 1444 | function preprocessor(command) { 1445 | return alias(new RegExp('#[ \t]*' + command), '#' + command); 1446 | } 1447 | 1448 | /** 1449 | * Creates a rule to optionally match one or more of the rules separated by a comma 1450 | * 1451 | * @param {Rule} rule 1452 | * 1453 | * @returns {ChoiceRule} 1454 | */ 1455 | function commaSep(rule) { 1456 | return optional(commaSep1(rule)); 1457 | } 1458 | 1459 | /** 1460 | * Creates a rule to match one or more of the rules separated by a comma 1461 | * 1462 | * @param {Rule} rule 1463 | * 1464 | * @returns {SeqRule} 1465 | */ 1466 | function commaSep1(rule) { 1467 | return seq(rule, repeat(seq(',', rule))); 1468 | } 1469 | 1470 | module.exports.PREC = PREC; 1471 | module.exports.preprocIf = preprocIf; 1472 | module.exports.preprocessor = preprocessor; 1473 | module.exports.commaSep = commaSep; 1474 | module.exports.commaSep1 = commaSep1; 1475 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-c", 3 | "version": "0.24.1", 4 | "description": "C grammar for tree-sitter", 5 | "repository": "https://github.com/tree-sitter/tree-sitter-c", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Max Brunsfeld", 9 | "email": "maxbrunsfeld@gmail.com" 10 | }, 11 | "maintainers": [ 12 | { 13 | "name": "Amaan Qureshi", 14 | "email": "amaanq12@gmail.com" 15 | } 16 | ], 17 | "main": "bindings/node", 18 | "types": "bindings/node", 19 | "keywords": [ 20 | "incremental", 21 | "parsing", 22 | "tree-sitter", 23 | "c" 24 | ], 25 | "files": [ 26 | "grammar.js", 27 | "tree-sitter.json", 28 | "binding.gyp", 29 | "prebuilds/**", 30 | "bindings/node/*", 31 | "queries/*", 32 | "src/**", 33 | "*.wasm" 34 | ], 35 | "dependencies": { 36 | "node-addon-api": "^8.3.1", 37 | "node-gyp-build": "^4.8.4" 38 | }, 39 | "devDependencies": { 40 | "eslint": "^9.17.0", 41 | "eslint-config-treesitter": "^1.0.2", 42 | "prebuildify": "^6.0.1", 43 | "tree-sitter-cli": "^0.25.0" 44 | }, 45 | "peerDependencies": { 46 | "tree-sitter": "^0.22.4" 47 | }, 48 | "peerDependenciesMeta": { 49 | "tree-sitter": { 50 | "optional": true 51 | } 52 | }, 53 | "scripts": { 54 | "install": "node-gyp-build", 55 | "lint": "eslint grammar.js", 56 | "prestart": "tree-sitter build --wasm", 57 | "start": "tree-sitter playground", 58 | "test": "node --test bindings/node/*_test.js" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=42", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "tree-sitter-c" 7 | description = "C grammar for tree-sitter" 8 | version = "0.24.1" 9 | keywords = ["incremental", "parsing", "tree-sitter", "c"] 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.10" 22 | license.text = "MIT" 23 | readme = "README.md" 24 | 25 | [project.urls] 26 | Homepage = "https://github.com/tree-sitter/tree-sitter-c" 27 | 28 | [project.optional-dependencies] 29 | core = ["tree-sitter~=0.24"] 30 | 31 | [tool.cibuildwheel] 32 | build = "cp310-*" 33 | build-frontend = "build" 34 | -------------------------------------------------------------------------------- /queries/highlights.scm: -------------------------------------------------------------------------------- 1 | (identifier) @variable 2 | 3 | ((identifier) @constant 4 | (#match? @constant "^[A-Z][A-Z\\d_]*$")) 5 | 6 | "break" @keyword 7 | "case" @keyword 8 | "const" @keyword 9 | "continue" @keyword 10 | "default" @keyword 11 | "do" @keyword 12 | "else" @keyword 13 | "enum" @keyword 14 | "extern" @keyword 15 | "for" @keyword 16 | "if" @keyword 17 | "inline" @keyword 18 | "return" @keyword 19 | "sizeof" @keyword 20 | "static" @keyword 21 | "struct" @keyword 22 | "switch" @keyword 23 | "typedef" @keyword 24 | "union" @keyword 25 | "volatile" @keyword 26 | "while" @keyword 27 | 28 | "#define" @keyword 29 | "#elif" @keyword 30 | "#else" @keyword 31 | "#endif" @keyword 32 | "#if" @keyword 33 | "#ifdef" @keyword 34 | "#ifndef" @keyword 35 | "#include" @keyword 36 | (preproc_directive) @keyword 37 | 38 | "--" @operator 39 | "-" @operator 40 | "-=" @operator 41 | "->" @operator 42 | "=" @operator 43 | "!=" @operator 44 | "*" @operator 45 | "&" @operator 46 | "&&" @operator 47 | "+" @operator 48 | "++" @operator 49 | "+=" @operator 50 | "<" @operator 51 | "==" @operator 52 | ">" @operator 53 | "||" @operator 54 | 55 | "." @delimiter 56 | ";" @delimiter 57 | 58 | (string_literal) @string 59 | (system_lib_string) @string 60 | 61 | (null) @constant 62 | (number_literal) @number 63 | (char_literal) @number 64 | 65 | (field_identifier) @property 66 | (statement_identifier) @label 67 | (type_identifier) @type 68 | (primitive_type) @type 69 | (sized_type_specifier) @type 70 | 71 | (call_expression 72 | function: (identifier) @function) 73 | (call_expression 74 | function: (field_expression 75 | field: (field_identifier) @function)) 76 | (function_declarator 77 | declarator: (identifier) @function) 78 | (preproc_function_def 79 | name: (identifier) @function.special) 80 | 81 | (comment) @comment 82 | -------------------------------------------------------------------------------- /queries/tags.scm: -------------------------------------------------------------------------------- 1 | (struct_specifier name: (type_identifier) @name body:(_)) @definition.class 2 | 3 | (declaration type: (union_specifier name: (type_identifier) @name)) @definition.class 4 | 5 | (function_declarator declarator: (identifier) @name) @definition.function 6 | 7 | (type_definition declarator: (type_identifier) @name) @definition.type 8 | 9 | (enum_specifier name: (type_identifier) @name) @definition.type 10 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from os import path 2 | from platform import system 3 | from sysconfig import get_config_var 4 | 5 | from setuptools import Extension, find_packages, setup 6 | from setuptools.command.build import build 7 | from setuptools.command.egg_info import egg_info 8 | from wheel.bdist_wheel import bdist_wheel 9 | 10 | sources = [ 11 | "bindings/python/tree_sitter_c/binding.c", 12 | "src/parser.c", 13 | ] 14 | if path.exists("src/scanner.c"): 15 | sources.append("src/scanner.c") 16 | 17 | macros: list[tuple[str, str | None]] = [ 18 | ("PY_SSIZE_T_CLEAN", None), 19 | ("TREE_SITTER_HIDE_SYMBOLS", None), 20 | ] 21 | if limited_api := not get_config_var("Py_GIL_DISABLED"): 22 | macros.append(("Py_LIMITED_API", "0x030A0000")) 23 | 24 | if system() != "Windows": 25 | cflags = ["-std=c11", "-fvisibility=hidden"] 26 | else: 27 | cflags = ["/std:c11", "/utf-8"] 28 | 29 | 30 | class Build(build): 31 | def run(self): 32 | if path.isdir("queries"): 33 | dest = path.join(self.build_lib, "tree_sitter_c", "queries") 34 | self.copy_tree("queries", dest) 35 | super().run() 36 | 37 | 38 | class BdistWheel(bdist_wheel): 39 | def get_tag(self): 40 | python, abi, platform = super().get_tag() 41 | if python.startswith("cp"): 42 | python, abi = "cp310", "abi3" 43 | return python, abi, platform 44 | 45 | 46 | class EggInfo(egg_info): 47 | def find_sources(self): 48 | super().find_sources() 49 | self.filelist.recursive_include("queries", "*.scm") 50 | self.filelist.include("src/tree_sitter/*.h") 51 | 52 | 53 | setup( 54 | packages=find_packages("bindings/python"), 55 | package_dir={"": "bindings/python"}, 56 | package_data={ 57 | "tree_sitter_c": ["*.pyi", "py.typed"], 58 | "tree_sitter_c.queries": ["*.scm"], 59 | }, 60 | ext_package="tree_sitter_c", 61 | ext_modules=[ 62 | Extension( 63 | name="_binding", 64 | sources=sources, 65 | extra_compile_args=cflags, 66 | define_macros=macros, 67 | include_dirs=["src"], 68 | py_limited_api=limited_api, 69 | ) 70 | ], 71 | cmdclass={ 72 | "build": Build, 73 | "bdist_wheel": BdistWheel, 74 | "egg_info": EggInfo, 75 | }, 76 | zip_safe=False 77 | ) 78 | -------------------------------------------------------------------------------- /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 { 22 | uint8_t major_version; 23 | uint8_t minor_version; 24 | uint8_t patch_version; 25 | } TSLanguageMetadata; 26 | #endif 27 | 28 | typedef struct { 29 | TSFieldId field_id; 30 | uint8_t child_index; 31 | bool inherited; 32 | } TSFieldMapEntry; 33 | 34 | // Used to index the field and supertype maps. 35 | typedef struct { 36 | uint16_t index; 37 | uint16_t length; 38 | } TSMapSlice; 39 | 40 | typedef struct { 41 | bool visible; 42 | bool named; 43 | bool supertype; 44 | } TSSymbolMetadata; 45 | 46 | typedef struct TSLexer TSLexer; 47 | 48 | struct TSLexer { 49 | int32_t lookahead; 50 | TSSymbol result_symbol; 51 | void (*advance)(TSLexer *, bool); 52 | void (*mark_end)(TSLexer *); 53 | uint32_t (*get_column)(TSLexer *); 54 | bool (*is_at_included_range_start)(const TSLexer *); 55 | bool (*eof)(const TSLexer *); 56 | void (*log)(const TSLexer *, const char *, ...); 57 | }; 58 | 59 | typedef enum { 60 | TSParseActionTypeShift, 61 | TSParseActionTypeReduce, 62 | TSParseActionTypeAccept, 63 | TSParseActionTypeRecover, 64 | } TSParseActionType; 65 | 66 | typedef union { 67 | struct { 68 | uint8_t type; 69 | TSStateId state; 70 | bool extra; 71 | bool repetition; 72 | } shift; 73 | struct { 74 | uint8_t type; 75 | uint8_t child_count; 76 | TSSymbol symbol; 77 | int16_t dynamic_precedence; 78 | uint16_t production_id; 79 | } reduce; 80 | uint8_t type; 81 | } TSParseAction; 82 | 83 | typedef struct { 84 | uint16_t lex_state; 85 | uint16_t external_lex_state; 86 | } TSLexMode; 87 | 88 | typedef struct { 89 | uint16_t lex_state; 90 | uint16_t external_lex_state; 91 | uint16_t reserved_word_set_id; 92 | } TSLexerMode; 93 | 94 | typedef union { 95 | TSParseAction action; 96 | struct { 97 | uint8_t count; 98 | bool reusable; 99 | } entry; 100 | } TSParseActionEntry; 101 | 102 | typedef struct { 103 | int32_t start; 104 | int32_t end; 105 | } TSCharacterRange; 106 | 107 | struct TSLanguage { 108 | uint32_t abi_version; 109 | uint32_t symbol_count; 110 | uint32_t alias_count; 111 | uint32_t token_count; 112 | uint32_t external_token_count; 113 | uint32_t state_count; 114 | uint32_t large_state_count; 115 | uint32_t production_id_count; 116 | uint32_t field_count; 117 | uint16_t max_alias_sequence_length; 118 | const uint16_t *parse_table; 119 | const uint16_t *small_parse_table; 120 | const uint32_t *small_parse_table_map; 121 | const TSParseActionEntry *parse_actions; 122 | const char * const *symbol_names; 123 | const char * const *field_names; 124 | const TSMapSlice *field_map_slices; 125 | const TSFieldMapEntry *field_map_entries; 126 | const TSSymbolMetadata *symbol_metadata; 127 | const TSSymbol *public_symbol_map; 128 | const uint16_t *alias_map; 129 | const TSSymbol *alias_sequences; 130 | const TSLexerMode *lex_modes; 131 | bool (*lex_fn)(TSLexer *, TSStateId); 132 | bool (*keyword_lex_fn)(TSLexer *, TSStateId); 133 | TSSymbol keyword_capture_token; 134 | struct { 135 | const bool *states; 136 | const TSSymbol *symbol_map; 137 | void *(*create)(void); 138 | void (*destroy)(void *); 139 | bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist); 140 | unsigned (*serialize)(void *, char *); 141 | void (*deserialize)(void *, const char *, unsigned); 142 | } external_scanner; 143 | const TSStateId *primary_state_ids; 144 | const char *name; 145 | const TSSymbol *reserved_words; 146 | uint16_t max_reserved_word_set_size; 147 | uint32_t supertype_count; 148 | const TSSymbol *supertype_symbols; 149 | const TSMapSlice *supertype_map_slices; 150 | const TSSymbol *supertype_map_entries; 151 | TSLanguageMetadata metadata; 152 | }; 153 | 154 | static inline bool set_contains(const TSCharacterRange *ranges, uint32_t len, int32_t lookahead) { 155 | uint32_t index = 0; 156 | uint32_t size = len - index; 157 | while (size > 1) { 158 | uint32_t half_size = size / 2; 159 | uint32_t mid_index = index + half_size; 160 | const TSCharacterRange *range = &ranges[mid_index]; 161 | if (lookahead >= range->start && lookahead <= range->end) { 162 | return true; 163 | } else if (lookahead > range->end) { 164 | index = mid_index; 165 | } 166 | size -= half_size; 167 | } 168 | const TSCharacterRange *range = &ranges[index]; 169 | return (lookahead >= range->start && lookahead <= range->end); 170 | } 171 | 172 | /* 173 | * Lexer Macros 174 | */ 175 | 176 | #ifdef _MSC_VER 177 | #define UNUSED __pragma(warning(suppress : 4101)) 178 | #else 179 | #define UNUSED __attribute__((unused)) 180 | #endif 181 | 182 | #define START_LEXER() \ 183 | bool result = false; \ 184 | bool skip = false; \ 185 | UNUSED \ 186 | bool eof = false; \ 187 | int32_t lookahead; \ 188 | goto start; \ 189 | next_state: \ 190 | lexer->advance(lexer, skip); \ 191 | start: \ 192 | skip = false; \ 193 | lookahead = lexer->lookahead; 194 | 195 | #define ADVANCE(state_value) \ 196 | { \ 197 | state = state_value; \ 198 | goto next_state; \ 199 | } 200 | 201 | #define ADVANCE_MAP(...) \ 202 | { \ 203 | static const uint16_t map[] = { __VA_ARGS__ }; \ 204 | for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \ 205 | if (map[i] == lookahead) { \ 206 | state = map[i + 1]; \ 207 | goto next_state; \ 208 | } \ 209 | } \ 210 | } 211 | 212 | #define SKIP(state_value) \ 213 | { \ 214 | skip = true; \ 215 | state = state_value; \ 216 | goto next_state; \ 217 | } 218 | 219 | #define ACCEPT_TOKEN(symbol_value) \ 220 | result = true; \ 221 | lexer->result_symbol = symbol_value; \ 222 | lexer->mark_end(lexer); 223 | 224 | #define END_STATE() return result; 225 | 226 | /* 227 | * Parse Table Macros 228 | */ 229 | 230 | #define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT) 231 | 232 | #define STATE(id) id 233 | 234 | #define ACTIONS(id) id 235 | 236 | #define SHIFT(state_value) \ 237 | {{ \ 238 | .shift = { \ 239 | .type = TSParseActionTypeShift, \ 240 | .state = (state_value) \ 241 | } \ 242 | }} 243 | 244 | #define SHIFT_REPEAT(state_value) \ 245 | {{ \ 246 | .shift = { \ 247 | .type = TSParseActionTypeShift, \ 248 | .state = (state_value), \ 249 | .repetition = true \ 250 | } \ 251 | }} 252 | 253 | #define SHIFT_EXTRA() \ 254 | {{ \ 255 | .shift = { \ 256 | .type = TSParseActionTypeShift, \ 257 | .extra = true \ 258 | } \ 259 | }} 260 | 261 | #define REDUCE(symbol_name, children, precedence, prod_id) \ 262 | {{ \ 263 | .reduce = { \ 264 | .type = TSParseActionTypeReduce, \ 265 | .symbol = symbol_name, \ 266 | .child_count = children, \ 267 | .dynamic_precedence = precedence, \ 268 | .production_id = prod_id \ 269 | }, \ 270 | }} 271 | 272 | #define RECOVER() \ 273 | {{ \ 274 | .type = TSParseActionTypeRecover \ 275 | }} 276 | 277 | #define ACCEPT_INPUT() \ 278 | {{ \ 279 | .type = TSParseActionTypeAccept \ 280 | }} 281 | 282 | #ifdef __cplusplus 283 | } 284 | #endif 285 | 286 | #endif // TREE_SITTER_PARSER_H_ 287 | -------------------------------------------------------------------------------- /test/corpus/ambiguities.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | pointer declarations vs expressions 3 | ================================================================================ 4 | 5 | TSLanguage *(*lang_parser)(void); 6 | 7 | char (*ptr_to_array)[]; 8 | 9 | int main() { 10 | // declare a function pointer 11 | T1 * b(T2 a); 12 | 13 | // evaluate expressions 14 | c * d(5); 15 | e(f * g); 16 | } 17 | 18 | -------------------------------------------------------------------------------- 19 | 20 | (translation_unit 21 | (declaration 22 | (type_identifier) 23 | (pointer_declarator 24 | (function_declarator 25 | (parenthesized_declarator 26 | (pointer_declarator 27 | (identifier))) 28 | (parameter_list 29 | (parameter_declaration 30 | (primitive_type)))))) 31 | (declaration 32 | (primitive_type) 33 | (array_declarator 34 | (parenthesized_declarator 35 | (pointer_declarator 36 | (identifier))))) 37 | (function_definition 38 | (primitive_type) 39 | (function_declarator 40 | (identifier) 41 | (parameter_list)) 42 | (compound_statement 43 | (comment) 44 | (declaration 45 | (type_identifier) 46 | (pointer_declarator 47 | (function_declarator 48 | (identifier) 49 | (parameter_list 50 | (parameter_declaration 51 | (type_identifier) 52 | (identifier)))))) 53 | (comment) 54 | (expression_statement 55 | (binary_expression 56 | (identifier) 57 | (call_expression 58 | (identifier) 59 | (argument_list 60 | (number_literal))))) 61 | (expression_statement 62 | (call_expression 63 | (identifier) 64 | (argument_list 65 | (binary_expression 66 | (identifier) 67 | (identifier)))))))) 68 | 69 | ================================================================================ 70 | casts vs multiplications 71 | ================================================================================ 72 | 73 | /* 74 | * ambiguities 75 | */ 76 | 77 | int main() { 78 | // cast 79 | a((B *)c); 80 | 81 | // parenthesized product 82 | d((e * f)); 83 | } 84 | 85 | -------------------------------------------------------------------------------- 86 | 87 | (translation_unit 88 | (comment) 89 | (function_definition 90 | (primitive_type) 91 | (function_declarator 92 | (identifier) 93 | (parameter_list)) 94 | (compound_statement 95 | (comment) 96 | (expression_statement 97 | (call_expression 98 | (identifier) 99 | (argument_list 100 | (cast_expression 101 | (type_descriptor 102 | (type_identifier) 103 | (abstract_pointer_declarator)) 104 | (identifier))))) 105 | (comment) 106 | (expression_statement 107 | (call_expression 108 | (identifier) 109 | (argument_list 110 | (parenthesized_expression 111 | (binary_expression 112 | (identifier) 113 | (identifier))))))))) 114 | 115 | ================================================================================ 116 | function-like type macros vs function calls 117 | ================================================================================ 118 | 119 | // this is a macro 120 | GIT_INLINE(int *) x = 5; 121 | 122 | -------------------------------------------------------------------------------- 123 | 124 | (translation_unit 125 | (comment) 126 | (declaration 127 | (macro_type_specifier 128 | (identifier) 129 | (type_descriptor 130 | (primitive_type) 131 | (abstract_pointer_declarator))) 132 | (init_declarator 133 | (identifier) 134 | (number_literal)))) 135 | 136 | ================================================================================ 137 | function calls vs parenthesized declarators vs macro types 138 | ================================================================================ 139 | 140 | int main() { 141 | /* 142 | * Could be either: 143 | * - function call 144 | * - declaration w/ parenthesized declarator 145 | * - declaration w/ macro type, no declarator 146 | */ 147 | ABC(d); 148 | 149 | /* 150 | * Normal declaration 151 | */ 152 | efg hij; 153 | } 154 | 155 | -------------------------------------------------------------------------------- 156 | 157 | (translation_unit 158 | (function_definition 159 | (primitive_type) 160 | (function_declarator 161 | (identifier) 162 | (parameter_list)) 163 | (compound_statement 164 | (comment) 165 | (expression_statement 166 | (call_expression 167 | (identifier) 168 | (argument_list 169 | (identifier)))) 170 | (comment) 171 | (declaration 172 | (type_identifier) 173 | (identifier))))) 174 | 175 | ================================================================================ 176 | Call expressions vs empty declarations w/ macros as types 177 | ================================================================================ 178 | 179 | int main() { 180 | int a = 1; 181 | b(a); 182 | A(A *); 183 | } 184 | 185 | -------------------------------------------------------------------------------- 186 | 187 | (translation_unit 188 | (function_definition 189 | (primitive_type) 190 | (function_declarator 191 | (identifier) 192 | (parameter_list)) 193 | (compound_statement 194 | (declaration 195 | (primitive_type) 196 | (init_declarator 197 | (identifier) 198 | (number_literal))) 199 | (expression_statement 200 | (call_expression 201 | (identifier) 202 | (argument_list 203 | (identifier)))) 204 | (macro_type_specifier 205 | (identifier) 206 | (type_descriptor 207 | (type_identifier) 208 | (abstract_pointer_declarator)))))) 209 | 210 | ================================================================================ 211 | Comments after for loops with ambiguities 212 | ================================================================================ 213 | 214 | int main() { 215 | for (a *b = c; d; e) { 216 | aff; 217 | } 218 | 219 | // a-comment 220 | 221 | g; 222 | } 223 | 224 | -------------------------------------------------------------------------------- 225 | 226 | (translation_unit 227 | (function_definition 228 | (primitive_type) 229 | (function_declarator 230 | (identifier) 231 | (parameter_list)) 232 | (compound_statement 233 | (for_statement 234 | (declaration 235 | (type_identifier) 236 | (init_declarator 237 | (pointer_declarator 238 | (identifier)) 239 | (identifier))) 240 | (identifier) 241 | (identifier) 242 | (compound_statement 243 | (expression_statement 244 | (identifier)))) 245 | (comment) 246 | (expression_statement 247 | (identifier))))) 248 | 249 | ================================================================================ 250 | Top-level macro invocations 251 | ================================================================================ 252 | 253 | DEFINE_SOMETHING(THING_A, "this is a thing a"); 254 | DEFINE_SOMETHING(THING_B, "this is a thing b", "thanks"); 255 | 256 | -------------------------------------------------------------------------------- 257 | 258 | (translation_unit 259 | (expression_statement 260 | (call_expression 261 | (identifier) 262 | (argument_list 263 | (identifier) 264 | (string_literal 265 | (string_content))))) 266 | (expression_statement 267 | (call_expression 268 | (identifier) 269 | (argument_list 270 | (identifier) 271 | (string_literal 272 | (string_content)) 273 | (string_literal 274 | (string_content)))))) 275 | -------------------------------------------------------------------------------- /test/corpus/crlf.txt: -------------------------------------------------------------------------------- 1 | ============================================ 2 | Line comments with escaped CRLF line endings 3 | ============================================ 4 | 5 | // hello \ 6 | this is still a comment 7 | this_is_not a_comment; 8 | 9 | --- 10 | 11 | (translation_unit 12 | (comment) 13 | (declaration (type_identifier) (identifier))) 14 | -------------------------------------------------------------------------------- /test/corpus/declarations.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | Struct declarations 3 | ================================================================================ 4 | 5 | struct s1; 6 | 7 | struct s2 { 8 | int x; 9 | float y : 5; 10 | }; 11 | 12 | struct s3 { 13 | int x : 1, y : 2; 14 | }; 15 | 16 | -------------------------------------------------------------------------------- 17 | 18 | (translation_unit 19 | (struct_specifier 20 | name: (type_identifier)) 21 | (struct_specifier 22 | name: (type_identifier) 23 | body: (field_declaration_list 24 | (field_declaration 25 | type: (primitive_type) 26 | declarator: (field_identifier)) 27 | (field_declaration 28 | type: (primitive_type) 29 | declarator: (field_identifier) 30 | (bitfield_clause 31 | (number_literal))))) 32 | (struct_specifier 33 | name: (type_identifier) 34 | body: (field_declaration_list 35 | (field_declaration 36 | type: (primitive_type) 37 | declarator: (field_identifier) 38 | (bitfield_clause 39 | (number_literal)) 40 | declarator: (field_identifier) 41 | (bitfield_clause 42 | (number_literal)))))) 43 | 44 | ================================================================================ 45 | Union declarations 46 | ================================================================================ 47 | 48 | union u1; 49 | 50 | union s2 { 51 | int x; 52 | float y; 53 | }; 54 | 55 | -------------------------------------------------------------------------------- 56 | 57 | (translation_unit 58 | (union_specifier 59 | name: (type_identifier)) 60 | (union_specifier 61 | name: (type_identifier) 62 | body: (field_declaration_list 63 | (field_declaration 64 | type: (primitive_type) 65 | declarator: (field_identifier)) 66 | (field_declaration 67 | type: (primitive_type) 68 | declarator: (field_identifier))))) 69 | 70 | ================================================================================ 71 | Enum declarations 72 | ================================================================================ 73 | 74 | enum e1; 75 | 76 | enum e2 { 77 | val1, 78 | val2 = 5, 79 | val3 80 | }; 81 | 82 | enum e3 { 83 | val1, 84 | }; 85 | 86 | enum e4: int { 87 | #ifdef A 88 | val1 = 'hey', 89 | #else 90 | val1 = 'ho', 91 | #endif 92 | 93 | #if HEY 94 | val2 = 'hey', 95 | #else 96 | val2 = 'ho', 97 | #endif 98 | }; 99 | 100 | -------------------------------------------------------------------------------- 101 | 102 | (translation_unit 103 | (enum_specifier 104 | name: (type_identifier)) 105 | (enum_specifier 106 | name: (type_identifier) 107 | body: (enumerator_list 108 | (enumerator 109 | name: (identifier)) 110 | (enumerator 111 | name: (identifier) 112 | value: (number_literal)) 113 | (enumerator 114 | name: (identifier)))) 115 | (enum_specifier 116 | name: (type_identifier) 117 | body: (enumerator_list 118 | (enumerator 119 | name: (identifier)))) 120 | (enum_specifier 121 | name: (type_identifier) 122 | underlying_type: (primitive_type) 123 | body: (enumerator_list 124 | (preproc_ifdef 125 | name: (identifier) 126 | (enumerator 127 | name: (identifier) 128 | value: (char_literal 129 | (character) 130 | (character) 131 | (character))) 132 | alternative: (preproc_else 133 | (enumerator 134 | name: (identifier) 135 | value: (char_literal 136 | (character) 137 | (character))))) 138 | (preproc_if 139 | condition: (identifier) 140 | (enumerator 141 | name: (identifier) 142 | value: (char_literal 143 | (character) 144 | (character) 145 | (character))) 146 | alternative: (preproc_else 147 | (enumerator 148 | name: (identifier) 149 | value: (char_literal 150 | (character) 151 | (character)))))))) 152 | 153 | ================================================================================ 154 | Struct declarations containing preprocessor directives 155 | ================================================================================ 156 | 157 | struct s { 158 | #define A 5 159 | int b[a]; 160 | #undef A 161 | }; 162 | 163 | -------------------------------------------------------------------------------- 164 | 165 | (translation_unit 166 | (struct_specifier 167 | (type_identifier) 168 | (field_declaration_list 169 | (preproc_def 170 | (identifier) 171 | (preproc_arg)) 172 | (field_declaration 173 | (primitive_type) 174 | (array_declarator 175 | (field_identifier) 176 | (identifier))) 177 | (preproc_call 178 | (preproc_directive) 179 | (preproc_arg))))) 180 | 181 | ================================================================================ 182 | Primitive-typed variable declarations 183 | ================================================================================ 184 | 185 | unsigned short int a; 186 | long int b, c = 5, d; 187 | float d, e; 188 | unsigned f; 189 | short g, h; 190 | int unsigned short i; 191 | unsigned int long j; 192 | 193 | -------------------------------------------------------------------------------- 194 | 195 | (translation_unit 196 | (declaration 197 | type: (sized_type_specifier 198 | type: (primitive_type)) 199 | declarator: (identifier)) 200 | (declaration 201 | type: (sized_type_specifier 202 | type: (primitive_type)) 203 | declarator: (identifier) 204 | declarator: (init_declarator 205 | declarator: (identifier) 206 | value: (number_literal)) 207 | declarator: (identifier)) 208 | (declaration 209 | type: (primitive_type) 210 | declarator: (identifier) 211 | declarator: (identifier)) 212 | (declaration 213 | type: (sized_type_specifier) 214 | declarator: (identifier)) 215 | (declaration 216 | type: (sized_type_specifier) 217 | declarator: (identifier) 218 | declarator: (identifier)) 219 | (declaration 220 | type: (sized_type_specifier 221 | type: (primitive_type)) 222 | declarator: (identifier)) 223 | (declaration 224 | type: (sized_type_specifier 225 | type: (primitive_type)) 226 | declarator: (identifier))) 227 | 228 | ================================================================================ 229 | Variable storage classes 230 | ================================================================================ 231 | 232 | int a; 233 | extern int b, c; 234 | auto int d; 235 | register int e; 236 | static int f; 237 | register uint64_t rd_ asm("x" "10"); 238 | 239 | -------------------------------------------------------------------------------- 240 | 241 | (translation_unit 242 | (declaration 243 | (primitive_type) 244 | (identifier)) 245 | (declaration 246 | (storage_class_specifier) 247 | (primitive_type) 248 | (identifier) 249 | (identifier)) 250 | (declaration 251 | (storage_class_specifier) 252 | (primitive_type) 253 | (identifier)) 254 | (declaration 255 | (storage_class_specifier) 256 | (primitive_type) 257 | (identifier)) 258 | (declaration 259 | (storage_class_specifier) 260 | (primitive_type) 261 | (identifier)) 262 | (declaration 263 | (storage_class_specifier) 264 | (primitive_type) 265 | (identifier) 266 | (gnu_asm_expression 267 | (concatenated_string 268 | (string_literal 269 | (string_content)) 270 | (string_literal 271 | (string_content)))))) 272 | 273 | ================================================================================ 274 | Composite-typed variable declarations 275 | ================================================================================ 276 | 277 | struct b c; 278 | union { int e; } f; 279 | enum { g, h } i; 280 | 281 | -------------------------------------------------------------------------------- 282 | 283 | (translation_unit 284 | (declaration 285 | type: (struct_specifier 286 | name: (type_identifier)) 287 | declarator: (identifier)) 288 | (declaration 289 | type: (union_specifier 290 | body: (field_declaration_list 291 | (field_declaration 292 | type: (primitive_type) 293 | declarator: (field_identifier)))) 294 | declarator: (identifier)) 295 | (declaration 296 | type: (enum_specifier 297 | body: (enumerator_list 298 | (enumerator 299 | name: (identifier)) 300 | (enumerator 301 | name: (identifier)))) 302 | declarator: (identifier))) 303 | 304 | ================================================================================ 305 | Pointer variable declarations 306 | ================================================================================ 307 | 308 | char *the_string; 309 | const char **the_strings; 310 | int const * const restrict x; 311 | 312 | -------------------------------------------------------------------------------- 313 | 314 | (translation_unit 315 | (declaration 316 | type: (primitive_type) 317 | declarator: (pointer_declarator 318 | declarator: (identifier))) 319 | (declaration 320 | (type_qualifier) 321 | type: (primitive_type) 322 | declarator: (pointer_declarator 323 | declarator: (pointer_declarator 324 | declarator: (identifier)))) 325 | (declaration 326 | type: (primitive_type) 327 | (type_qualifier) 328 | declarator: (pointer_declarator 329 | (type_qualifier) 330 | (type_qualifier) 331 | declarator: (identifier)))) 332 | 333 | ================================================================================ 334 | Typedefs 335 | ================================================================================ 336 | 337 | typedef int my_int; 338 | 339 | typedef struct { 340 | int x; 341 | } *a; 342 | 343 | typedef void my_callback(void *, size_t); 344 | 345 | typedef struct A { 346 | int i; 347 | } a, b; 348 | 349 | typedef void const *voidpc; 350 | typedef void volatile *voidpv; 351 | typedef void const volatile *const voidpcv; 352 | 353 | typedef unsigned long int; 354 | typedef unsigned short ptrdiff_t; 355 | typedef short charptr_t; 356 | typedef unsigned nullptr_t; 357 | typedef signed max_align_t; 358 | 359 | typedef unsigned long ulong_t; 360 | typedef long long_t; 361 | typedef unsigned short ushort_t; 362 | typedef short short_t; 363 | typedef unsigned unsigned_t; 364 | typedef signed signed_t; 365 | 366 | typedef long long; 367 | typedef short short; 368 | typedef unsigned int uint; 369 | typedef unsigned short ushort; 370 | typedef unsigned unsigned short; 371 | typedef signed signed short; 372 | typedef signed signed unsigned; 373 | typedef unsigned long int long ull; 374 | 375 | typedef int register_t __attribute__((__mode__(__word__))); 376 | 377 | __extension__ typedef long int greg_t; 378 | 379 | __extension__ typedef struct { 380 | long long int quot; 381 | long long int rem; 382 | } lldiv_t; 383 | 384 | -------------------------------------------------------------------------------- 385 | 386 | (translation_unit 387 | (type_definition 388 | type: (primitive_type) 389 | declarator: (type_identifier)) 390 | (type_definition 391 | type: (struct_specifier 392 | body: (field_declaration_list 393 | (field_declaration 394 | type: (primitive_type) 395 | declarator: (field_identifier)))) 396 | declarator: (pointer_declarator 397 | declarator: (type_identifier))) 398 | (type_definition 399 | type: (primitive_type) 400 | declarator: (function_declarator 401 | declarator: (type_identifier) 402 | parameters: (parameter_list 403 | (parameter_declaration 404 | type: (primitive_type) 405 | declarator: (abstract_pointer_declarator)) 406 | (parameter_declaration 407 | type: (primitive_type))))) 408 | (type_definition 409 | type: (struct_specifier 410 | name: (type_identifier) 411 | body: (field_declaration_list 412 | (field_declaration 413 | type: (primitive_type) 414 | declarator: (field_identifier)))) 415 | declarator: (type_identifier) 416 | declarator: (type_identifier)) 417 | (type_definition 418 | type: (primitive_type) 419 | (type_qualifier) 420 | declarator: (pointer_declarator 421 | declarator: (type_identifier))) 422 | (type_definition 423 | type: (primitive_type) 424 | (type_qualifier) 425 | declarator: (pointer_declarator 426 | declarator: (type_identifier))) 427 | (type_definition 428 | type: (primitive_type) 429 | (type_qualifier) 430 | (type_qualifier) 431 | declarator: (pointer_declarator 432 | (type_qualifier) 433 | declarator: (type_identifier))) 434 | (type_definition 435 | type: (sized_type_specifier) 436 | declarator: (primitive_type)) 437 | (type_definition 438 | type: (sized_type_specifier) 439 | declarator: (primitive_type)) 440 | (type_definition 441 | type: (sized_type_specifier) 442 | declarator: (primitive_type)) 443 | (type_definition 444 | type: (sized_type_specifier) 445 | declarator: (primitive_type)) 446 | (type_definition 447 | type: (sized_type_specifier) 448 | declarator: (primitive_type)) 449 | (type_definition 450 | type: (sized_type_specifier) 451 | declarator: (type_identifier)) 452 | (type_definition 453 | type: (sized_type_specifier) 454 | declarator: (type_identifier)) 455 | (type_definition 456 | type: (sized_type_specifier) 457 | declarator: (type_identifier)) 458 | (type_definition 459 | type: (sized_type_specifier) 460 | declarator: (type_identifier)) 461 | (type_definition 462 | type: (sized_type_specifier) 463 | declarator: (type_identifier)) 464 | (type_definition 465 | type: (sized_type_specifier) 466 | declarator: (type_identifier)) 467 | (type_definition 468 | type: (sized_type_specifier) 469 | declarator: (primitive_type)) 470 | (type_definition 471 | type: (sized_type_specifier) 472 | declarator: (primitive_type)) 473 | (type_definition 474 | type: (sized_type_specifier 475 | type: (primitive_type)) 476 | declarator: (type_identifier)) 477 | (type_definition 478 | type: (sized_type_specifier) 479 | declarator: (type_identifier)) 480 | (type_definition 481 | type: (sized_type_specifier) 482 | declarator: (primitive_type)) 483 | (type_definition 484 | type: (sized_type_specifier) 485 | declarator: (primitive_type)) 486 | (type_definition 487 | type: (sized_type_specifier) 488 | declarator: (primitive_type)) 489 | (type_definition 490 | type: (sized_type_specifier 491 | type: (primitive_type)) 492 | declarator: (type_identifier)) 493 | (type_definition 494 | type: (primitive_type) 495 | declarator: (type_identifier) 496 | (attribute_specifier 497 | (argument_list 498 | (call_expression 499 | function: (identifier) 500 | arguments: (argument_list 501 | (identifier)))))) 502 | (type_definition 503 | type: (sized_type_specifier 504 | type: (primitive_type)) 505 | declarator: (type_identifier)) 506 | (type_definition 507 | type: (struct_specifier 508 | body: (field_declaration_list 509 | (field_declaration 510 | type: (sized_type_specifier 511 | type: (primitive_type)) 512 | declarator: (field_identifier)) 513 | (field_declaration 514 | type: (sized_type_specifier 515 | type: (primitive_type)) 516 | declarator: (field_identifier)))) 517 | declarator: (type_identifier))) 518 | 519 | ================================================================================ 520 | Function declarations 521 | ================================================================================ 522 | 523 | int main(int argc, const char **argv); 524 | static foo bar(); 525 | static baz quux(...); 526 | 527 | -------------------------------------------------------------------------------- 528 | 529 | (translation_unit 530 | (declaration 531 | (primitive_type) 532 | (function_declarator 533 | (identifier) 534 | (parameter_list 535 | (parameter_declaration 536 | (primitive_type) 537 | (identifier)) 538 | (parameter_declaration 539 | (type_qualifier) 540 | (primitive_type) 541 | (pointer_declarator 542 | (pointer_declarator 543 | (identifier))))))) 544 | (declaration 545 | (storage_class_specifier) 546 | (type_identifier) 547 | (function_declarator 548 | (identifier) 549 | (parameter_list))) 550 | (declaration 551 | (storage_class_specifier) 552 | (type_identifier) 553 | (function_declarator 554 | (identifier) 555 | (parameter_list 556 | (variadic_parameter))))) 557 | 558 | ================================================================================ 559 | Function definitions 560 | ================================================================================ 561 | 562 | void * do_stuff(int arg1) { 563 | return 5; 564 | } 565 | 566 | // K&R style 567 | int foo(bar, baz, qux) 568 | int bar, baz; 569 | char *qux; 570 | { 571 | } 572 | 573 | -------------------------------------------------------------------------------- 574 | 575 | (translation_unit 576 | (function_definition 577 | type: (primitive_type) 578 | declarator: (pointer_declarator 579 | declarator: (function_declarator 580 | declarator: (identifier) 581 | parameters: (parameter_list 582 | (parameter_declaration 583 | type: (primitive_type) 584 | declarator: (identifier))))) 585 | body: (compound_statement 586 | (return_statement 587 | (number_literal)))) 588 | (comment) 589 | (function_definition 590 | type: (primitive_type) 591 | declarator: (function_declarator 592 | declarator: (identifier) 593 | parameters: (parameter_list 594 | (identifier) 595 | (identifier) 596 | (identifier))) 597 | (declaration 598 | type: (primitive_type) 599 | declarator: (identifier) 600 | declarator: (identifier)) 601 | (declaration 602 | type: (primitive_type) 603 | declarator: (pointer_declarator 604 | declarator: (identifier))) 605 | body: (compound_statement))) 606 | 607 | ================================================================================ 608 | Function specifiers after types 609 | ================================================================================ 610 | 611 | int static inline do_stuff(int arg1) { 612 | return 5; 613 | } 614 | 615 | -------------------------------------------------------------------------------- 616 | 617 | (translation_unit 618 | (function_definition 619 | (primitive_type) 620 | (storage_class_specifier) 621 | (storage_class_specifier) 622 | (function_declarator 623 | (identifier) 624 | (parameter_list 625 | (parameter_declaration 626 | (primitive_type) 627 | (identifier)))) 628 | (compound_statement 629 | (return_statement 630 | (number_literal))))) 631 | 632 | ================================================================================ 633 | Function definitions with macro attributes 634 | ================================================================================ 635 | 636 | void * do_stuff(int arg1) 637 | SOME_ATTR 638 | SOME_ATTR(1) 639 | { 640 | return 5; 641 | } 642 | 643 | -------------------------------------------------------------------------------- 644 | 645 | (translation_unit 646 | (function_definition 647 | type: (primitive_type) 648 | declarator: (pointer_declarator 649 | declarator: (function_declarator 650 | declarator: (identifier) 651 | parameters: (parameter_list 652 | (parameter_declaration 653 | type: (primitive_type) 654 | declarator: (identifier))) 655 | (identifier) 656 | (call_expression 657 | function: (identifier) 658 | arguments: (argument_list 659 | (number_literal))))) 660 | body: (compound_statement 661 | (return_statement 662 | (number_literal))))) 663 | 664 | ================================================================================ 665 | Linkage specifications 666 | ================================================================================ 667 | 668 | extern "C" int foo(); 669 | 670 | extern "C" int foo() { return 0; } 671 | 672 | extern "C" { 673 | int bar(); 674 | int baz(); 675 | } 676 | 677 | -------------------------------------------------------------------------------- 678 | 679 | (translation_unit 680 | (linkage_specification 681 | (string_literal 682 | (string_content)) 683 | (declaration 684 | (primitive_type) 685 | (function_declarator 686 | (identifier) 687 | (parameter_list)))) 688 | (linkage_specification 689 | (string_literal 690 | (string_content)) 691 | (function_definition 692 | (primitive_type) 693 | (function_declarator 694 | (identifier) 695 | (parameter_list)) 696 | (compound_statement 697 | (return_statement 698 | (number_literal))))) 699 | (linkage_specification 700 | (string_literal 701 | (string_content)) 702 | (declaration_list 703 | (declaration 704 | (primitive_type) 705 | (function_declarator 706 | (identifier) 707 | (parameter_list))) 708 | (declaration 709 | (primitive_type) 710 | (function_declarator 711 | (identifier) 712 | (parameter_list)))))) 713 | 714 | ================================================================================ 715 | Type qualifiers 716 | ================================================================================ 717 | 718 | const _Atomic unsigned long int x = 5; 719 | restrict int y = 6; 720 | volatile int z = 7; 721 | constexpr int a = 8; 722 | __thread int c = 9; 723 | alignas(16) int i; 724 | _Alignas(int) int j; 725 | noreturn void b() {} 726 | __extension__ extern int ffsll (long long int __ll) 727 | __attribute__ ((__nothrow__ )) __attribute__ ((__const__)); 728 | 729 | -------------------------------------------------------------------------------- 730 | 731 | (translation_unit 732 | (declaration 733 | (type_qualifier) 734 | (type_qualifier) 735 | (sized_type_specifier 736 | (primitive_type)) 737 | (init_declarator 738 | (identifier) 739 | (number_literal))) 740 | (declaration 741 | (type_qualifier) 742 | (primitive_type) 743 | (init_declarator 744 | (identifier) 745 | (number_literal))) 746 | (declaration 747 | (type_qualifier) 748 | (primitive_type) 749 | (init_declarator 750 | (identifier) 751 | (number_literal))) 752 | (declaration 753 | (type_qualifier) 754 | (primitive_type) 755 | (init_declarator 756 | (identifier) 757 | (number_literal))) 758 | (declaration 759 | (storage_class_specifier) 760 | (primitive_type) 761 | (init_declarator 762 | (identifier) 763 | (number_literal))) 764 | (declaration 765 | (type_qualifier 766 | (alignas_qualifier 767 | (number_literal))) 768 | (primitive_type) 769 | (identifier)) 770 | (declaration 771 | (type_qualifier 772 | (alignas_qualifier 773 | (type_descriptor 774 | (primitive_type)))) 775 | (primitive_type) 776 | (identifier)) 777 | (function_definition 778 | (type_qualifier) 779 | (primitive_type) 780 | (function_declarator 781 | (identifier) 782 | (parameter_list)) 783 | (compound_statement)) 784 | (declaration 785 | (type_qualifier) 786 | (storage_class_specifier) 787 | (primitive_type) 788 | (function_declarator 789 | (identifier) 790 | (parameter_list 791 | (parameter_declaration 792 | (sized_type_specifier 793 | (primitive_type)) 794 | (identifier))) 795 | (attribute_specifier 796 | (argument_list 797 | (identifier))) 798 | (attribute_specifier 799 | (argument_list 800 | (identifier)))))) 801 | 802 | ================================================================================ 803 | Local array declarations 804 | ================================================================================ 805 | 806 | int main() { 807 | char the_buffer[the_size]; 808 | char the_other_buffer[*]; 809 | } 810 | 811 | -------------------------------------------------------------------------------- 812 | 813 | (translation_unit 814 | (function_definition 815 | (primitive_type) 816 | (function_declarator 817 | (identifier) 818 | (parameter_list)) 819 | (compound_statement 820 | (declaration 821 | (primitive_type) 822 | (array_declarator 823 | (identifier) 824 | (identifier))) 825 | (declaration 826 | (primitive_type) 827 | (array_declarator 828 | (identifier)))))) 829 | 830 | ================================================================================ 831 | Attributes 832 | ================================================================================ 833 | 834 | extern __attribute__((visibility("hidden"))) int foo(); 835 | extern int bar() __attribute__((const)); 836 | void die(const char *format, ...) __attribute__((noreturn)) 837 | __attribute__((format(printf,1,2))); 838 | extern __attribute__((visibility("default"), weak)) int print_status(); 839 | 840 | extern int strerror_r(int __errnum, char *__buf, 841 | int __buflen) __asm__("" 842 | "__xpg_strerror_r") 843 | __attribute__((__nothrow__)) __attribute__((__nonnull__(2))); 844 | 845 | extern int _IO_vfprintf (_IO_FILE *__restrict, const char *__restrict, 846 | __gnuc_va_list); 847 | 848 | int f([[a::b(c), d]] int x) {} 849 | 850 | [[gnu::always_inline]] [[gnu::hot]] [[gnu::const]] [[nodiscard]] 851 | int g(void); 852 | 853 | [[gnu::always_inline, gnu::hot, gnu::const, nodiscard]] 854 | int g(void); 855 | 856 | int i [[maybe_unused]]; 857 | void f[[gnu::always_inline]](); 858 | 859 | [[nodiscard("reason")]] int foo; 860 | 861 | [[fallthrough]]; 862 | 863 | struct S { 864 | int a [[deprecated]]; 865 | }; 866 | 867 | typedef int MyInt [[deprecated]]; 868 | 869 | struct X { 870 | int a __attribute__((aligned(4))); 871 | } __attribute__((aligned(16))); 872 | 873 | union Y { 874 | int a __attribute__((aligned(4))); 875 | } __attribute__((aligned(16))); 876 | 877 | enum Z { 878 | A 879 | } __attribute__((aligned(16))); 880 | 881 | struct __attribute__((__packed__)) foo_t { 882 | int x; 883 | }; 884 | 885 | -------------------------------------------------------------------------------- 886 | 887 | (translation_unit 888 | (declaration 889 | (storage_class_specifier) 890 | (attribute_specifier 891 | (argument_list 892 | (call_expression 893 | (identifier) 894 | (argument_list 895 | (string_literal 896 | (string_content)))))) 897 | (primitive_type) 898 | (function_declarator 899 | (identifier) 900 | (parameter_list))) 901 | (declaration 902 | (storage_class_specifier) 903 | (primitive_type) 904 | (function_declarator 905 | (identifier) 906 | (parameter_list) 907 | (attribute_specifier 908 | (argument_list 909 | (identifier))))) 910 | (declaration 911 | (primitive_type) 912 | (function_declarator 913 | (identifier) 914 | (parameter_list 915 | (parameter_declaration 916 | (type_qualifier) 917 | (primitive_type) 918 | (pointer_declarator 919 | (identifier))) 920 | (variadic_parameter)) 921 | (attribute_specifier 922 | (argument_list 923 | (identifier))) 924 | (attribute_specifier 925 | (argument_list 926 | (call_expression 927 | (identifier) 928 | (argument_list 929 | (identifier) 930 | (number_literal) 931 | (number_literal))))))) 932 | (declaration 933 | (storage_class_specifier) 934 | (attribute_specifier 935 | (argument_list 936 | (call_expression 937 | (identifier) 938 | (argument_list 939 | (string_literal 940 | (string_content)))) 941 | (identifier))) 942 | (primitive_type) 943 | (function_declarator 944 | (identifier) 945 | (parameter_list))) 946 | (declaration 947 | (storage_class_specifier) 948 | (primitive_type) 949 | (function_declarator 950 | (identifier) 951 | (parameter_list 952 | (parameter_declaration 953 | (primitive_type) 954 | (identifier)) 955 | (parameter_declaration 956 | (primitive_type) 957 | (pointer_declarator 958 | (identifier))) 959 | (parameter_declaration 960 | (primitive_type) 961 | (identifier))) 962 | (gnu_asm_expression 963 | (concatenated_string 964 | (string_literal) 965 | (string_literal 966 | (string_content)))) 967 | (attribute_specifier 968 | (argument_list 969 | (identifier))) 970 | (attribute_specifier 971 | (argument_list 972 | (call_expression 973 | (identifier) 974 | (argument_list 975 | (number_literal))))))) 976 | (declaration 977 | (storage_class_specifier) 978 | (primitive_type) 979 | (function_declarator 980 | (identifier) 981 | (parameter_list 982 | (parameter_declaration 983 | (type_identifier) 984 | (abstract_pointer_declarator 985 | (ms_pointer_modifier 986 | (ms_restrict_modifier)))) 987 | (parameter_declaration 988 | (type_qualifier) 989 | (primitive_type) 990 | (abstract_pointer_declarator 991 | (ms_pointer_modifier 992 | (ms_restrict_modifier)))) 993 | (parameter_declaration 994 | (type_identifier))))) 995 | (function_definition 996 | (primitive_type) 997 | (function_declarator 998 | (identifier) 999 | (parameter_list 1000 | (parameter_declaration 1001 | (attribute_declaration 1002 | (attribute 1003 | (identifier) 1004 | (identifier) 1005 | (argument_list 1006 | (identifier))) 1007 | (attribute 1008 | (identifier))) 1009 | (primitive_type) 1010 | (identifier)))) 1011 | (compound_statement)) 1012 | (declaration 1013 | (attribute_declaration 1014 | (attribute 1015 | (identifier) 1016 | (identifier))) 1017 | (attribute_declaration 1018 | (attribute 1019 | (identifier) 1020 | (identifier))) 1021 | (attribute_declaration 1022 | (attribute 1023 | (identifier) 1024 | (identifier))) 1025 | (attribute_declaration 1026 | (attribute 1027 | (identifier))) 1028 | (primitive_type) 1029 | (function_declarator 1030 | (identifier) 1031 | (parameter_list 1032 | (parameter_declaration 1033 | (primitive_type))))) 1034 | (declaration 1035 | (attribute_declaration 1036 | (attribute 1037 | (identifier) 1038 | (identifier)) 1039 | (attribute 1040 | (identifier) 1041 | (identifier)) 1042 | (attribute 1043 | (identifier) 1044 | (identifier)) 1045 | (attribute 1046 | (identifier))) 1047 | (primitive_type) 1048 | (function_declarator 1049 | (identifier) 1050 | (parameter_list 1051 | (parameter_declaration 1052 | (primitive_type))))) 1053 | (declaration 1054 | (primitive_type) 1055 | (attributed_declarator 1056 | (identifier) 1057 | (attribute_declaration 1058 | (attribute 1059 | (identifier))))) 1060 | (declaration 1061 | (primitive_type) 1062 | (function_declarator 1063 | (attributed_declarator 1064 | (identifier) 1065 | (attribute_declaration 1066 | (attribute 1067 | (identifier) 1068 | (identifier)))) 1069 | (parameter_list))) 1070 | (declaration 1071 | (attribute_declaration 1072 | (attribute 1073 | (identifier) 1074 | (argument_list 1075 | (string_literal 1076 | (string_content))))) 1077 | (primitive_type) 1078 | (identifier)) 1079 | (attributed_statement 1080 | (attribute_declaration 1081 | (attribute 1082 | (identifier))) 1083 | (expression_statement)) 1084 | (struct_specifier 1085 | (type_identifier) 1086 | (field_declaration_list 1087 | (field_declaration 1088 | (primitive_type) 1089 | (attributed_declarator 1090 | (field_identifier) 1091 | (attribute_declaration 1092 | (attribute 1093 | (identifier))))))) 1094 | (type_definition 1095 | (primitive_type) 1096 | (attributed_declarator 1097 | (type_identifier) 1098 | (attribute_declaration 1099 | (attribute 1100 | (identifier))))) 1101 | (struct_specifier 1102 | (type_identifier) 1103 | (field_declaration_list 1104 | (field_declaration 1105 | (primitive_type) 1106 | (field_identifier) 1107 | (attribute_specifier 1108 | (argument_list 1109 | (call_expression 1110 | (identifier) 1111 | (argument_list 1112 | (number_literal))))))) 1113 | (attribute_specifier 1114 | (argument_list 1115 | (call_expression 1116 | (identifier) 1117 | (argument_list 1118 | (number_literal)))))) 1119 | (union_specifier 1120 | (type_identifier) 1121 | (field_declaration_list 1122 | (field_declaration 1123 | (primitive_type) 1124 | (field_identifier) 1125 | (attribute_specifier 1126 | (argument_list 1127 | (call_expression 1128 | (identifier) 1129 | (argument_list 1130 | (number_literal))))))) 1131 | (attribute_specifier 1132 | (argument_list 1133 | (call_expression 1134 | (identifier) 1135 | (argument_list 1136 | (number_literal)))))) 1137 | (enum_specifier 1138 | (type_identifier) 1139 | (enumerator_list 1140 | (enumerator 1141 | (identifier))) 1142 | (attribute_specifier 1143 | (argument_list 1144 | (call_expression 1145 | (identifier) 1146 | (argument_list 1147 | (number_literal)))))) 1148 | (struct_specifier 1149 | (attribute_specifier 1150 | (argument_list 1151 | (identifier))) 1152 | (type_identifier) 1153 | (field_declaration_list 1154 | (field_declaration 1155 | (primitive_type) 1156 | (field_identifier))))) 1157 | 1158 | ================================================================================ 1159 | More Assembly 1160 | ================================================================================ 1161 | 1162 | int main() { 1163 | int var; 1164 | __asm__( 1165 | "nop;" 1166 | : [var] "=r"(var) 1167 | : 1168 | : "eax", "ra" "x" 1169 | ); 1170 | 1171 | asm("addq %2,%0; adcq %3,%1" 1172 | : "+m"(rp[0]), "+d"(high) 1173 | : "r"(c1), "g"(0) 1174 | : "cc" 1175 | ); 1176 | } 1177 | 1178 | 1179 | -------------------------------------------------------------------------------- 1180 | 1181 | (translation_unit 1182 | (function_definition 1183 | (primitive_type) 1184 | (function_declarator 1185 | (identifier) 1186 | (parameter_list)) 1187 | (compound_statement 1188 | (declaration 1189 | (primitive_type) 1190 | (identifier)) 1191 | (expression_statement 1192 | (gnu_asm_expression 1193 | (string_literal 1194 | (string_content)) 1195 | (gnu_asm_output_operand_list 1196 | (gnu_asm_output_operand 1197 | (identifier) 1198 | (string_literal 1199 | (string_content)) 1200 | (identifier))) 1201 | (gnu_asm_input_operand_list) 1202 | (gnu_asm_clobber_list 1203 | (string_literal 1204 | (string_content)) 1205 | (concatenated_string 1206 | (string_literal 1207 | (string_content)) 1208 | (string_literal 1209 | (string_content)))))) 1210 | (expression_statement 1211 | (gnu_asm_expression 1212 | (string_literal 1213 | (string_content)) 1214 | (gnu_asm_output_operand_list 1215 | (gnu_asm_output_operand 1216 | (string_literal 1217 | (string_content)) 1218 | (subscript_expression 1219 | (identifier) 1220 | (number_literal))) 1221 | (gnu_asm_output_operand 1222 | (string_literal 1223 | (string_content)) 1224 | (identifier))) 1225 | (gnu_asm_input_operand_list 1226 | (gnu_asm_input_operand 1227 | (string_literal 1228 | (string_content)) 1229 | (identifier)) 1230 | (gnu_asm_input_operand 1231 | (string_literal 1232 | (string_content)) 1233 | (number_literal))) 1234 | (gnu_asm_clobber_list 1235 | (string_literal 1236 | (string_content)))))))) 1237 | 1238 | ================================================================================ 1239 | Static in Array Declarations 1240 | ================================================================================ 1241 | 1242 | void foo (int a[static 10]); 1243 | 1244 | -------------------------------------------------------------------------------- 1245 | 1246 | (translation_unit 1247 | (declaration 1248 | (primitive_type) 1249 | (function_declarator 1250 | (identifier) 1251 | (parameter_list 1252 | (parameter_declaration 1253 | (primitive_type) 1254 | (array_declarator 1255 | (identifier) 1256 | (number_literal))))))) 1257 | -------------------------------------------------------------------------------- /test/corpus/microsoft.txt: -------------------------------------------------------------------------------- 1 | ================================ 2 | declaration specs 3 | ================================ 4 | 5 | struct __declspec(dllexport) s2 6 | { 7 | }; 8 | 9 | union __declspec(noinline) u2 { 10 | }; 11 | 12 | --- 13 | 14 | (translation_unit 15 | (struct_specifier 16 | (ms_declspec_modifier 17 | (identifier)) 18 | name: (type_identifier) 19 | body: (field_declaration_list)) 20 | (union_specifier 21 | (ms_declspec_modifier 22 | (identifier)) 23 | name: (type_identifier) 24 | body: (field_declaration_list))) 25 | 26 | ================================ 27 | pointers 28 | ================================ 29 | 30 | struct s2 31 | { 32 | int * __restrict x; 33 | int * __sptr psp; 34 | int * __uptr pup; 35 | int * __unaligned pup; 36 | }; 37 | 38 | void sum2(int n, int * __restrict a, int * __restrict b, 39 | int * c, int * d) { 40 | int i; 41 | for (i = 0; i < n; i++) { 42 | a[i] = b[i] + c[i]; 43 | c[i] = b[i] + d[i]; 44 | } 45 | } 46 | 47 | void MyFunction(char * __uptr myValue); 48 | 49 | --- 50 | 51 | (translation_unit 52 | (struct_specifier 53 | name: (type_identifier) 54 | body: (field_declaration_list 55 | (field_declaration 56 | type: (primitive_type) 57 | declarator: (pointer_declarator 58 | (ms_pointer_modifier 59 | (ms_restrict_modifier)) 60 | declarator: (field_identifier))) 61 | (field_declaration 62 | type: (primitive_type) 63 | declarator: (pointer_declarator 64 | (ms_pointer_modifier 65 | (ms_signed_ptr_modifier)) 66 | declarator: (field_identifier))) 67 | (field_declaration 68 | type: (primitive_type) 69 | declarator: (pointer_declarator 70 | (ms_pointer_modifier 71 | (ms_unsigned_ptr_modifier)) 72 | declarator: (field_identifier))) 73 | (field_declaration 74 | type: (primitive_type) 75 | declarator: (pointer_declarator 76 | (ms_pointer_modifier 77 | (ms_unaligned_ptr_modifier)) 78 | declarator: (field_identifier))))) 79 | (function_definition 80 | type: (primitive_type) 81 | declarator: (function_declarator 82 | declarator: (identifier) 83 | parameters: (parameter_list 84 | (parameter_declaration 85 | type: (primitive_type) 86 | declarator: (identifier)) 87 | (parameter_declaration 88 | type: (primitive_type) 89 | declarator: (pointer_declarator 90 | (ms_pointer_modifier 91 | (ms_restrict_modifier)) 92 | declarator: (identifier))) 93 | (parameter_declaration 94 | type: (primitive_type) 95 | declarator: (pointer_declarator 96 | (ms_pointer_modifier 97 | (ms_restrict_modifier)) 98 | declarator: (identifier))) 99 | (parameter_declaration 100 | type: (primitive_type) 101 | declarator: (pointer_declarator 102 | declarator: (identifier))) 103 | (parameter_declaration 104 | type: (primitive_type) 105 | declarator: (pointer_declarator 106 | declarator: (identifier))))) 107 | body: (compound_statement 108 | (declaration 109 | type: (primitive_type) 110 | declarator: (identifier)) 111 | (for_statement 112 | initializer: (assignment_expression 113 | left: (identifier) 114 | right: (number_literal)) 115 | condition: (binary_expression 116 | left: (identifier) 117 | right: (identifier)) 118 | update: (update_expression 119 | argument: (identifier)) 120 | body: (compound_statement 121 | (expression_statement 122 | (assignment_expression 123 | left: (subscript_expression 124 | argument: (identifier) 125 | index: (identifier)) 126 | right: (binary_expression 127 | left: (subscript_expression 128 | argument: (identifier) 129 | index: (identifier)) 130 | right: (subscript_expression 131 | argument: (identifier) 132 | index: (identifier))))) 133 | (expression_statement 134 | (assignment_expression 135 | left: (subscript_expression 136 | argument: (identifier) 137 | index: (identifier)) 138 | right: (binary_expression 139 | left: (subscript_expression 140 | argument: (identifier) 141 | index: (identifier)) 142 | right: (subscript_expression 143 | argument: (identifier) 144 | index: (identifier))))))))) 145 | (declaration 146 | type: (primitive_type) 147 | declarator: (function_declarator 148 | declarator: (identifier) 149 | parameters: (parameter_list 150 | (parameter_declaration 151 | type: (primitive_type) 152 | declarator: (pointer_declarator 153 | (ms_pointer_modifier 154 | (ms_unsigned_ptr_modifier)) 155 | declarator: (identifier))))))) 156 | 157 | ================================ 158 | call modifiers 159 | ================================ 160 | 161 | __cdecl void mymethod(){ 162 | return; 163 | } 164 | 165 | __fastcall void mymethod(){ 166 | return; 167 | } 168 | 169 | void __stdcall f() { } 170 | 171 | void (__stdcall g)() { } 172 | 173 | void __stdcall h(); 174 | 175 | void (__stdcall j()); 176 | 177 | typedef void(__stdcall *fp)(); 178 | 179 | --- 180 | 181 | (translation_unit 182 | (function_definition 183 | (ms_call_modifier) 184 | type: (primitive_type) 185 | declarator: (function_declarator 186 | declarator: (identifier) 187 | parameters: (parameter_list)) 188 | body: (compound_statement 189 | (return_statement))) 190 | (function_definition 191 | (ms_call_modifier) 192 | type: (primitive_type) 193 | declarator: (function_declarator 194 | declarator: (identifier) 195 | parameters: (parameter_list)) 196 | body: (compound_statement 197 | (return_statement))) 198 | (function_definition 199 | type: (primitive_type) 200 | (ms_call_modifier) 201 | declarator: (function_declarator 202 | declarator: (identifier) 203 | parameters: (parameter_list)) 204 | body: (compound_statement)) 205 | (function_definition 206 | type: (primitive_type) 207 | declarator: (function_declarator 208 | declarator: (parenthesized_declarator 209 | (ms_call_modifier) 210 | (identifier)) 211 | parameters: (parameter_list)) 212 | body: (compound_statement)) 213 | (declaration 214 | type: (primitive_type) 215 | declarator: (ms_call_modifier) 216 | declarator: (function_declarator 217 | declarator: (identifier) 218 | parameters: (parameter_list))) 219 | (declaration 220 | type: (primitive_type) 221 | declarator: (parenthesized_declarator 222 | (ms_call_modifier) 223 | (function_declarator 224 | declarator: (identifier) 225 | parameters: (parameter_list)))) 226 | (type_definition 227 | type: (primitive_type) 228 | declarator: (function_declarator 229 | declarator: (parenthesized_declarator 230 | (ms_call_modifier) 231 | (pointer_declarator 232 | declarator: (type_identifier))) 233 | parameters: (parameter_list)))) 234 | 235 | ================================ 236 | SEH exception handling 237 | ================================ 238 | 239 | int main() { 240 | int arg; 241 | __try { 242 | __try { 243 | arg = 1; 244 | __leave; 245 | } __except (-1) { 246 | arg = 2; 247 | } 248 | __leave; 249 | arg = 3; 250 | } __finally { 251 | printf("arg: %d\n", arg); 252 | } 253 | } 254 | 255 | --- 256 | 257 | (translation_unit 258 | (function_definition 259 | (primitive_type) 260 | (function_declarator 261 | (identifier) 262 | (parameter_list)) 263 | (compound_statement 264 | (declaration 265 | (primitive_type) 266 | (identifier)) 267 | (seh_try_statement 268 | (compound_statement 269 | (seh_try_statement 270 | (compound_statement 271 | (expression_statement 272 | (assignment_expression 273 | (identifier) 274 | (number_literal))) 275 | (seh_leave_statement)) 276 | (seh_except_clause 277 | (parenthesized_expression 278 | (number_literal)) 279 | (compound_statement 280 | (expression_statement 281 | (assignment_expression 282 | (identifier) 283 | (number_literal)))))) 284 | (seh_leave_statement) 285 | (expression_statement 286 | (assignment_expression 287 | (identifier) 288 | (number_literal)))) 289 | (seh_finally_clause 290 | (compound_statement 291 | (expression_statement 292 | (call_expression 293 | (identifier) 294 | (argument_list 295 | (string_literal 296 | (string_content) 297 | (escape_sequence)) 298 | (identifier)))))))))) 299 | -------------------------------------------------------------------------------- /test/corpus/preprocessor.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | Include directives 3 | ================================================================================ 4 | 5 | #include "some/path.h" 6 | #include 7 | #include MACRO 8 | #include MACRO(arg1, arg2) 9 | 10 | -------------------------------------------------------------------------------- 11 | 12 | (translation_unit 13 | (preproc_include 14 | path: (string_literal 15 | (string_content))) 16 | (preproc_include 17 | path: (system_lib_string)) 18 | (preproc_include 19 | path: (identifier)) 20 | (preproc_include 21 | path: (call_expression 22 | function: (identifier) 23 | arguments: (argument_list 24 | (identifier) 25 | (identifier))))) 26 | 27 | ================================================================================ 28 | Object-like macro definitions 29 | ================================================================================ 30 | 31 | #define ONE 32 | #define TWO int a = b; 33 | #define THREE \ 34 | c == d ? \ 35 | e : \ 36 | f 37 | #define FOUR (mno * pq) 38 | #define FIVE(a,b) x \ 39 | + y 40 | #define SIX(a, \ 41 | b) x \ 42 | + y 43 | #define SEVEN 7/* seven has an 44 | * annoying comment */ 45 | #define EIGHT(x) do { \ 46 | x = x + 1; \ 47 | x = x / 2; \ 48 | } while (x > 0); 49 | 50 | -------------------------------------------------------------------------------- 51 | 52 | (translation_unit 53 | (preproc_def 54 | name: (identifier)) 55 | (preproc_def 56 | name: (identifier) 57 | value: (preproc_arg)) 58 | (preproc_def 59 | name: (identifier) 60 | value: (preproc_arg)) 61 | (preproc_def 62 | name: (identifier) 63 | value: (preproc_arg)) 64 | (preproc_function_def 65 | name: (identifier) 66 | parameters: (preproc_params 67 | (identifier) 68 | (identifier)) 69 | value: (preproc_arg)) 70 | (preproc_function_def 71 | name: (identifier) 72 | parameters: (preproc_params 73 | (identifier) 74 | (identifier)) 75 | value: (preproc_arg)) 76 | (preproc_def 77 | name: (identifier) 78 | value: (preproc_arg) 79 | (comment)) 80 | (preproc_function_def 81 | name: (identifier) 82 | parameters: (preproc_params 83 | (identifier)) 84 | value: (preproc_arg))) 85 | 86 | ================================================================================ 87 | Function-like macro definitions 88 | ================================================================================ 89 | 90 | #define ONE() a 91 | #define TWO(b) c 92 | #define THREE(d, e) f 93 | #define FOUR(...) g 94 | #define FIVE(h, i, ...) j 95 | 96 | -------------------------------------------------------------------------------- 97 | 98 | (translation_unit 99 | (preproc_function_def 100 | name: (identifier) 101 | parameters: (preproc_params) 102 | value: (preproc_arg)) 103 | (preproc_function_def 104 | name: (identifier) 105 | parameters: (preproc_params 106 | (identifier)) 107 | value: (preproc_arg)) 108 | (preproc_function_def 109 | name: (identifier) 110 | parameters: (preproc_params 111 | (identifier) 112 | (identifier)) 113 | value: (preproc_arg)) 114 | (preproc_function_def 115 | name: (identifier) 116 | parameters: (preproc_params) 117 | value: (preproc_arg)) 118 | (preproc_function_def 119 | name: (identifier) 120 | parameters: (preproc_params 121 | (identifier) 122 | (identifier)) 123 | value: (preproc_arg))) 124 | 125 | ================================================================================ 126 | Ifdefs 127 | ================================================================================ 128 | 129 | #ifndef DEFINE1 130 | int j; 131 | #endif 132 | 133 | #ifdef DEFINE2 134 | ssize_t b; 135 | #define c 32 136 | #elif defined DEFINE3 137 | #else 138 | int b; 139 | #define c 16 140 | #endif 141 | 142 | #ifdef DEFINE2 143 | #else 144 | # ifdef DEFINE3 145 | # else 146 | # endif 147 | #endif 148 | 149 | -------------------------------------------------------------------------------- 150 | 151 | (translation_unit 152 | (preproc_ifdef 153 | name: (identifier) 154 | (declaration 155 | type: (primitive_type) 156 | declarator: (identifier))) 157 | (preproc_ifdef 158 | name: (identifier) 159 | (declaration 160 | type: (primitive_type) 161 | declarator: (identifier)) 162 | (preproc_def 163 | name: (identifier) 164 | value: (preproc_arg)) 165 | alternative: (preproc_elif 166 | condition: (preproc_defined 167 | (identifier)) 168 | alternative: (preproc_else 169 | (declaration 170 | type: (primitive_type) 171 | declarator: (identifier)) 172 | (preproc_def 173 | name: (identifier) 174 | value: (preproc_arg))))) 175 | (preproc_ifdef 176 | name: (identifier) 177 | alternative: (preproc_else 178 | (preproc_ifdef 179 | name: (identifier) 180 | alternative: (preproc_else))))) 181 | 182 | ================================================================================ 183 | Elifdefs 184 | ================================================================================ 185 | 186 | #ifndef DEFINE1 187 | int j; 188 | #elifndef DEFINE2 189 | int k; 190 | #endif 191 | 192 | #ifdef DEFINE2 193 | ssize_t b; 194 | #elifdef DEFINE3 195 | ssize_t c; 196 | #else 197 | int b; 198 | #endif 199 | 200 | -------------------------------------------------------------------------------- 201 | 202 | (translation_unit 203 | (preproc_ifdef 204 | (identifier) 205 | (declaration 206 | (primitive_type) 207 | (identifier)) 208 | (preproc_elifdef 209 | (identifier) 210 | (declaration 211 | (primitive_type) 212 | (identifier)))) 213 | (preproc_ifdef 214 | (identifier) 215 | (declaration 216 | (primitive_type) 217 | (identifier)) 218 | (preproc_elifdef 219 | (identifier) 220 | (declaration 221 | (primitive_type) 222 | (identifier)) 223 | (preproc_else 224 | (declaration 225 | (primitive_type) 226 | (identifier)))))) 227 | 228 | ================================================================================ 229 | Mixing #elif and #elifdef 230 | ================================================================================ 231 | 232 | #ifndef DEFINE1 233 | int i; 234 | #elif defined(DEFINE2) 235 | int j; 236 | #endif 237 | 238 | #if defined DEFINE3 239 | int a; 240 | #elifdef DEFINE4 241 | int b; 242 | #else 243 | int c; 244 | #endif 245 | 246 | -------------------------------------------------------------------------------- 247 | 248 | (translation_unit 249 | (preproc_ifdef 250 | name: (identifier) 251 | (declaration 252 | type: (primitive_type) 253 | declarator: (identifier)) 254 | alternative: (preproc_elif 255 | condition: (preproc_defined 256 | (identifier)) 257 | (declaration 258 | type: (primitive_type) 259 | declarator: (identifier)))) 260 | (preproc_if 261 | condition: (preproc_defined 262 | (identifier)) 263 | (declaration 264 | type: (primitive_type) 265 | declarator: (identifier)) 266 | alternative: (preproc_elifdef 267 | name: (identifier) 268 | (declaration 269 | type: (primitive_type) 270 | declarator: (identifier)) 271 | alternative: (preproc_else 272 | (declaration 273 | type: (primitive_type) 274 | declarator: (identifier)))))) 275 | 276 | ================================================================================ 277 | General if blocks 278 | ================================================================================ 279 | 280 | #if defined(__GNUC__) && defined(__PIC__) 281 | #define inline inline __attribute__((always_inline)) 282 | #elif defined(_WIN32) 283 | #define something 284 | #elif !defined(SOMETHING_ELSE) 285 | #define SOMETHING_ELSE 286 | #else 287 | #include 288 | #endif 289 | 290 | -------------------------------------------------------------------------------- 291 | 292 | (translation_unit 293 | (preproc_if 294 | condition: (binary_expression 295 | left: (preproc_defined 296 | (identifier)) 297 | right: (preproc_defined 298 | (identifier))) 299 | (preproc_def 300 | name: (identifier) 301 | value: (preproc_arg)) 302 | alternative: (preproc_elif 303 | condition: (preproc_defined 304 | (identifier)) 305 | (preproc_def 306 | name: (identifier)) 307 | alternative: (preproc_elif 308 | condition: (unary_expression 309 | argument: (preproc_defined 310 | (identifier))) 311 | (preproc_def 312 | name: (identifier)) 313 | alternative: (preproc_else 314 | (preproc_include 315 | path: (system_lib_string))))))) 316 | 317 | ================================================================================ 318 | Preprocessor conditionals in functions 319 | ================================================================================ 320 | 321 | int main() { 322 | #if d 323 | puts("1"); 324 | #else 325 | puts("2"); 326 | #endif 327 | 328 | #if a 329 | return 0; 330 | #elif b 331 | return 1; 332 | #elif c 333 | return 2; 334 | #else 335 | return 3; 336 | #endif 337 | } 338 | 339 | -------------------------------------------------------------------------------- 340 | 341 | (translation_unit 342 | (function_definition 343 | (primitive_type) 344 | (function_declarator 345 | (identifier) 346 | (parameter_list)) 347 | (compound_statement 348 | (preproc_if 349 | (identifier) 350 | (expression_statement 351 | (call_expression 352 | (identifier) 353 | (argument_list 354 | (string_literal 355 | (string_content))))) 356 | (preproc_else 357 | (expression_statement 358 | (call_expression 359 | (identifier) 360 | (argument_list 361 | (string_literal 362 | (string_content))))))) 363 | (preproc_if 364 | (identifier) 365 | (return_statement 366 | (number_literal)) 367 | (preproc_elif 368 | (identifier) 369 | (return_statement 370 | (number_literal)) 371 | (preproc_elif 372 | (identifier) 373 | (return_statement 374 | (number_literal)) 375 | (preproc_else 376 | (return_statement 377 | (number_literal))))))))) 378 | 379 | ================================================================================ 380 | Preprocessor conditionals in struct/union bodies 381 | ================================================================================ 382 | 383 | struct S { 384 | #ifdef _WIN32 385 | LONG f2; 386 | #else 387 | uint32_t f2; 388 | #endif 389 | }; 390 | 391 | -------------------------------------------------------------------------------- 392 | 393 | (translation_unit 394 | (struct_specifier 395 | (type_identifier) 396 | (field_declaration_list 397 | (preproc_ifdef 398 | (identifier) 399 | (field_declaration 400 | (type_identifier) 401 | (field_identifier)) 402 | (preproc_else 403 | (field_declaration 404 | (primitive_type) 405 | (field_identifier))))))) 406 | 407 | ================================================================================ 408 | Unknown preprocessor directives 409 | ================================================================================ 410 | 411 | #pragma mark - UIViewController 412 | 413 | -------------------------------------------------------------------------------- 414 | 415 | (translation_unit 416 | (preproc_call 417 | directive: (preproc_directive) 418 | argument: (preproc_arg))) 419 | 420 | ================================================================================ 421 | Preprocessor expressions 422 | ================================================================================ 423 | 424 | #if A(B || C) && \ 425 | !D(F) 426 | 427 | uint32_t a; 428 | 429 | #endif 430 | 431 | -------------------------------------------------------------------------------- 432 | 433 | (translation_unit 434 | (preproc_if 435 | (binary_expression 436 | (call_expression 437 | (identifier) 438 | (argument_list 439 | (binary_expression 440 | (identifier) 441 | (identifier)))) 442 | (unary_expression 443 | (call_expression 444 | (identifier) 445 | (argument_list 446 | (identifier))))) 447 | (declaration 448 | (primitive_type) 449 | (identifier)))) 450 | -------------------------------------------------------------------------------- /test/corpus/statements.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | If statements 3 | ================================================================================ 4 | 5 | int main() { 6 | if (a) 7 | 1; 8 | 9 | if (!a) { 10 | 2; 11 | } else { 12 | 3; 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- 17 | 18 | (translation_unit 19 | (function_definition 20 | (primitive_type) 21 | (function_declarator 22 | (identifier) 23 | (parameter_list)) 24 | (compound_statement 25 | (if_statement 26 | (parenthesized_expression 27 | (identifier)) 28 | (expression_statement 29 | (number_literal))) 30 | (if_statement 31 | (parenthesized_expression 32 | (unary_expression 33 | (identifier))) 34 | (compound_statement 35 | (expression_statement 36 | (number_literal))) 37 | (else_clause 38 | (compound_statement 39 | (expression_statement 40 | (number_literal)))))))) 41 | 42 | ================================================================================ 43 | For loops 44 | ================================================================================ 45 | 46 | int main() { 47 | for (;;) 48 | 1; 49 | 50 | for (int i = 0; i < 5; next(), i++) { 51 | 2; 52 | } 53 | 54 | for (start(); check(); step()) 55 | 3; 56 | 57 | for (i = 0, j = 0, k = 0, l = 0; i < 1, j < 1; i++, j++, k++, l++) 58 | 1; 59 | } 60 | 61 | -------------------------------------------------------------------------------- 62 | 63 | (translation_unit 64 | (function_definition 65 | (primitive_type) 66 | (function_declarator 67 | (identifier) 68 | (parameter_list)) 69 | (compound_statement 70 | (for_statement 71 | (expression_statement 72 | (number_literal))) 73 | (for_statement 74 | (declaration 75 | (primitive_type) 76 | (init_declarator 77 | (identifier) 78 | (number_literal))) 79 | (binary_expression 80 | (identifier) 81 | (number_literal)) 82 | (comma_expression 83 | (call_expression 84 | (identifier) 85 | (argument_list)) 86 | (update_expression 87 | (identifier))) 88 | (compound_statement 89 | (expression_statement 90 | (number_literal)))) 91 | (for_statement 92 | (call_expression 93 | (identifier) 94 | (argument_list)) 95 | (call_expression 96 | (identifier) 97 | (argument_list)) 98 | (call_expression 99 | (identifier) 100 | (argument_list)) 101 | (expression_statement 102 | (number_literal))) 103 | (for_statement 104 | (comma_expression 105 | (assignment_expression 106 | (identifier) 107 | (number_literal)) 108 | (comma_expression 109 | (assignment_expression 110 | (identifier) 111 | (number_literal)) 112 | (comma_expression 113 | (assignment_expression 114 | (identifier) 115 | (number_literal)) 116 | (assignment_expression 117 | (identifier) 118 | (number_literal))))) 119 | (comma_expression 120 | (binary_expression 121 | (identifier) 122 | (number_literal)) 123 | (binary_expression 124 | (identifier) 125 | (number_literal))) 126 | (comma_expression 127 | (update_expression 128 | (identifier)) 129 | (comma_expression 130 | (update_expression 131 | (identifier)) 132 | (comma_expression 133 | (update_expression 134 | (identifier)) 135 | (update_expression 136 | (identifier))))) 137 | (expression_statement 138 | (number_literal)))))) 139 | 140 | ================================================================================ 141 | While loops 142 | ================================================================================ 143 | 144 | int main() { 145 | while (x) 146 | printf("hi"); 147 | } 148 | 149 | -------------------------------------------------------------------------------- 150 | 151 | (translation_unit 152 | (function_definition 153 | (primitive_type) 154 | (function_declarator 155 | (identifier) 156 | (parameter_list)) 157 | (compound_statement 158 | (while_statement 159 | (parenthesized_expression 160 | (identifier)) 161 | (expression_statement 162 | (call_expression 163 | (identifier) 164 | (argument_list 165 | (string_literal 166 | (string_content))))))))) 167 | 168 | ================================================================================ 169 | Labeled statements 170 | ================================================================================ 171 | 172 | void foo(T *t) { 173 | recur: 174 | t = t->next(); 175 | if (t) goto recur; 176 | } 177 | 178 | -------------------------------------------------------------------------------- 179 | 180 | (translation_unit 181 | (function_definition 182 | (primitive_type) 183 | (function_declarator 184 | (identifier) 185 | (parameter_list 186 | (parameter_declaration 187 | (type_identifier) 188 | (pointer_declarator 189 | (identifier))))) 190 | (compound_statement 191 | (labeled_statement 192 | (statement_identifier) 193 | (expression_statement 194 | (assignment_expression 195 | (identifier) 196 | (call_expression 197 | (field_expression 198 | (identifier) 199 | (field_identifier)) 200 | (argument_list))))) 201 | (if_statement 202 | (parenthesized_expression 203 | (identifier)) 204 | (goto_statement 205 | (statement_identifier)))))) 206 | 207 | ================================================================================ 208 | Switch statements 209 | ================================================================================ 210 | 211 | void foo(int a) { 212 | switch (a) { 213 | puts("entered switch!"); 214 | 215 | case 3: 216 | case 5: 217 | if (b) { 218 | c(); 219 | } 220 | break; 221 | 222 | default: 223 | c(); 224 | break; 225 | } 226 | } 227 | 228 | -------------------------------------------------------------------------------- 229 | 230 | (translation_unit 231 | (function_definition 232 | (primitive_type) 233 | (function_declarator 234 | (identifier) 235 | (parameter_list 236 | (parameter_declaration 237 | (primitive_type) 238 | (identifier)))) 239 | (compound_statement 240 | (switch_statement 241 | (parenthesized_expression 242 | (identifier)) 243 | (compound_statement 244 | (expression_statement 245 | (call_expression 246 | (identifier) 247 | (argument_list 248 | (string_literal 249 | (string_content))))) 250 | (case_statement 251 | (number_literal)) 252 | (case_statement 253 | (number_literal) 254 | (if_statement 255 | (parenthesized_expression 256 | (identifier)) 257 | (compound_statement 258 | (expression_statement 259 | (call_expression 260 | (identifier) 261 | (argument_list))))) 262 | (break_statement)) 263 | (case_statement 264 | (expression_statement 265 | (call_expression 266 | (identifier) 267 | (argument_list))) 268 | (break_statement))))))) 269 | 270 | ================================================================================ 271 | Case statements separate from switch statements 272 | ================================================================================ 273 | 274 | int main() { 275 | switch (count % 8) { 276 | case 0: 277 | do { 278 | *to = *from++; 279 | case 2: *to = *from++; 280 | case 1: *to = *from++; 281 | } while (--n > 0); 282 | } 283 | } 284 | 285 | -------------------------------------------------------------------------------- 286 | 287 | (translation_unit 288 | (function_definition 289 | (primitive_type) 290 | (function_declarator 291 | (identifier) 292 | (parameter_list)) 293 | (compound_statement 294 | (switch_statement 295 | (parenthesized_expression 296 | (binary_expression 297 | (identifier) 298 | (number_literal))) 299 | (compound_statement 300 | (case_statement 301 | (number_literal) 302 | (do_statement 303 | (compound_statement 304 | (expression_statement 305 | (assignment_expression 306 | (pointer_expression 307 | (identifier)) 308 | (pointer_expression 309 | (update_expression 310 | (identifier))))) 311 | (case_statement 312 | (number_literal) 313 | (expression_statement 314 | (assignment_expression 315 | (pointer_expression 316 | (identifier)) 317 | (pointer_expression 318 | (update_expression 319 | (identifier)))))) 320 | (case_statement 321 | (number_literal) 322 | (expression_statement 323 | (assignment_expression 324 | (pointer_expression 325 | (identifier)) 326 | (pointer_expression 327 | (update_expression 328 | (identifier))))))) 329 | (parenthesized_expression 330 | (binary_expression 331 | (update_expression 332 | (identifier)) 333 | (number_literal)))))))))) 334 | 335 | ================================================================================ 336 | Return statements 337 | ================================================================================ 338 | 339 | void foo() { 340 | return; 341 | return a; 342 | return a, b; 343 | } 344 | 345 | -------------------------------------------------------------------------------- 346 | 347 | (translation_unit 348 | (function_definition 349 | (primitive_type) 350 | (function_declarator 351 | (identifier) 352 | (parameter_list)) 353 | (compound_statement 354 | (return_statement) 355 | (return_statement 356 | (identifier)) 357 | (return_statement 358 | (comma_expression 359 | (identifier) 360 | (identifier)))))) 361 | 362 | ================================================================================ 363 | Comments with asterisks 364 | ================================================================================ 365 | 366 | /************************* 367 | * odd number of asterisks 368 | *************************/ 369 | int a; 370 | 371 | /************************** 372 | * even number of asterisks 373 | **************************/ 374 | int b; 375 | 376 | -------------------------------------------------------------------------------- 377 | 378 | (translation_unit 379 | (comment) 380 | (declaration 381 | (primitive_type) 382 | (identifier)) 383 | (comment) 384 | (declaration 385 | (primitive_type) 386 | (identifier))) 387 | 388 | ================================================================================ 389 | Comment with multiple backslashes 390 | ================================================================================ 391 | 392 | int a = 3; // Hello \\ 393 | World 394 | 395 | -------------------------------------------------------------------------------- 396 | 397 | (translation_unit 398 | (declaration 399 | (primitive_type) 400 | (init_declarator 401 | (identifier) 402 | (number_literal))) 403 | (comment)) 404 | 405 | ================================================================================ 406 | Attributes 407 | ================================================================================ 408 | 409 | void f() { 410 | [[a]] switch (b) { 411 | [[c]] case 1: {} 412 | case 2: 413 | [[fallthrough]]; 414 | default: 415 | } 416 | [[a]] while (true) {} 417 | [[a]] if (true) {} 418 | [[a]] for (;;) {} 419 | [[a]] return; 420 | [[a]] a; 421 | [[a]]; 422 | [[a]] label: {} 423 | [[a]] goto label; 424 | 425 | // these are c++ specific, but their bind locations should be c-compatible 426 | if (true) [[likely]] {} else [[unlikely]] {} 427 | do [[likely]] {} while (true); 428 | } 429 | 430 | -------------------------------------------------------------------------------- 431 | 432 | (translation_unit 433 | (function_definition 434 | (primitive_type) 435 | (function_declarator 436 | (identifier) 437 | (parameter_list)) 438 | (compound_statement 439 | (attributed_statement 440 | (attribute_declaration 441 | (attribute 442 | (identifier))) 443 | (switch_statement 444 | (parenthesized_expression 445 | (identifier)) 446 | (compound_statement 447 | (attributed_statement 448 | (attribute_declaration 449 | (attribute 450 | (identifier))) 451 | (case_statement 452 | (number_literal) 453 | (compound_statement))) 454 | (case_statement 455 | (number_literal) 456 | (attributed_statement 457 | (attribute_declaration 458 | (attribute 459 | (identifier))) 460 | (expression_statement))) 461 | (case_statement)))) 462 | (attributed_statement 463 | (attribute_declaration 464 | (attribute 465 | (identifier))) 466 | (while_statement 467 | (parenthesized_expression 468 | (true)) 469 | (compound_statement))) 470 | (attributed_statement 471 | (attribute_declaration 472 | (attribute 473 | (identifier))) 474 | (if_statement 475 | (parenthesized_expression 476 | (true)) 477 | (compound_statement))) 478 | (attributed_statement 479 | (attribute_declaration 480 | (attribute 481 | (identifier))) 482 | (for_statement 483 | (compound_statement))) 484 | (attributed_statement 485 | (attribute_declaration 486 | (attribute 487 | (identifier))) 488 | (return_statement)) 489 | (attributed_statement 490 | (attribute_declaration 491 | (attribute 492 | (identifier))) 493 | (expression_statement 494 | (identifier))) 495 | (attributed_statement 496 | (attribute_declaration 497 | (attribute 498 | (identifier))) 499 | (expression_statement)) 500 | (attributed_statement 501 | (attribute_declaration 502 | (attribute 503 | (identifier))) 504 | (labeled_statement 505 | (statement_identifier) 506 | (compound_statement))) 507 | (attributed_statement 508 | (attribute_declaration 509 | (attribute 510 | (identifier))) 511 | (goto_statement 512 | (statement_identifier))) 513 | (comment) 514 | (if_statement 515 | (parenthesized_expression 516 | (true)) 517 | (attributed_statement 518 | (attribute_declaration 519 | (attribute 520 | (identifier))) 521 | (compound_statement)) 522 | (else_clause 523 | (attributed_statement 524 | (attribute_declaration 525 | (attribute 526 | (identifier))) 527 | (compound_statement)))) 528 | (do_statement 529 | (attributed_statement 530 | (attribute_declaration 531 | (attribute 532 | (identifier))) 533 | (compound_statement)) 534 | (parenthesized_expression 535 | (true)))))) 536 | -------------------------------------------------------------------------------- /test/corpus/types.txt: -------------------------------------------------------------------------------- 1 | ======================================== 2 | Primitive types 3 | ======================================== 4 | 5 | int a; 6 | uint8_t a; 7 | uint16_t a; 8 | uint32_t a; 9 | uint64_t a; 10 | uintptr_t a; 11 | 12 | int8_t a; 13 | int16_t a; 14 | int32_t a; 15 | int64_t a; 16 | intptr_t a; 17 | 18 | char16_t a; 19 | char32_t a; 20 | 21 | size_t a; 22 | ssize_t a; 23 | 24 | --- 25 | 26 | (translation_unit 27 | (declaration (primitive_type) (identifier)) 28 | (declaration (primitive_type) (identifier)) 29 | (declaration (primitive_type) (identifier)) 30 | (declaration (primitive_type) (identifier)) 31 | (declaration (primitive_type) (identifier)) 32 | (declaration (primitive_type) (identifier)) 33 | (declaration (primitive_type) (identifier)) 34 | (declaration (primitive_type) (identifier)) 35 | (declaration (primitive_type) (identifier)) 36 | (declaration (primitive_type) (identifier)) 37 | (declaration (primitive_type) (identifier)) 38 | (declaration (primitive_type) (identifier)) 39 | (declaration (primitive_type) (identifier)) 40 | (declaration (primitive_type) (identifier)) 41 | (declaration (primitive_type) (identifier))) 42 | 43 | ======================================== 44 | Type modifiers 45 | ======================================== 46 | 47 | void f(unsigned); 48 | void f(unsigned int); 49 | void f(signed long int); 50 | void f(unsigned v1); 51 | void f(unsigned long v2); 52 | 53 | --- 54 | 55 | (translation_unit 56 | (declaration 57 | (primitive_type) 58 | (function_declarator 59 | (identifier) 60 | (parameter_list (parameter_declaration (sized_type_specifier))))) 61 | (declaration 62 | (primitive_type) 63 | (function_declarator 64 | (identifier) 65 | (parameter_list (parameter_declaration (sized_type_specifier (primitive_type)))))) 66 | (declaration 67 | (primitive_type) 68 | (function_declarator 69 | (identifier) 70 | (parameter_list (parameter_declaration (sized_type_specifier (primitive_type)))))) 71 | (declaration 72 | (primitive_type) 73 | (function_declarator 74 | (identifier) 75 | (parameter_list (parameter_declaration (sized_type_specifier) (identifier))))) 76 | (declaration 77 | (primitive_type) 78 | (function_declarator 79 | (identifier) 80 | (parameter_list (parameter_declaration (sized_type_specifier) (identifier)))))) 81 | -------------------------------------------------------------------------------- /test/highlight/keywords.c: -------------------------------------------------------------------------------- 1 | #include 2 | // ^ keyword 3 | // ^ string 4 | 5 | #include "something.h" 6 | // ^ string 7 | -------------------------------------------------------------------------------- /test/highlight/names.c: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | // ^ keyword 3 | // ^ keyword 4 | a_t b; 5 | // <- type 6 | // ^ property 7 | 8 | unsigned c_t (*d)[2]; 9 | // ^ type 10 | // ^ type 11 | // ^ property 12 | }, T, V; 13 | // ^ type 14 | // ^ type 15 | 16 | int main(const char string[SIZE]) { 17 | // <- type 18 | // ^ function 19 | // ^ keyword 20 | // ^ type 21 | // ^ variable 22 | // ^ constant 23 | 24 | return foo.bar + foo.baz(); 25 | // ^ keyword 26 | // ^ variable 27 | // ^ property 28 | // ^ function 29 | 30 | error: 31 | // <- label 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /tree-sitter.json: -------------------------------------------------------------------------------- 1 | { 2 | "grammars": [ 3 | { 4 | "name": "c", 5 | "camelcase": "C", 6 | "scope": "source.c", 7 | "path": ".", 8 | "file-types": [ 9 | "c", 10 | "h" 11 | ], 12 | "highlights": "queries/highlights.scm", 13 | "tags": "queries/tags.scm", 14 | "injection-regex": "^(c|h)$" 15 | } 16 | ], 17 | "metadata": { 18 | "version": "0.24.1", 19 | "license": "MIT", 20 | "description": "C grammar for tree-sitter", 21 | "authors": [ 22 | { 23 | "name": "Max Brunsfeld", 24 | "email": "maxbrunsfeld@gmail.com" 25 | }, 26 | { 27 | "name": "Amaan Qureshi", 28 | "email": "amaanq12@gmail.com" 29 | } 30 | ], 31 | "links": { 32 | "repository": "https://github.com/tree-sitter/tree-sitter-c" 33 | } 34 | }, 35 | "bindings": { 36 | "c": true, 37 | "go": true, 38 | "node": true, 39 | "python": true, 40 | "rust": true, 41 | "swift": true 42 | } 43 | } 44 | --------------------------------------------------------------------------------