├── .editorconfig ├── .gitattributes ├── .github └── workflows │ ├── nix-github-actions.yml │ └── publish.yml ├── .gitignore ├── .mergify.yml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── binding.gyp ├── bindings ├── node │ ├── binding.cc │ └── index.js └── rust │ ├── build.rs │ └── lib.rs ├── corpus ├── basic.txt ├── error_recovery.txt └── string.txt ├── default.nix ├── flake.lock ├── flake.nix ├── grammar.js ├── package-lock.json ├── package.json ├── queries ├── highlights.scm ├── injections.scm └── locals.scm ├── renovate.json ├── shell.nix ├── src ├── grammar.json ├── node-types.json ├── parser.c ├── scanner.c └── tree_sitter │ └── parser.h ├── test └── highlight │ └── basic.nix └── treefmt.toml /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | trim_trailing_whitespace = false 7 | 8 | # for testing purposes, the corpus may have trailing whitespace 9 | # and may have mixed EOL. 10 | # Still want a final newline though, as that makes no semantic difference. 11 | [corpus/*] 12 | trim_trailing_whitespace = false 13 | end_of_line = unset 14 | 15 | [**.{js,json,cc,css}] 16 | indent_style = space 17 | indent_size = 2 18 | 19 | # tree-sitter generate emits json with no trailing newline 20 | [src/node-types.json] 21 | insert_final_newline = false 22 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | /src/** linguist-vendored 2 | /src/scanner.cc linguist-vendored=false 3 | -------------------------------------------------------------------------------- /.github/workflows/nix-github-actions.yml: -------------------------------------------------------------------------------- 1 | name: Nix Flake actions 2 | 3 | on: 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | - main 9 | 10 | jobs: 11 | nix-matrix: 12 | runs-on: ubuntu-latest 13 | outputs: 14 | matrix: ${{ steps.set-matrix.outputs.matrix }} 15 | steps: 16 | - uses: actions/checkout@v4 17 | - uses: cachix/install-nix-action@v31 18 | - id: set-matrix 19 | name: Generate Nix Matrix 20 | run: | 21 | set -Eeu 22 | echo "matrix=$(nix eval --json '.#githubActions.matrix')" >> "$GITHUB_OUTPUT" 23 | 24 | nix-build: 25 | needs: nix-matrix 26 | runs-on: ${{ matrix.os }} 27 | strategy: 28 | matrix: ${{fromJSON(needs.nix-matrix.outputs.matrix)}} 29 | steps: 30 | - uses: actions/checkout@v4 31 | - uses: cachix/install-nix-action@v31 32 | - name: Add nix-community cache 33 | uses: cachix/cachix-action@v16 34 | with: 35 | name: nix-community 36 | authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' 37 | - run: nix build -L ".#${{ matrix.attr }}" 38 | 39 | collect: 40 | runs-on: ubuntu-latest 41 | needs: 42 | - nix-build 43 | steps: 44 | - run: true 45 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Release to crates.io 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*.*.*' # Matches tags like v1.0.0, v2.1.3, etc. 7 | 8 | jobs: 9 | release: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v4 15 | 16 | - name: Set up Rust 17 | uses: actions-rs/toolchain@v1 18 | with: 19 | toolchain: stable 20 | override: true 21 | 22 | - name: Cache Cargo registry 23 | uses: actions/cache@v4 24 | with: 25 | path: ~/.cargo/registry 26 | key: ${{ runner.os }}-cargo-registry 27 | restore-keys: | 28 | ${{ runner.os }}-cargo-registry 29 | 30 | - name: Cache Cargo index 31 | uses: actions/cache@v4 32 | with: 33 | path: ~/.cargo/git 34 | key: ${{ runner.os }}-cargo-index 35 | restore-keys: | 36 | ${{ runner.os }}-cargo-index 37 | 38 | - name: Build the project 39 | run: cargo build --release 40 | 41 | - name: Publish to crates.io 42 | env: 43 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 44 | run: cargo publish 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | node_modules 3 | -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | pull_request_rules: 2 | - name: automatic merge for Renovate pull requests 3 | conditions: 4 | - author=renovate[bot] 5 | - check-success=collect 6 | actions: 7 | merge: 8 | method: rebase 9 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 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.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" 19 | dependencies = [ 20 | "shlex", 21 | ] 22 | 23 | [[package]] 24 | name = "memchr" 25 | version = "2.7.4" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 28 | 29 | [[package]] 30 | name = "regex" 31 | version = "1.10.6" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" 34 | dependencies = [ 35 | "aho-corasick", 36 | "memchr", 37 | "regex-automata", 38 | "regex-syntax", 39 | ] 40 | 41 | [[package]] 42 | name = "regex-automata" 43 | version = "0.4.7" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" 46 | dependencies = [ 47 | "aho-corasick", 48 | "memchr", 49 | "regex-syntax", 50 | ] 51 | 52 | [[package]] 53 | name = "regex-syntax" 54 | version = "0.8.4" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" 57 | 58 | [[package]] 59 | name = "shlex" 60 | version = "1.3.0" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 63 | 64 | [[package]] 65 | name = "streaming-iterator" 66 | version = "0.1.9" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520" 69 | 70 | [[package]] 71 | name = "tree-sitter" 72 | version = "0.24.4" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "b67baf55e7e1b6806063b1e51041069c90afff16afcbbccd278d899f9d84bca4" 75 | dependencies = [ 76 | "cc", 77 | "regex", 78 | "regex-syntax", 79 | "streaming-iterator", 80 | "tree-sitter-language", 81 | ] 82 | 83 | [[package]] 84 | name = "tree-sitter-language" 85 | version = "0.1.1" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "2ca9cabf8f61ee3e83c0f532c45e9e082627f77a8bb9553684df584edcf82654" 88 | 89 | [[package]] 90 | name = "tree-sitter-nix" 91 | version = "0.0.2" 92 | dependencies = [ 93 | "cc", 94 | "tree-sitter", 95 | "tree-sitter-language", 96 | ] 97 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tree-sitter-nix" 3 | description = "nix grammar for the tree-sitter parsing library" 4 | version = "0.0.2" 5 | keywords = ["incremental", "parsing", "nix"] 6 | categories = ["parsing", "text-editors"] 7 | repository = "https://github.com/nix-community/tree-sitter-nix" 8 | edition = "2018" 9 | license = "MIT" 10 | 11 | build = "bindings/rust/build.rs" 12 | include = [ 13 | "bindings/rust/*", 14 | "grammar.js", 15 | "queries/*", 16 | "src/*", 17 | ] 18 | 19 | [lib] 20 | path = "bindings/rust/lib.rs" 21 | 22 | [dependencies] 23 | tree-sitter-language = "0.1.0" 24 | 25 | [dev-dependencies] 26 | tree-sitter = ">=0.23" 27 | 28 | [build-dependencies] 29 | cc = "1.0" 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Charles Strahan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tree-sitter-nix 2 | 3 | [![Build Status](https://github.com/nix-community/tree-sitter-nix/actions/workflows/nix-github-actions.yml/badge.svg)](https://github.com/nix-community/tree-sitter-nix/actions/workflows/nix-github-actions.yml) 4 | 5 | Nix grammar for [tree-sitter](https://github.com/tree-sitter/tree-sitter). 6 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_nix_binding", 5 | "include_dirs": [ 6 | " 3 | #include "nan.h" 4 | 5 | using namespace v8; 6 | 7 | extern "C" TSLanguage * tree_sitter_nix(); 8 | 9 | namespace { 10 | 11 | NAN_METHOD(New) {} 12 | 13 | void Init(Local exports, Local module) { 14 | Local tpl = Nan::New(New); 15 | tpl->SetClassName(Nan::New("Language").ToLocalChecked()); 16 | tpl->InstanceTemplate()->SetInternalFieldCount(1); 17 | 18 | Local constructor = Nan::GetFunction(tpl).ToLocalChecked(); 19 | Local instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked(); 20 | Nan::SetInternalFieldPointer(instance, 0, tree_sitter_nix()); 21 | 22 | Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("nix").ToLocalChecked()); 23 | Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance); 24 | } 25 | 26 | NODE_MODULE(tree_sitter_nix_binding, Init) 27 | 28 | } // namespace 29 | -------------------------------------------------------------------------------- /bindings/node/index.js: -------------------------------------------------------------------------------- 1 | try { 2 | module.exports = require("../../build/Release/tree_sitter_nix_binding"); 3 | } catch (error1) { 4 | if (error1.code !== "MODULE_NOT_FOUND") { 5 | throw error1; 6 | } 7 | try { 8 | module.exports = require("../../build/Debug/tree_sitter_nix_binding"); 9 | } catch (error2) { 10 | if (error2.code !== "MODULE_NOT_FOUND") { 11 | throw error2; 12 | } 13 | throw error1; 14 | } 15 | } 16 | 17 | try { 18 | module.exports.nodeTypeInfo = require("../../src/node-types.json"); 19 | } catch (_) {} 20 | -------------------------------------------------------------------------------- /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.include(&src_dir); 6 | c_config 7 | .flag_if_supported("-Wno-unused-parameter") 8 | .flag_if_supported("-Wno-unused-but-set-variable") 9 | .flag_if_supported("-Wno-trigraphs"); 10 | let parser_path = src_dir.join("parser.c"); 11 | c_config.file(&parser_path); 12 | 13 | // If your language uses an external scanner written in C, 14 | // then include this block of code: 15 | 16 | let scanner_path = src_dir.join("scanner.c"); 17 | c_config.file(&scanner_path); 18 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 19 | 20 | c_config.compile("parser"); 21 | println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); 22 | 23 | // If your language uses an external scanner written in C++, 24 | // then include this block of code: 25 | 26 | /* 27 | let mut cpp_config = cc::Build::new(); 28 | cpp_config.cpp(true); 29 | cpp_config.include(&src_dir); 30 | cpp_config 31 | .flag_if_supported("-Wno-unused-parameter") 32 | .flag_if_supported("-Wno-unused-but-set-variable"); 33 | let scanner_path = src_dir.join("scanner.cc"); 34 | cpp_config.file(&scanner_path); 35 | cpp_config.compile("scanner"); 36 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 37 | */ 38 | } 39 | -------------------------------------------------------------------------------- /bindings/rust/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate provides nix 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 | //! let 11 | //! b = a + 1; 12 | //! a = 1; 13 | //! in 14 | //! a + b 15 | //! "#; 16 | //! let mut parser = Parser::new(); 17 | //! let language = tree_sitter_nix::LANGUAGE; 18 | //! parser 19 | //! .set_language(&language.into()) 20 | //! .expect("Error loading nix parser"); 21 | //! let tree = parser.parse(code, None).unwrap(); 22 | //! assert!(!tree.root_node().has_error()); 23 | //! ``` 24 | //! 25 | //! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html 26 | //! [language func]: fn.language.html 27 | //! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html 28 | //! [tree-sitter]: https://tree-sitter.github.io/ 29 | 30 | use tree_sitter_language::LanguageFn; 31 | 32 | extern "C" { 33 | fn tree_sitter_nix() -> *const (); 34 | } 35 | 36 | /// The tree-sitter [`LanguageFn`] for this grammar. 37 | pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_nix) }; 38 | 39 | /// The content of the [`node-types.json`][] file for this grammar. 40 | /// 41 | /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types 42 | pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json"); 43 | 44 | // Uncomment these to include any queries that this grammar contains 45 | 46 | /// The syntax highlighting query for this language. 47 | pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm"); 48 | 49 | // The injections query for this language. 50 | // pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm"); 51 | 52 | // The locals tagging query for this language. 53 | // pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm"); 54 | 55 | /// The symbol tagging query for this language. 56 | // pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm"); 57 | 58 | #[cfg(test)] 59 | mod tests { 60 | #[test] 61 | fn test_can_load_grammar() { 62 | let mut parser = tree_sitter::Parser::new(); 63 | parser 64 | .set_language(&super::LANGUAGE.into()) 65 | .expect("Error loading nix parser"); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /corpus/basic.txt: -------------------------------------------------------------------------------- 1 | ==================== 2 | empty source 3 | ==================== 4 | 5 | --- 6 | 7 | (source_code) 8 | 9 | ==================== 10 | comments 11 | ==================== 12 | 13 | # This is a comment. 14 | 15 | /* 16 | This is also a comment. 17 | */ 18 | 19 | /*This as well, even with two asterisks.**/ 20 | 21 | "This is a string." 22 | 23 | --- 24 | 25 | (source_code (comment) (comment) (comment) (string_expression (string_fragment))) 26 | 27 | ==================== 28 | identifier 29 | ==================== 30 | 31 | abc 32 | 33 | --- 34 | 35 | (source_code (variable_expression (identifier))) 36 | 37 | ==================== 38 | integer_expression 39 | ==================== 40 | 41 | 123 42 | 43 | --- 44 | 45 | (source_code (integer_expression)) 46 | 47 | ==================== 48 | float_expression 49 | ==================== 50 | 51 | 123.456 52 | 53 | --- 54 | 55 | (source_code (float_expression)) 56 | 57 | ==================== 58 | uri 59 | ==================== 60 | 61 | http://foobar.com:80?baz=quux&blarg=etc 62 | 63 | --- 64 | 65 | (source_code (uri_expression)) 66 | 67 | ==================== 68 | list (empty) 69 | ==================== 70 | 71 | [ ] 72 | 73 | --- 74 | 75 | (source_code (list_expression)) 76 | 77 | ==================== 78 | list 79 | ==================== 80 | 81 | [ a 1 2.0 ] 82 | 83 | --- 84 | 85 | (source_code (list_expression (variable_expression (identifier)) (integer_expression) (float_expression))) 86 | 87 | ==================== 88 | if 89 | ==================== 90 | 91 | if a then b else c 92 | 93 | --- 94 | 95 | (source_code (if_expression (variable_expression (identifier)) (variable_expression (identifier)) (variable_expression (identifier)))) 96 | 97 | ==================== 98 | assert 99 | ==================== 100 | 101 | assert a; b 102 | 103 | --- 104 | 105 | (source_code (assert_expression (variable_expression (identifier)) (variable_expression (identifier)))) 106 | 107 | ==================== 108 | with 109 | ==================== 110 | 111 | with a; b 112 | 113 | --- 114 | 115 | (source_code (with_expression (variable_expression (identifier)) (variable_expression (identifier)))) 116 | 117 | ==================== 118 | let (empty) 119 | ==================== 120 | 121 | let in a 122 | 123 | --- 124 | 125 | (source_code (let_expression (variable_expression (identifier)))) 126 | 127 | ==================== 128 | let (binding) 129 | ==================== 130 | 131 | let a = b; in c 132 | 133 | --- 134 | 135 | (source_code 136 | (let_expression 137 | (binding_set 138 | (binding 139 | (attrpath (identifier)) 140 | (variable_expression (identifier)))) 141 | (variable_expression (identifier)))) 142 | 143 | ==================== 144 | let (binding, comments) 145 | ==================== 146 | 147 | let 148 | # foo 149 | a = b; 150 | # bar 151 | x = y; 152 | in 153 | # baz 154 | c 155 | 156 | --- 157 | 158 | (source_code 159 | (let_expression 160 | (comment) 161 | (binding_set 162 | (binding (attrpath (identifier)) (variable_expression (identifier))) 163 | (comment) 164 | (binding (attrpath (identifier)) (variable_expression (identifier)))) 165 | (comment) 166 | (variable_expression (identifier)))) 167 | 168 | ==================== 169 | let (inherit) 170 | ==================== 171 | 172 | let inherit a; in c 173 | 174 | --- 175 | 176 | (source_code 177 | (let_expression 178 | (binding_set 179 | (inherit 180 | (inherited_attrs 181 | (identifier)))) 182 | (variable_expression (identifier)))) 183 | 184 | ==================== 185 | let (inherit from) 186 | ==================== 187 | 188 | let inherit (a) b "c" ${d}; in 123 189 | 190 | --- 191 | 192 | (source_code 193 | (let_expression 194 | (binding_set 195 | (inherit_from 196 | (variable_expression (identifier)) 197 | (inherited_attrs 198 | (identifier) (string_expression (string_fragment)) (interpolation (variable_expression (identifier)))))) 199 | (integer_expression))) 200 | 201 | ==================== 202 | function_expression 203 | ==================== 204 | 205 | a: b 206 | 207 | --- 208 | 209 | (source_code (function_expression (identifier) (variable_expression (identifier)))) 210 | 211 | ==================== 212 | function_expression (with_expression formals) 213 | ==================== 214 | 215 | a@{ /*1*/ b, /*2*/ c ? 123, /*3*/ ... }: 1.234 216 | 217 | --- 218 | 219 | (source_code 220 | (function_expression 221 | (identifier) 222 | (formals 223 | (comment) 224 | (formal (identifier)) 225 | (comment) 226 | (formal (identifier) (integer_expression)) 227 | (comment) 228 | (ellipses)) 229 | (float_expression))) 230 | 231 | ==================== 232 | rec. attrset (empty) 233 | ==================== 234 | 235 | rec { } 236 | 237 | --- 238 | 239 | (source_code (rec_attrset_expression)) 240 | 241 | ==================== 242 | let attrset (empty) 243 | ==================== 244 | 245 | let { } 246 | 247 | --- 248 | 249 | (source_code (let_attrset_expression)) 250 | 251 | ==================== 252 | attrset (empty) 253 | ==================== 254 | 255 | { } 256 | 257 | --- 258 | 259 | (source_code (attrset_expression)) 260 | 261 | ==================== 262 | attr set 263 | ==================== 264 | 265 | { a = 1; ${b} = "quux"; "c" = 3.14; x.y.z = ; } 266 | 267 | --- 268 | 269 | (source_code 270 | (attrset_expression 271 | (binding_set 272 | (binding (attrpath (identifier)) (integer_expression)) 273 | (binding (attrpath (interpolation (variable_expression (identifier)))) (string_expression (string_fragment))) 274 | (binding (attrpath (string_expression (string_fragment))) (float_expression)) 275 | (binding (attrpath (identifier) (identifier) (identifier)) (spath_expression))))) 276 | 277 | ==================== 278 | select_expression 279 | ==================== 280 | 281 | u.v.${w}."x${y}z" 282 | 283 | --- 284 | 285 | (source_code 286 | (select_expression 287 | (variable_expression (identifier)) 288 | (attrpath 289 | (identifier) 290 | (interpolation (variable_expression (identifier))) 291 | (string_expression 292 | (string_fragment) 293 | (interpolation (variable_expression (identifier))) 294 | (string_fragment))))) 295 | 296 | 297 | 298 | ==================== 299 | hasAttr operator 300 | ==================== 301 | 302 | a ? ${b}.c."d" 303 | 304 | --- 305 | 306 | (source_code 307 | (has_attr_expression 308 | (variable_expression (identifier)) 309 | (attrpath 310 | (interpolation (variable_expression (identifier))) 311 | (identifier) 312 | (string_expression (string_fragment))))) 313 | 314 | ==================== 315 | apply_expressionlication 316 | ==================== 317 | 318 | a 1 2.0 319 | 320 | --- 321 | 322 | (source_code 323 | (apply_expression 324 | (apply_expression 325 | (variable_expression (identifier)) 326 | (integer_expression)) 327 | (float_expression))) 328 | 329 | ==================== 330 | path_expression test 331 | ==================== 332 | 333 | a/c${x}c 334 | 335 | --- 336 | 337 | (source_code 338 | (path_expression 339 | (path_fragment) 340 | (interpolation 341 | (variable_expression (identifier))) 342 | (path_fragment))) 343 | 344 | 345 | ==================== 346 | path_expression1 347 | ==================== 348 | 349 | x/a${x}a.a${123} 350 | 351 | --- 352 | 353 | (source_code 354 | (path_expression 355 | (path_fragment) 356 | (interpolation 357 | (variable_expression (identifier))) 358 | (path_fragment) 359 | (interpolation 360 | (integer_expression)))) 361 | 362 | ==================== 363 | path_expression2 364 | ==================== 365 | 366 | x/a${x}a/a${123} 367 | 368 | --- 369 | 370 | (source_code 371 | (path_expression 372 | (path_fragment) 373 | (interpolation 374 | (variable_expression (identifier))) 375 | (path_fragment) 376 | (interpolation 377 | (integer_expression)))) 378 | 379 | 380 | ==================== 381 | path_expression3 382 | ==================== 383 | 384 | /abc 385 | 386 | --- 387 | 388 | (source_code 389 | (path_expression 390 | (path_fragment))) 391 | 392 | ==================== 393 | path_expression4 394 | ==================== 395 | 396 | -123/abc 397 | 398 | --- 399 | 400 | (source_code 401 | (path_expression 402 | (path_fragment))) 403 | 404 | ==================== 405 | path_expression5 406 | ==================== 407 | 408 | dir/${name}.${extension} 409 | 410 | --- 411 | 412 | (source_code 413 | (path_expression 414 | (path_fragment) 415 | (interpolation 416 | (variable_expression (identifier))) 417 | (path_fragment) 418 | (interpolation 419 | (variable_expression (identifier))))) 420 | 421 | ==================== 422 | path_expression6 423 | ==================== 424 | 425 | 426 | a/b${c} d/e${f} 427 | 428 | --- 429 | 430 | (source_code 431 | (apply_expression 432 | (path_expression 433 | (path_fragment) 434 | (interpolation 435 | (variable_expression (identifier)))) 436 | (path_expression 437 | (path_fragment) 438 | (interpolation 439 | (variable_expression (identifier)))))) 440 | 441 | ==================== 442 | hpath_expression1 443 | ==================== 444 | 445 | ~/. 446 | 447 | --- 448 | 449 | (source_code 450 | (hpath_expression 451 | (path_fragment))) 452 | 453 | 454 | ==================== 455 | hpath_expression2 456 | ==================== 457 | 458 | ~/a${x}a/a${123} 459 | 460 | --- 461 | 462 | (source_code 463 | (hpath_expression 464 | (path_fragment) 465 | (interpolation 466 | (variable_expression (identifier))) 467 | (path_fragment) 468 | (interpolation 469 | (integer_expression)))) 470 | 471 | ==================== 472 | division not mistaken for path_expressions (1) 473 | ==================== 474 | 475 | a/ b 476 | 477 | --- 478 | 479 | (source_code 480 | (binary_expression 481 | (variable_expression (identifier)) 482 | (variable_expression (identifier)))) 483 | 484 | ==================== 485 | path_expression craziness - see https://github.com/NixOS/nix/pull/5066#issuecomment-1071918251 486 | ==================== 487 | 488 | a.${foo}/b.${bar} 489 | 490 | --- 491 | 492 | (source_code 493 | (apply_expression 494 | (select_expression 495 | (variable_expression (identifier)) 496 | (attrpath 497 | (interpolation 498 | (variable_expression (identifier))))) 499 | (path_expression 500 | (path_fragment) 501 | (interpolation 502 | (variable_expression (identifier)))))) 503 | 504 | ==================== 505 | operators 506 | ==================== 507 | 508 | square 2 + -pi - 42.0 509 | 510 | --- 511 | 512 | (source_code 513 | (binary_expression 514 | (binary_expression 515 | (apply_expression (variable_expression (identifier)) (integer_expression)) 516 | (unary_expression (variable_expression (identifier)))) 517 | (float_expression))) 518 | 519 | ==================== 520 | parens 521 | ==================== 522 | 523 | (123) 524 | 525 | --- 526 | 527 | (source_code 528 | (parenthesized_expression (integer_expression))) 529 | -------------------------------------------------------------------------------- /corpus/error_recovery.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | attrset typing field 3 | ================================================================================ 4 | 5 | { 6 | a = "foo"; 7 | b = 42; 8 | typing 9 | c = {}; 10 | d = x: x; 11 | } 12 | 13 | -------------------------------------------------------------------------------- 14 | 15 | (source_code 16 | (attrset_expression 17 | (binding_set 18 | (binding 19 | (attrpath 20 | (identifier)) 21 | (string_expression (string_fragment))) 22 | (binding 23 | (attrpath 24 | (identifier)) 25 | (integer_expression)) 26 | (binding 27 | (attrpath 28 | (identifier)) 29 | (ERROR 30 | (identifier)) 31 | (attrset_expression)) 32 | (binding 33 | (attrpath 34 | (identifier)) 35 | (function_expression 36 | (identifier) 37 | (variable_expression (identifier))))))) 38 | 39 | ================================================================================ 40 | attrset typing field following string 41 | ================================================================================ 42 | 43 | { 44 | typing 45 | inputs.nixpkgs.url = "github:nixos/nixpkgs"; 46 | inputs.nixpkgs-21-05.url = "github:nixos/nixpkgs/nixos-21.05"; 47 | } 48 | 49 | -------------------------------------------------------------------------------- 50 | 51 | (source_code 52 | (attrset_expression 53 | (ERROR 54 | (identifier)) 55 | (binding_set 56 | (binding 57 | (attrpath 58 | (identifier) 59 | (identifier) 60 | (identifier)) 61 | (string_expression (string_fragment))) 62 | (binding 63 | (attrpath 64 | (identifier) 65 | (identifier) 66 | (identifier)) 67 | (string_expression (string_fragment)))))) 68 | 69 | ================================================================================ 70 | attrset typing attrpath 71 | ================================================================================ 72 | 73 | { 74 | a = "foo"; 75 | b = 42; 76 | typing.path_expression 77 | c = {}; 78 | d = x: x; 79 | } 80 | 81 | -------------------------------------------------------------------------------- 82 | 83 | (source_code 84 | (attrset_expression 85 | (binding_set 86 | (binding 87 | (attrpath 88 | (identifier)) 89 | (string_expression (string_fragment))) 90 | (binding 91 | (attrpath 92 | (identifier)) 93 | (integer_expression)) 94 | (binding 95 | (attrpath 96 | (identifier) 97 | (identifier)) 98 | (ERROR 99 | (identifier)) 100 | (attrset_expression)) 101 | (binding 102 | (attrpath 103 | (identifier)) 104 | (function_expression 105 | (identifier) 106 | (variable_expression (identifier))))))) 107 | 108 | ================================================================================ 109 | attrset missing value 110 | ================================================================================ 111 | 112 | { 113 | a = "foo"; 114 | b = 42; 115 | typing = 116 | c = {}; 117 | d = x: x; 118 | } 119 | 120 | -------------------------------------------------------------------------------- 121 | 122 | (source_code 123 | (attrset_expression 124 | (binding_set 125 | (binding 126 | (attrpath 127 | (identifier)) 128 | (string_expression (string_fragment))) 129 | (binding 130 | (attrpath 131 | (identifier)) 132 | (integer_expression)) 133 | (binding 134 | (attrpath 135 | (identifier)) 136 | (apply_expression 137 | (variable_expression (identifier)) 138 | (ERROR) 139 | (attrset_expression))) 140 | (binding 141 | (attrpath 142 | (identifier)) 143 | (function_expression 144 | (identifier) 145 | (variable_expression (identifier))))))) 146 | 147 | ================================================================================ 148 | bind typing parenthesis 149 | ================================================================================ 150 | 151 | { 152 | a = "foo"; 153 | b = a: 42; 154 | typing = (a: 155 | c = {}; 156 | d = x: x; 157 | } 158 | 159 | -------------------------------------------------------------------------------- 160 | 161 | (source_code 162 | (attrset_expression 163 | (binding_set 164 | (binding 165 | (attrpath 166 | (identifier)) 167 | (string_expression (string_fragment))) 168 | (binding 169 | (attrpath 170 | (identifier)) 171 | (function_expression 172 | (identifier) 173 | (integer_expression))) 174 | (binding 175 | (attrpath 176 | (identifier)) 177 | (ERROR 178 | (function_expression 179 | (identifier) 180 | (variable_expression (identifier)))) 181 | (attrset_expression)) 182 | (binding 183 | (attrpath 184 | (identifier)) 185 | (function_expression 186 | (identifier) 187 | (variable_expression (identifier))))))) 188 | 189 | ================================================================================ 190 | let typing field 191 | ================================================================================ 192 | 193 | let 194 | a = "foo"; 195 | b = 42; 196 | typing 197 | c = {}; 198 | d = x: x; 199 | in {} 200 | 201 | -------------------------------------------------------------------------------- 202 | 203 | (source_code 204 | (let_expression 205 | (binding_set 206 | (binding 207 | (attrpath 208 | (identifier)) 209 | (string_expression (string_fragment))) 210 | (binding 211 | (attrpath 212 | (identifier)) 213 | (integer_expression)) 214 | (binding 215 | (attrpath 216 | (identifier)) 217 | (ERROR 218 | (identifier)) 219 | (attrset_expression)) 220 | (binding 221 | (attrpath 222 | (identifier)) 223 | (function_expression 224 | (identifier) 225 | (variable_expression (identifier))))) 226 | (attrset_expression))) 227 | 228 | ================================================================================ 229 | let missing value 230 | ================================================================================ 231 | 232 | let 233 | a = "foo"; 234 | b = 42; 235 | typing = 236 | c = {}; 237 | d = x: x; 238 | in 239 | a 240 | 241 | -------------------------------------------------------------------------------- 242 | 243 | (source_code 244 | (let_expression 245 | (binding_set 246 | (binding 247 | (attrpath 248 | (identifier)) 249 | (string_expression (string_fragment))) 250 | (binding 251 | (attrpath 252 | (identifier)) 253 | (integer_expression)) 254 | (binding 255 | (attrpath 256 | (identifier)) 257 | (apply_expression 258 | (variable_expression (identifier)) 259 | (ERROR) 260 | (attrset_expression))) 261 | (binding 262 | (attrpath 263 | (identifier)) 264 | (function_expression 265 | (identifier) 266 | (variable_expression (identifier))))) 267 | (variable_expression (identifier)))) 268 | -------------------------------------------------------------------------------- /corpus/string.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | string 3 | ================================================================================ 4 | 5 | "abcdef" 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (source_code 10 | (string_expression (string_fragment))) 11 | 12 | ================================================================================ 13 | string (complex) 14 | ================================================================================ 15 | 16 | " 17 | ${bob} likes crisp $ bills. escape newline \ 18 | \${don't interpolate here!}" 19 | 20 | -------------------------------------------------------------------------------- 21 | 22 | (source_code 23 | (string_expression 24 | (string_fragment) 25 | (interpolation 26 | (variable_expression (identifier))) 27 | (string_fragment) 28 | (escape_sequence) 29 | (dollar_escape) 30 | (string_fragment) 31 | (string_fragment))) 32 | 33 | ================================================================================ 34 | indented string 35 | ================================================================================ 36 | 37 | '' 38 | abc 39 | def 40 | ghi 41 | '' 42 | 43 | -------------------------------------------------------------------------------- 44 | 45 | (source_code 46 | (indented_string_expression (string_fragment))) 47 | 48 | ================================================================================ 49 | indented string (complex) 50 | ================================================================================ 51 | 52 | '' 53 | This is just a couple of quotes: ''' 54 | A lone $ doesn't throw things off. 55 | And of course, ''\${this shouldn't be an interpolation}. 56 | But ${this} is. 57 | This works, too: ''$ 58 | '' 59 | 60 | -------------------------------------------------------------------------------- 61 | 62 | (source_code 63 | (indented_string_expression 64 | (string_fragment) 65 | (escape_sequence) 66 | (string_fragment) 67 | (dollar_escape) 68 | (string_fragment) 69 | (string_fragment) 70 | (interpolation 71 | (variable_expression (identifier))) 72 | (string_fragment) 73 | (dollar_escape) 74 | (string_fragment) 75 | (string_fragment))) 76 | 77 | ================================================================================ 78 | string ($) 79 | ================================================================================ 80 | 81 | [ 82 | "$" 83 | "$\n" 84 | "${x}" 85 | "$${x}" 86 | "$$${x}" 87 | "$$$${x}" 88 | ] 89 | 90 | -------------------------------------------------------------------------------- 91 | 92 | (source_code 93 | (list_expression 94 | (string_expression (string_fragment)) 95 | (string_expression 96 | (string_fragment) 97 | (escape_sequence)) 98 | (string_expression 99 | (interpolation 100 | (variable_expression (identifier)))) 101 | (string_expression (string_fragment)) 102 | (string_expression 103 | (string_fragment) 104 | (interpolation 105 | (variable_expression (identifier)))) 106 | (string_expression (string_fragment)))) 107 | 108 | ================================================================================ 109 | indented string ($) 110 | ================================================================================ 111 | 112 | [ 113 | ''$'' 114 | ''$''\n'' 115 | ''${x}'' 116 | ''$${x}'' 117 | ''$$${x}'' 118 | ''$$$${x}'' 119 | ] 120 | 121 | -------------------------------------------------------------------------------- 122 | 123 | (source_code 124 | (list_expression 125 | (indented_string_expression (string_fragment)) 126 | (indented_string_expression 127 | (string_fragment) 128 | (escape_sequence)) 129 | (indented_string_expression 130 | (interpolation 131 | (variable_expression (identifier)))) 132 | (indented_string_expression (string_fragment)) 133 | (indented_string_expression 134 | (string_fragment) 135 | (interpolation 136 | (variable_expression (identifier)))) 137 | (indented_string_expression (string_fragment)))) 138 | 139 | ================================================================================ 140 | unterminated string 141 | ================================================================================ 142 | 143 | "foo ${bar} \n 144 | 145 | -------------------------------------------------------------------------------- 146 | 147 | (source_code 148 | (string_expression 149 | (string_fragment) 150 | (interpolation 151 | (variable_expression (identifier))) 152 | (string_fragment) 153 | (escape_sequence) 154 | (MISSING """))) 155 | 156 | ================================================================================ 157 | unterminated string escape 158 | ================================================================================ 159 | 160 | "foo ${bar} \n \ 161 | -------------------------------------------------------------------------------- 162 | 163 | (source_code 164 | (ERROR 165 | (string_fragment) 166 | (interpolation 167 | (variable_expression (identifier))) 168 | (string_fragment) 169 | (escape_sequence) 170 | (string_fragment) 171 | (UNEXPECTED '\0'))) 172 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import { } 2 | , lib ? pkgs.lib 3 | , src ? lib.cleanSource ./. 4 | }: 5 | 6 | pkgs.tree-sitter-grammars.tree-sitter-nix.overrideAttrs (old: { 7 | name = "tree-sitter-nix-dev"; 8 | version = "dev"; 9 | inherit src; 10 | 11 | doCheck = true; 12 | checkInputs = [ 13 | pkgs.tree-sitter 14 | pkgs.nodejs 15 | ]; 16 | checkPhase = '' 17 | HOME=$(mktemp -d) tree-sitter test 18 | ''; 19 | }) 20 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1710146030, 9 | "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nix-github-actions": { 22 | "inputs": { 23 | "nixpkgs": [ 24 | "nixpkgs" 25 | ] 26 | }, 27 | "locked": { 28 | "lastModified": 1703863825, 29 | "narHash": "sha256-rXwqjtwiGKJheXB43ybM8NwWB8rO2dSRrEqes0S7F5Y=", 30 | "owner": "nix-community", 31 | "repo": "nix-github-actions", 32 | "rev": "5163432afc817cf8bd1f031418d1869e4c9d5547", 33 | "type": "github" 34 | }, 35 | "original": { 36 | "owner": "nix-community", 37 | "repo": "nix-github-actions", 38 | "type": "github" 39 | } 40 | }, 41 | "nixpkgs": { 42 | "locked": { 43 | "lastModified": 1711703276, 44 | "narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=", 45 | "owner": "NixOS", 46 | "repo": "nixpkgs", 47 | "rev": "d8fe5e6c92d0d190646fb9f1056741a229980089", 48 | "type": "github" 49 | }, 50 | "original": { 51 | "owner": "NixOS", 52 | "ref": "nixos-unstable", 53 | "repo": "nixpkgs", 54 | "type": "github" 55 | } 56 | }, 57 | "root": { 58 | "inputs": { 59 | "flake-utils": "flake-utils", 60 | "nix-github-actions": "nix-github-actions", 61 | "nixpkgs": "nixpkgs" 62 | } 63 | }, 64 | "systems": { 65 | "locked": { 66 | "lastModified": 1681028828, 67 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 68 | "owner": "nix-systems", 69 | "repo": "default", 70 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 71 | "type": "github" 72 | }, 73 | "original": { 74 | "owner": "nix-systems", 75 | "repo": "default", 76 | "type": "github" 77 | } 78 | } 79 | }, 80 | "root": "root", 81 | "version": 7 82 | } 83 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "tree-sitter-nix"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 | 7 | flake-utils.url = "github:numtide/flake-utils"; 8 | 9 | nix-github-actions.url = "github:nix-community/nix-github-actions"; 10 | nix-github-actions.inputs.nixpkgs.follows = "nixpkgs"; 11 | }; 12 | 13 | outputs = { self, nixpkgs, flake-utils, nix-github-actions }: ( 14 | (flake-utils.lib.eachDefaultSystem (system: 15 | let 16 | pkgs = nixpkgs.legacyPackages.${system}; 17 | inherit (pkgs) lib; 18 | 19 | in 20 | { 21 | checks = 22 | let 23 | # shellPackages = (pkgs.callPackage ./shell.nix { }).packages; 24 | 25 | # If the generated code differs from the checked in we need 26 | # to check in the newly generated sources. 27 | mkCheck = name: check: pkgs.runCommand name 28 | { 29 | inherit (self.devShells.${system}.default) nativeBuildInputs; 30 | } '' 31 | cp -rv ${self} src 32 | chmod +w -R src 33 | cd src 34 | 35 | ${check} 36 | 37 | touch $out 38 | ''; 39 | 40 | in 41 | { 42 | build = self.packages.${system}.tree-sitter-nix; 43 | 44 | editorconfig = mkCheck "editorconfig" "editorconfig-checker"; 45 | 46 | # If the generated code differs from the checked in we need 47 | # to check in the newly generated sources. 48 | generated-diff = mkCheck "generated-diff" '' 49 | HOME=. npm run generate 50 | diff -r src/ ${self}/src 51 | ''; 52 | 53 | treefmt = mkCheck "treefmt" "treefmt --no-cache --fail-on-change"; 54 | 55 | rust-bindings = 56 | let 57 | cargo' = lib.importTOML ./Cargo.toml; 58 | in 59 | pkgs.rustPlatform.buildRustPackage { 60 | pname = cargo'.package.name; 61 | inherit (cargo'.package) version; 62 | src = self; 63 | cargoLock = { 64 | lockFile = ./Cargo.lock; 65 | }; 66 | }; 67 | 68 | } // lib.optionalAttrs (!pkgs.stdenv.isDarwin) { 69 | # Requires xcode 70 | node-bindings = 71 | let 72 | package' = lib.importJSON ./package.json; 73 | in 74 | pkgs.stdenv.mkDerivation { 75 | pname = package'.name; 76 | inherit (package') version; 77 | src = self; 78 | nativeBuildInputs = with pkgs; [ 79 | importNpmLock.hooks.npmConfigHook 80 | nodejs 81 | nodejs.passthru.python # for node-gyp 82 | npmHooks.npmBuildHook 83 | npmHooks.npmInstallHook 84 | tree-sitter 85 | ]; 86 | npmDeps = pkgs.importNpmLock { 87 | npmRoot = ./.; 88 | }; 89 | buildPhase = '' 90 | runHook preBuild 91 | ${pkgs.nodePackages.node-gyp}/bin/node-gyp configure 92 | npm run build 93 | runHook postBuild 94 | ''; 95 | installPhase = "touch $out"; 96 | }; 97 | }; 98 | 99 | packages.tree-sitter-nix = pkgs.callPackage ./default.nix { src = self; }; 100 | packages.default = self.packages.${system}.tree-sitter-nix; 101 | devShells.default = pkgs.callPackage ./shell.nix { }; 102 | 103 | formatter = pkgs.writeShellScriptBin "tree-sitter-nix-fmt" '' 104 | exec ${pkgs.treefmt}/bin/treefmt --config-file ${./treefmt.toml} "$@" 105 | ''; 106 | 107 | })) // { 108 | 109 | githubActions = nix-github-actions.lib.mkGithubMatrix { 110 | # Inherit GHA actions matrix from a subset of platforms supported by hosted runners 111 | platforms = { 112 | "x86_64-linux" = "nscloud-ubuntu-22.04-amd64-4x16"; 113 | "x86_64-darwin" = "macos-13"; 114 | "aarch64-darwin" = "macos-latest"; 115 | "aarch64-linux" = "nscloud-ubuntu-22.04-arm64-4x16"; 116 | }; 117 | checks = { 118 | inherit (self.checks) x86_64-linux; 119 | 120 | # Don't run linters on darwin as it's just scheduling overhead 121 | x86_64-darwin = builtins.removeAttrs self.checks.x86_64-darwin [ "editorconfig" "generated-diff" "treefmt" ]; 122 | }; 123 | }; 124 | 125 | } 126 | ); 127 | } 128 | -------------------------------------------------------------------------------- /grammar.js: -------------------------------------------------------------------------------- 1 | const PREC = { 2 | impl: 1, 3 | or: 2, 4 | and: 3, 5 | eq: 4, 6 | neq: 4, 7 | "<": 5, 8 | ">": 5, 9 | leq: 5, 10 | geq: 5, 11 | update: 6, 12 | not: 7, 13 | "+": 8, 14 | "-": 8, 15 | "*": 9, 16 | "/": 9, 17 | concat: 10, 18 | "?": 11, 19 | negate: 12, 20 | }; 21 | 22 | module.exports = grammar({ 23 | name: "nix", 24 | 25 | extras: ($) => [/\s/, $.comment], 26 | 27 | supertypes: ($) => [$._expression], 28 | 29 | inline: ($) => [], 30 | 31 | externals: ($) => [ 32 | $.string_fragment, 33 | $._indented_string_fragment, 34 | $._path_start, 35 | $.path_fragment, 36 | $.dollar_escape, 37 | $._indented_dollar_escape, 38 | ], 39 | 40 | word: ($) => $.keyword, 41 | 42 | conflicts: ($) => [], 43 | 44 | rules: { 45 | source_code: ($) => optional(field("expression", $._expression)), 46 | _expression: ($) => $._expr_function_expression, 47 | 48 | // Keywords go before identifiers to let them take precedence when both are expected. 49 | // Workaround before https://github.com/tree-sitter/tree-sitter/pull/246 50 | keyword: ($) => /if|then|else|let|inherit|in|rec|with|assert/, 51 | identifier: ($) => /[a-zA-Z_][a-zA-Z0-9_\'\-]*/, 52 | 53 | variable_expression: ($) => field("name", $.identifier), 54 | integer_expression: ($) => /[0-9]+/, 55 | float_expression: ($) => 56 | /(([1-9][0-9]*\.[0-9]*)|(0?\.[0-9]+))([Ee][+-]?[0-9]+)?/, 57 | 58 | path_expression: ($) => 59 | seq( 60 | alias($._path_start, $.path_fragment), 61 | repeat( 62 | choice( 63 | $.path_fragment, 64 | alias($._immediate_interpolation, $.interpolation), 65 | ), 66 | ), 67 | ), 68 | 69 | _hpath_start: ($) => /\~\/[a-zA-Z0-9\._\-\+\/]+/, 70 | hpath_expression: ($) => 71 | seq( 72 | alias($._hpath_start, $.path_fragment), 73 | repeat( 74 | choice( 75 | $.path_fragment, 76 | alias($._immediate_interpolation, $.interpolation), 77 | ), 78 | ), 79 | ), 80 | 81 | spath_expression: ($) => /<[a-zA-Z0-9\._\-\+]+(\/[a-zA-Z0-9\._\-\+]+)*>/, 82 | uri_expression: ($) => 83 | /[a-zA-Z][a-zA-Z0-9\+\-\.]*:[a-zA-Z0-9%\/\?:@\&=\+\$,\-_\.\!\~\*\']+/, 84 | 85 | _expr_function_expression: ($) => 86 | choice( 87 | $.function_expression, 88 | $.assert_expression, 89 | $.with_expression, 90 | $.let_expression, 91 | $._expr_if, 92 | ), 93 | 94 | function_expression: ($) => 95 | choice( 96 | seq( 97 | field("universal", $.identifier), 98 | ":", 99 | field("body", $._expr_function_expression), 100 | ), 101 | seq( 102 | field("formals", $.formals), 103 | ":", 104 | field("body", $._expr_function_expression), 105 | ), 106 | seq( 107 | field("formals", $.formals), 108 | "@", 109 | field("universal", $.identifier), 110 | ":", 111 | field("body", $._expr_function_expression), 112 | ), 113 | seq( 114 | field("universal", $.identifier), 115 | "@", 116 | field("formals", $.formals), 117 | ":", 118 | field("body", $._expr_function_expression), 119 | ), 120 | ), 121 | 122 | formals: ($) => 123 | choice( 124 | seq("{", "}"), 125 | seq("{", commaSep1(field("formal", $.formal)), "}"), 126 | seq( 127 | "{", 128 | commaSep1(field("formal", $.formal)), 129 | ",", 130 | field("ellipses", $.ellipses), 131 | "}", 132 | ), 133 | seq("{", field("ellipses", $.ellipses), "}"), 134 | ), 135 | formal: ($) => 136 | seq( 137 | field("name", $.identifier), 138 | optional(seq("?", field("default", $._expression))), 139 | ), 140 | ellipses: ($) => "...", 141 | 142 | assert_expression: ($) => 143 | seq( 144 | "assert", 145 | field("condition", $._expression), 146 | ";", 147 | field("body", $._expr_function_expression), 148 | ), 149 | with_expression: ($) => 150 | seq( 151 | "with", 152 | field("environment", $._expression), 153 | ";", 154 | field("body", $._expr_function_expression), 155 | ), 156 | let_expression: ($) => 157 | seq( 158 | "let", 159 | optional($.binding_set), 160 | "in", 161 | field("body", $._expr_function_expression), 162 | ), 163 | 164 | _expr_if: ($) => choice($.if_expression, $._expr_op), 165 | 166 | if_expression: ($) => 167 | seq( 168 | "if", 169 | field("condition", $._expression), 170 | "then", 171 | field("consequence", $._expression), 172 | "else", 173 | field("alternative", $._expression), 174 | ), 175 | 176 | _expr_op: ($) => 177 | choice( 178 | $.has_attr_expression, 179 | $.unary_expression, 180 | $.binary_expression, 181 | $._expr_apply_expression, 182 | ), 183 | 184 | // I choose to *not* have this among the binary operators because 185 | // this is the sole exception that takes an attrpath (instead of expression) 186 | // as its right operand. 187 | // My gut feeling is that this is: 188 | // 1) better in theory, and 189 | // 2) will be easier to work with in practice. 190 | has_attr_expression: ($) => 191 | prec( 192 | PREC["?"], 193 | seq( 194 | field("expression", $._expr_op), 195 | field("operator", "?"), 196 | field("attrpath", $.attrpath), 197 | ), 198 | ), 199 | 200 | unary_expression: ($) => 201 | choice( 202 | ...[ 203 | ["!", PREC.not], 204 | ["-", PREC.negate], 205 | ].map(([operator, precedence]) => 206 | prec( 207 | precedence, 208 | seq(field("operator", operator), field("argument", $._expr_op)), 209 | ), 210 | ), 211 | ), 212 | 213 | binary_expression: ($) => 214 | choice( 215 | // left assoc. 216 | ...[ 217 | ["==", PREC.eq], 218 | ["!=", PREC.neq], 219 | ["<", PREC["<"]], 220 | ["<=", PREC.leq], 221 | [">", PREC[">"]], 222 | [">=", PREC.geq], 223 | ["&&", PREC.and], 224 | ["||", PREC.or], 225 | ["+", PREC["+"]], 226 | ["-", PREC["-"]], 227 | ["*", PREC["*"]], 228 | ["/", PREC["/"]], 229 | ].map(([operator, precedence]) => 230 | prec.left( 231 | precedence, 232 | seq( 233 | field("left", $._expr_op), 234 | field("operator", operator), 235 | field("right", $._expr_op), 236 | ), 237 | ), 238 | ), 239 | // right assoc. 240 | ...[ 241 | ["->", PREC.impl], 242 | ["//", PREC.update], 243 | ["++", PREC.concat], 244 | ].map(([operator, precedence]) => 245 | prec.right( 246 | precedence, 247 | seq( 248 | field("left", $._expr_op), 249 | field("operator", operator), 250 | field("right", $._expr_op), 251 | ), 252 | ), 253 | ), 254 | ), 255 | 256 | _expr_apply_expression: ($) => 257 | choice($.apply_expression, $._expr_select_expression), 258 | 259 | apply_expression: ($) => 260 | seq( 261 | field("function", $._expr_apply_expression), 262 | field("argument", $._expr_select_expression), 263 | ), 264 | 265 | _expr_select_expression: ($) => choice($.select_expression, $._expr_simple), 266 | 267 | select_expression: ($) => 268 | choice( 269 | seq( 270 | field("expression", $._expr_simple), 271 | ".", 272 | field("attrpath", $.attrpath), 273 | ), 274 | seq( 275 | field("expression", $._expr_simple), 276 | ".", 277 | field("attrpath", $.attrpath), 278 | "or", 279 | field("default", $._expr_select_expression), 280 | ), 281 | ), 282 | 283 | _expr_simple: ($) => 284 | choice( 285 | $.variable_expression, 286 | $.integer_expression, 287 | $.float_expression, 288 | $.string_expression, 289 | $.indented_string_expression, 290 | $.path_expression, 291 | $.hpath_expression, 292 | $.spath_expression, 293 | $.uri_expression, 294 | $.parenthesized_expression, 295 | $.attrset_expression, 296 | $.let_attrset_expression, 297 | $.rec_attrset_expression, 298 | $.list_expression, 299 | ), 300 | 301 | parenthesized_expression: ($) => 302 | seq("(", field("expression", $._expression), ")"), 303 | 304 | attrset_expression: ($) => seq("{", optional($.binding_set), "}"), 305 | let_attrset_expression: ($) => 306 | seq("let", "{", optional($.binding_set), "}"), 307 | rec_attrset_expression: ($) => 308 | seq("rec", "{", optional($.binding_set), "}"), 309 | 310 | string_expression: ($) => 311 | seq( 312 | '"', 313 | repeat( 314 | choice( 315 | $.string_fragment, 316 | $.interpolation, 317 | choice( 318 | $.escape_sequence, 319 | seq($.dollar_escape, alias("$", $.string_fragment)), 320 | ), 321 | ), 322 | ), 323 | '"', 324 | ), 325 | 326 | escape_sequence: ($) => token.immediate(/\\([^$]|\s)/), // Can also escape newline. 327 | 328 | indented_string_expression: ($) => 329 | seq( 330 | "''", 331 | repeat( 332 | choice( 333 | alias($._indented_string_fragment, $.string_fragment), 334 | $.interpolation, 335 | choice( 336 | alias($._indented_escape_sequence, $.escape_sequence), 337 | seq( 338 | alias($._indented_dollar_escape, $.dollar_escape), 339 | alias("$", $.string_fragment), 340 | ), 341 | ), 342 | ), 343 | ), 344 | "''", 345 | ), 346 | _indented_escape_sequence: ($) => token.immediate(/'''|''\\([^$]|\s)/), // Can also escape newline. 347 | 348 | binding_set: ($) => 349 | repeat1(field("binding", choice($.binding, $.inherit, $.inherit_from))), 350 | binding: ($) => 351 | seq( 352 | field("attrpath", $.attrpath), 353 | "=", 354 | field("expression", $._expression), 355 | ";", 356 | ), 357 | inherit: ($) => seq("inherit", field("attrs", $.inherited_attrs), ";"), 358 | inherit_from: ($) => 359 | seq( 360 | "inherit", 361 | "(", 362 | field("expression", $._expression), 363 | ")", 364 | field("attrs", $.inherited_attrs), 365 | ";", 366 | ), 367 | 368 | attrpath: ($) => 369 | sep1( 370 | field( 371 | "attr", 372 | choice($.identifier, $.string_expression, $.interpolation), 373 | ), 374 | ".", 375 | ), 376 | 377 | inherited_attrs: ($) => 378 | repeat1( 379 | field( 380 | "attr", 381 | choice($.identifier, $.string_expression, $.interpolation), 382 | ), 383 | ), 384 | 385 | _immediate_interpolation: ($) => 386 | seq(token.immediate("${"), field("expression", $._expression), "}"), 387 | interpolation: ($) => seq("${", field("expression", $._expression), "}"), 388 | 389 | list_expression: ($) => 390 | seq("[", repeat(field("element", $._expr_select_expression)), "]"), 391 | 392 | comment: ($) => 393 | token(choice(seq("#", /.*/), seq("/*", /[^*]*\*+([^/*][^*]*\*+)*/, "/"))), 394 | }, 395 | }); 396 | 397 | function sep(rule, separator) { 398 | return optional(sep1(rule, separator)); 399 | } 400 | 401 | function sep1(rule, separator) { 402 | return seq(rule, repeat(seq(separator, rule))); 403 | } 404 | 405 | function commaSep1(rule) { 406 | return sep1(rule, ","); 407 | } 408 | 409 | function commaSep(rule) { 410 | return optional(commaSep1(rule)); 411 | } 412 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-nix", 3 | "version": "0.0.2", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "tree-sitter-nix", 9 | "version": "0.0.2", 10 | "license": "MIT", 11 | "dependencies": { 12 | "nan": "^2.17.0" 13 | }, 14 | "devDependencies": {} 15 | }, 16 | "node_modules/nan": { 17 | "version": "2.22.2", 18 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.22.2.tgz", 19 | "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==", 20 | "license": "MIT" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-nix", 3 | "version": "0.0.2", 4 | "description": "Tree Sitter grammar for Nix", 5 | "main": "bindings/node", 6 | "scripts": { 7 | "build": "npm run generate && node-gyp build", 8 | "generate": "tree-sitter generate --abi 13", 9 | "test": "tree-sitter test" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/nix-community/tree-sitter-nix.git" 14 | }, 15 | "author": "Charles Strahan", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/nix-community/tree-sitter-nix/issues" 19 | }, 20 | "homepage": "https://github.com/nix-community/tree-sitter-nix#readme", 21 | "dependencies": { 22 | "nan": "^2.17.0" 23 | }, 24 | "devDependencies": {}, 25 | "tree-sitter": [ 26 | { 27 | "file-types": [ 28 | "nix" 29 | ], 30 | "highlights": [ 31 | "queries/highlights.scm" 32 | ], 33 | "injection-regex": "^(nix)$", 34 | "locals": [ 35 | "queries/locals.scm" 36 | ], 37 | "scope": "source.nix" 38 | } 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /queries/highlights.scm: -------------------------------------------------------------------------------- 1 | (comment) @comment 2 | 3 | [ 4 | "if" 5 | "then" 6 | "else" 7 | "let" 8 | "inherit" 9 | "in" 10 | "rec" 11 | "with" 12 | "assert" 13 | "or" 14 | ] @keyword 15 | 16 | ((identifier) @variable.builtin 17 | (#match? @variable.builtin "^(__currentSystem|__currentTime|__nixPath|__nixVersion|__storeDir|builtins|false|null|true)$") 18 | (#is-not? local)) 19 | 20 | ((identifier) @function.builtin 21 | (#match? @function.builtin "^(__add|__addErrorContext|__all|__any|__appendContext|__attrNames|__attrValues|__bitAnd|__bitOr|__bitXor|__catAttrs|__compareVersions|__concatLists|__concatMap|__concatStringsSep|__deepSeq|__div|__elem|__elemAt|__fetchurl|__filter|__filterSource|__findFile|__foldl'|__fromJSON|__functionArgs|__genList|__genericClosure|__getAttr|__getContext|__getEnv|__hasAttr|__hasContext|__hashFile|__hashString|__head|__intersectAttrs|__isAttrs|__isBool|__isFloat|__isFunction|__isInt|__isList|__isPath|__isString|__langVersion|__length|__lessThan|__listToAttrs|__mapAttrs|__match|__mul|__parseDrvName|__partition|__path|__pathExists|__readDir|__readFile|__replaceStrings|__seq|__sort|__split|__splitVersion|__storePath|__stringLength|__sub|__substring|__tail|__toFile|__toJSON|__toPath|__toXML|__trace|__tryEval|__typeOf|__unsafeDiscardOutputDependency|__unsafeDiscardStringContext|__unsafeGetAttrPos|__valueSize|abort|baseNameOf|derivation|derivationStrict|dirOf|fetchGit|fetchMercurial|fetchTarball|fromTOML|import|isNull|map|placeholder|removeAttrs|scopedImport|throw|toString)$") 22 | (#is-not? local)) 23 | 24 | [ 25 | (integer_expression) 26 | (float_expression) 27 | ] @number 28 | 29 | (escape_sequence) @escape 30 | (dollar_escape) @escape 31 | 32 | (function_expression 33 | universal: (identifier) @variable.parameter 34 | ) 35 | 36 | (formal 37 | name: (identifier) @variable.parameter 38 | "?"? @punctuation.delimiter) 39 | 40 | (select_expression 41 | attrpath: (attrpath (identifier)) @property) 42 | 43 | (apply_expression 44 | function: [ 45 | (variable_expression (identifier)) @function 46 | (select_expression 47 | attrpath: (attrpath 48 | attr: (identifier) @function .))]) 49 | 50 | (unary_expression 51 | operator: _ @operator) 52 | 53 | (binary_expression 54 | operator: _ @operator) 55 | 56 | (variable_expression (identifier) @variable) 57 | 58 | (binding 59 | attrpath: (attrpath (identifier)) @property) 60 | 61 | (identifier) @property 62 | 63 | (inherit_from attrs: (inherited_attrs attr: (identifier) @property) ) 64 | 65 | [ 66 | ";" 67 | "." 68 | "," 69 | "=" 70 | ] @punctuation.delimiter 71 | 72 | [ 73 | "(" 74 | ")" 75 | "[" 76 | "]" 77 | "{" 78 | "}" 79 | ] @punctuation.bracket 80 | 81 | (identifier) @variable 82 | 83 | [ 84 | (string_expression) 85 | (indented_string_expression) 86 | ] @string 87 | 88 | [ 89 | (path_expression) 90 | (hpath_expression) 91 | (spath_expression) 92 | ] @string.special.path 93 | 94 | (uri_expression) @string.special.uri 95 | 96 | (interpolation 97 | "${" @punctuation.special 98 | (_) @embedded 99 | "}" @punctuation.special) 100 | -------------------------------------------------------------------------------- /queries/injections.scm: -------------------------------------------------------------------------------- 1 | ; mark arbitary languages with a comment 2 | ((((comment) @injection.language) . 3 | (indented_string_expression (string_fragment) @injection.content)) 4 | (#set! injection.combined)) 5 | 6 | ((binding 7 | attrpath: (attrpath (identifier) @_path) 8 | expression: (indented_string_expression 9 | (string_fragment) @injection.content)) 10 | (#match? @_path "(^\\w*Phase|(pre|post)\\w*|(.*\\.)?\\w*([sS]cript|[hH]ook)|(.*\\.)?startup)$") 11 | (#set! injection.language "bash") 12 | (#set! injection.combined)) 13 | 14 | ((apply_expression 15 | function: (apply_expression function: (_) @_func) 16 | argument: (indented_string_expression (string_fragment) @injection.content)) 17 | (#match? @_func "(^|\\.)writeShellScript(Bin)?$") 18 | (#set! injection.language "bash") 19 | (#set! injection.combined)) 20 | 21 | (apply_expression 22 | (apply_expression 23 | function: (apply_expression 24 | function: ((_) @_func))) 25 | argument: (indented_string_expression (string_fragment) @injection.content) 26 | (#match? @_func "(^|\\.)runCommand(((No)?(CC))?(Local)?)?$") 27 | (#set! injection.language "bash") 28 | (#set! injection.combined)) 29 | 30 | (apply_expression 31 | function: ((_) @_func) 32 | argument: (_ (_)* (_ (_)* (binding 33 | attrpath: (attrpath (identifier) @_path) 34 | expression: (indented_string_expression 35 | (string_fragment) @injection.content)))) 36 | (#match? @_func "(^|\\.)writeShellApplication$") 37 | (#match? @_path "^text$") 38 | (#set! injection.language "bash") 39 | (#set! injection.combined)) 40 | -------------------------------------------------------------------------------- /queries/locals.scm: -------------------------------------------------------------------------------- 1 | ;; when using @local.reference, tree-sitter seems to 2 | ;; apply the scope from the identifier it has looked up, 3 | ;; which makes sense for most languages. 4 | ;; however, we want to highlight things as function based on their call-site, 5 | ;; not their definition; therefore using TS's support for tracking locals 6 | ;; impedes our ability to get the highlighting we want. 7 | ;; 8 | ;; also, TS doesn't seem to support scoping as implemented in languages 9 | ;; with lazy let bindings, which results in syntax highlighting/goto-reference 10 | ;; results that depend on the order of definitions, which is counter to the 11 | ;; semantics of Nix. 12 | ;; 13 | ;; so for now we'll opt for not having any locals queries. 14 | ;; 15 | ;; see: https://github.com/tree-sitter/tree-sitter/issues/918 16 | 17 | ;(function_expression 18 | ; universal: (identifier)? @local.definition 19 | ; formals: (formals (formal name: (identifier) @local.definition)*) 20 | ; universal: (identifier)? @local.definition 21 | ; ) @local.scope 22 | ; 23 | ;(rec_attrset_expression 24 | ; bind: (binding 25 | ; attrpath: (attrpath . (attr_identifier) @local.definition)) 26 | ;) @local.scope 27 | ; 28 | ;(let_expression 29 | ; bind: (binding 30 | ; attrpath: (attrpath . (attr_identifier) @local.definition)) 31 | ;) @local.scope 32 | ; 33 | ;(identifier) @local.reference 34 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": ["config:recommended"], 4 | "lockFileMaintenance": { 5 | "enabled": true, 6 | "extends": ["schedule:weekly"] 7 | }, 8 | "nix": { 9 | "enabled": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import { } }: 2 | 3 | pkgs.mkShell { 4 | packages = [ 5 | pkgs.nodejs 6 | pkgs.python3 7 | 8 | pkgs.tree-sitter 9 | pkgs.editorconfig-checker 10 | 11 | pkgs.rustc 12 | pkgs.cargo 13 | 14 | # Formatters 15 | pkgs.treefmt 16 | pkgs.nixpkgs-fmt 17 | pkgs.nodePackages.prettier 18 | pkgs.rustfmt 19 | pkgs.clang-tools 20 | ]; 21 | } 22 | -------------------------------------------------------------------------------- /src/grammar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nix", 3 | "word": "keyword", 4 | "rules": { 5 | "source_code": { 6 | "type": "CHOICE", 7 | "members": [ 8 | { 9 | "type": "FIELD", 10 | "name": "expression", 11 | "content": { 12 | "type": "SYMBOL", 13 | "name": "_expression" 14 | } 15 | }, 16 | { 17 | "type": "BLANK" 18 | } 19 | ] 20 | }, 21 | "_expression": { 22 | "type": "SYMBOL", 23 | "name": "_expr_function_expression" 24 | }, 25 | "keyword": { 26 | "type": "PATTERN", 27 | "value": "if|then|else|let|inherit|in|rec|with|assert" 28 | }, 29 | "identifier": { 30 | "type": "PATTERN", 31 | "value": "[a-zA-Z_][a-zA-Z0-9_\\'\\-]*" 32 | }, 33 | "variable_expression": { 34 | "type": "FIELD", 35 | "name": "name", 36 | "content": { 37 | "type": "SYMBOL", 38 | "name": "identifier" 39 | } 40 | }, 41 | "integer_expression": { 42 | "type": "PATTERN", 43 | "value": "[0-9]+" 44 | }, 45 | "float_expression": { 46 | "type": "PATTERN", 47 | "value": "(([1-9][0-9]*\\.[0-9]*)|(0?\\.[0-9]+))([Ee][+-]?[0-9]+)?" 48 | }, 49 | "path_expression": { 50 | "type": "SEQ", 51 | "members": [ 52 | { 53 | "type": "ALIAS", 54 | "content": { 55 | "type": "SYMBOL", 56 | "name": "_path_start" 57 | }, 58 | "named": true, 59 | "value": "path_fragment" 60 | }, 61 | { 62 | "type": "REPEAT", 63 | "content": { 64 | "type": "CHOICE", 65 | "members": [ 66 | { 67 | "type": "SYMBOL", 68 | "name": "path_fragment" 69 | }, 70 | { 71 | "type": "ALIAS", 72 | "content": { 73 | "type": "SYMBOL", 74 | "name": "_immediate_interpolation" 75 | }, 76 | "named": true, 77 | "value": "interpolation" 78 | } 79 | ] 80 | } 81 | } 82 | ] 83 | }, 84 | "_hpath_start": { 85 | "type": "PATTERN", 86 | "value": "\\~\\/[a-zA-Z0-9\\._\\-\\+\\/]+" 87 | }, 88 | "hpath_expression": { 89 | "type": "SEQ", 90 | "members": [ 91 | { 92 | "type": "ALIAS", 93 | "content": { 94 | "type": "SYMBOL", 95 | "name": "_hpath_start" 96 | }, 97 | "named": true, 98 | "value": "path_fragment" 99 | }, 100 | { 101 | "type": "REPEAT", 102 | "content": { 103 | "type": "CHOICE", 104 | "members": [ 105 | { 106 | "type": "SYMBOL", 107 | "name": "path_fragment" 108 | }, 109 | { 110 | "type": "ALIAS", 111 | "content": { 112 | "type": "SYMBOL", 113 | "name": "_immediate_interpolation" 114 | }, 115 | "named": true, 116 | "value": "interpolation" 117 | } 118 | ] 119 | } 120 | } 121 | ] 122 | }, 123 | "spath_expression": { 124 | "type": "PATTERN", 125 | "value": "<[a-zA-Z0-9\\._\\-\\+]+(\\/[a-zA-Z0-9\\._\\-\\+]+)*>" 126 | }, 127 | "uri_expression": { 128 | "type": "PATTERN", 129 | "value": "[a-zA-Z][a-zA-Z0-9\\+\\-\\.]*:[a-zA-Z0-9%\\/\\?:@\\&=\\+\\$,\\-_\\.\\!\\~\\*\\']+" 130 | }, 131 | "_expr_function_expression": { 132 | "type": "CHOICE", 133 | "members": [ 134 | { 135 | "type": "SYMBOL", 136 | "name": "function_expression" 137 | }, 138 | { 139 | "type": "SYMBOL", 140 | "name": "assert_expression" 141 | }, 142 | { 143 | "type": "SYMBOL", 144 | "name": "with_expression" 145 | }, 146 | { 147 | "type": "SYMBOL", 148 | "name": "let_expression" 149 | }, 150 | { 151 | "type": "SYMBOL", 152 | "name": "_expr_if" 153 | } 154 | ] 155 | }, 156 | "function_expression": { 157 | "type": "CHOICE", 158 | "members": [ 159 | { 160 | "type": "SEQ", 161 | "members": [ 162 | { 163 | "type": "FIELD", 164 | "name": "universal", 165 | "content": { 166 | "type": "SYMBOL", 167 | "name": "identifier" 168 | } 169 | }, 170 | { 171 | "type": "STRING", 172 | "value": ":" 173 | }, 174 | { 175 | "type": "FIELD", 176 | "name": "body", 177 | "content": { 178 | "type": "SYMBOL", 179 | "name": "_expr_function_expression" 180 | } 181 | } 182 | ] 183 | }, 184 | { 185 | "type": "SEQ", 186 | "members": [ 187 | { 188 | "type": "FIELD", 189 | "name": "formals", 190 | "content": { 191 | "type": "SYMBOL", 192 | "name": "formals" 193 | } 194 | }, 195 | { 196 | "type": "STRING", 197 | "value": ":" 198 | }, 199 | { 200 | "type": "FIELD", 201 | "name": "body", 202 | "content": { 203 | "type": "SYMBOL", 204 | "name": "_expr_function_expression" 205 | } 206 | } 207 | ] 208 | }, 209 | { 210 | "type": "SEQ", 211 | "members": [ 212 | { 213 | "type": "FIELD", 214 | "name": "formals", 215 | "content": { 216 | "type": "SYMBOL", 217 | "name": "formals" 218 | } 219 | }, 220 | { 221 | "type": "STRING", 222 | "value": "@" 223 | }, 224 | { 225 | "type": "FIELD", 226 | "name": "universal", 227 | "content": { 228 | "type": "SYMBOL", 229 | "name": "identifier" 230 | } 231 | }, 232 | { 233 | "type": "STRING", 234 | "value": ":" 235 | }, 236 | { 237 | "type": "FIELD", 238 | "name": "body", 239 | "content": { 240 | "type": "SYMBOL", 241 | "name": "_expr_function_expression" 242 | } 243 | } 244 | ] 245 | }, 246 | { 247 | "type": "SEQ", 248 | "members": [ 249 | { 250 | "type": "FIELD", 251 | "name": "universal", 252 | "content": { 253 | "type": "SYMBOL", 254 | "name": "identifier" 255 | } 256 | }, 257 | { 258 | "type": "STRING", 259 | "value": "@" 260 | }, 261 | { 262 | "type": "FIELD", 263 | "name": "formals", 264 | "content": { 265 | "type": "SYMBOL", 266 | "name": "formals" 267 | } 268 | }, 269 | { 270 | "type": "STRING", 271 | "value": ":" 272 | }, 273 | { 274 | "type": "FIELD", 275 | "name": "body", 276 | "content": { 277 | "type": "SYMBOL", 278 | "name": "_expr_function_expression" 279 | } 280 | } 281 | ] 282 | } 283 | ] 284 | }, 285 | "formals": { 286 | "type": "CHOICE", 287 | "members": [ 288 | { 289 | "type": "SEQ", 290 | "members": [ 291 | { 292 | "type": "STRING", 293 | "value": "{" 294 | }, 295 | { 296 | "type": "STRING", 297 | "value": "}" 298 | } 299 | ] 300 | }, 301 | { 302 | "type": "SEQ", 303 | "members": [ 304 | { 305 | "type": "STRING", 306 | "value": "{" 307 | }, 308 | { 309 | "type": "SEQ", 310 | "members": [ 311 | { 312 | "type": "FIELD", 313 | "name": "formal", 314 | "content": { 315 | "type": "SYMBOL", 316 | "name": "formal" 317 | } 318 | }, 319 | { 320 | "type": "REPEAT", 321 | "content": { 322 | "type": "SEQ", 323 | "members": [ 324 | { 325 | "type": "STRING", 326 | "value": "," 327 | }, 328 | { 329 | "type": "FIELD", 330 | "name": "formal", 331 | "content": { 332 | "type": "SYMBOL", 333 | "name": "formal" 334 | } 335 | } 336 | ] 337 | } 338 | } 339 | ] 340 | }, 341 | { 342 | "type": "STRING", 343 | "value": "}" 344 | } 345 | ] 346 | }, 347 | { 348 | "type": "SEQ", 349 | "members": [ 350 | { 351 | "type": "STRING", 352 | "value": "{" 353 | }, 354 | { 355 | "type": "SEQ", 356 | "members": [ 357 | { 358 | "type": "FIELD", 359 | "name": "formal", 360 | "content": { 361 | "type": "SYMBOL", 362 | "name": "formal" 363 | } 364 | }, 365 | { 366 | "type": "REPEAT", 367 | "content": { 368 | "type": "SEQ", 369 | "members": [ 370 | { 371 | "type": "STRING", 372 | "value": "," 373 | }, 374 | { 375 | "type": "FIELD", 376 | "name": "formal", 377 | "content": { 378 | "type": "SYMBOL", 379 | "name": "formal" 380 | } 381 | } 382 | ] 383 | } 384 | } 385 | ] 386 | }, 387 | { 388 | "type": "STRING", 389 | "value": "," 390 | }, 391 | { 392 | "type": "FIELD", 393 | "name": "ellipses", 394 | "content": { 395 | "type": "SYMBOL", 396 | "name": "ellipses" 397 | } 398 | }, 399 | { 400 | "type": "STRING", 401 | "value": "}" 402 | } 403 | ] 404 | }, 405 | { 406 | "type": "SEQ", 407 | "members": [ 408 | { 409 | "type": "STRING", 410 | "value": "{" 411 | }, 412 | { 413 | "type": "FIELD", 414 | "name": "ellipses", 415 | "content": { 416 | "type": "SYMBOL", 417 | "name": "ellipses" 418 | } 419 | }, 420 | { 421 | "type": "STRING", 422 | "value": "}" 423 | } 424 | ] 425 | } 426 | ] 427 | }, 428 | "formal": { 429 | "type": "SEQ", 430 | "members": [ 431 | { 432 | "type": "FIELD", 433 | "name": "name", 434 | "content": { 435 | "type": "SYMBOL", 436 | "name": "identifier" 437 | } 438 | }, 439 | { 440 | "type": "CHOICE", 441 | "members": [ 442 | { 443 | "type": "SEQ", 444 | "members": [ 445 | { 446 | "type": "STRING", 447 | "value": "?" 448 | }, 449 | { 450 | "type": "FIELD", 451 | "name": "default", 452 | "content": { 453 | "type": "SYMBOL", 454 | "name": "_expression" 455 | } 456 | } 457 | ] 458 | }, 459 | { 460 | "type": "BLANK" 461 | } 462 | ] 463 | } 464 | ] 465 | }, 466 | "ellipses": { 467 | "type": "STRING", 468 | "value": "..." 469 | }, 470 | "assert_expression": { 471 | "type": "SEQ", 472 | "members": [ 473 | { 474 | "type": "STRING", 475 | "value": "assert" 476 | }, 477 | { 478 | "type": "FIELD", 479 | "name": "condition", 480 | "content": { 481 | "type": "SYMBOL", 482 | "name": "_expression" 483 | } 484 | }, 485 | { 486 | "type": "STRING", 487 | "value": ";" 488 | }, 489 | { 490 | "type": "FIELD", 491 | "name": "body", 492 | "content": { 493 | "type": "SYMBOL", 494 | "name": "_expr_function_expression" 495 | } 496 | } 497 | ] 498 | }, 499 | "with_expression": { 500 | "type": "SEQ", 501 | "members": [ 502 | { 503 | "type": "STRING", 504 | "value": "with" 505 | }, 506 | { 507 | "type": "FIELD", 508 | "name": "environment", 509 | "content": { 510 | "type": "SYMBOL", 511 | "name": "_expression" 512 | } 513 | }, 514 | { 515 | "type": "STRING", 516 | "value": ";" 517 | }, 518 | { 519 | "type": "FIELD", 520 | "name": "body", 521 | "content": { 522 | "type": "SYMBOL", 523 | "name": "_expr_function_expression" 524 | } 525 | } 526 | ] 527 | }, 528 | "let_expression": { 529 | "type": "SEQ", 530 | "members": [ 531 | { 532 | "type": "STRING", 533 | "value": "let" 534 | }, 535 | { 536 | "type": "CHOICE", 537 | "members": [ 538 | { 539 | "type": "SYMBOL", 540 | "name": "binding_set" 541 | }, 542 | { 543 | "type": "BLANK" 544 | } 545 | ] 546 | }, 547 | { 548 | "type": "STRING", 549 | "value": "in" 550 | }, 551 | { 552 | "type": "FIELD", 553 | "name": "body", 554 | "content": { 555 | "type": "SYMBOL", 556 | "name": "_expr_function_expression" 557 | } 558 | } 559 | ] 560 | }, 561 | "_expr_if": { 562 | "type": "CHOICE", 563 | "members": [ 564 | { 565 | "type": "SYMBOL", 566 | "name": "if_expression" 567 | }, 568 | { 569 | "type": "SYMBOL", 570 | "name": "_expr_op" 571 | } 572 | ] 573 | }, 574 | "if_expression": { 575 | "type": "SEQ", 576 | "members": [ 577 | { 578 | "type": "STRING", 579 | "value": "if" 580 | }, 581 | { 582 | "type": "FIELD", 583 | "name": "condition", 584 | "content": { 585 | "type": "SYMBOL", 586 | "name": "_expression" 587 | } 588 | }, 589 | { 590 | "type": "STRING", 591 | "value": "then" 592 | }, 593 | { 594 | "type": "FIELD", 595 | "name": "consequence", 596 | "content": { 597 | "type": "SYMBOL", 598 | "name": "_expression" 599 | } 600 | }, 601 | { 602 | "type": "STRING", 603 | "value": "else" 604 | }, 605 | { 606 | "type": "FIELD", 607 | "name": "alternative", 608 | "content": { 609 | "type": "SYMBOL", 610 | "name": "_expression" 611 | } 612 | } 613 | ] 614 | }, 615 | "_expr_op": { 616 | "type": "CHOICE", 617 | "members": [ 618 | { 619 | "type": "SYMBOL", 620 | "name": "has_attr_expression" 621 | }, 622 | { 623 | "type": "SYMBOL", 624 | "name": "unary_expression" 625 | }, 626 | { 627 | "type": "SYMBOL", 628 | "name": "binary_expression" 629 | }, 630 | { 631 | "type": "SYMBOL", 632 | "name": "_expr_apply_expression" 633 | } 634 | ] 635 | }, 636 | "has_attr_expression": { 637 | "type": "PREC", 638 | "value": 11, 639 | "content": { 640 | "type": "SEQ", 641 | "members": [ 642 | { 643 | "type": "FIELD", 644 | "name": "expression", 645 | "content": { 646 | "type": "SYMBOL", 647 | "name": "_expr_op" 648 | } 649 | }, 650 | { 651 | "type": "FIELD", 652 | "name": "operator", 653 | "content": { 654 | "type": "STRING", 655 | "value": "?" 656 | } 657 | }, 658 | { 659 | "type": "FIELD", 660 | "name": "attrpath", 661 | "content": { 662 | "type": "SYMBOL", 663 | "name": "attrpath" 664 | } 665 | } 666 | ] 667 | } 668 | }, 669 | "unary_expression": { 670 | "type": "CHOICE", 671 | "members": [ 672 | { 673 | "type": "PREC", 674 | "value": 7, 675 | "content": { 676 | "type": "SEQ", 677 | "members": [ 678 | { 679 | "type": "FIELD", 680 | "name": "operator", 681 | "content": { 682 | "type": "STRING", 683 | "value": "!" 684 | } 685 | }, 686 | { 687 | "type": "FIELD", 688 | "name": "argument", 689 | "content": { 690 | "type": "SYMBOL", 691 | "name": "_expr_op" 692 | } 693 | } 694 | ] 695 | } 696 | }, 697 | { 698 | "type": "PREC", 699 | "value": 12, 700 | "content": { 701 | "type": "SEQ", 702 | "members": [ 703 | { 704 | "type": "FIELD", 705 | "name": "operator", 706 | "content": { 707 | "type": "STRING", 708 | "value": "-" 709 | } 710 | }, 711 | { 712 | "type": "FIELD", 713 | "name": "argument", 714 | "content": { 715 | "type": "SYMBOL", 716 | "name": "_expr_op" 717 | } 718 | } 719 | ] 720 | } 721 | } 722 | ] 723 | }, 724 | "binary_expression": { 725 | "type": "CHOICE", 726 | "members": [ 727 | { 728 | "type": "PREC_LEFT", 729 | "value": 4, 730 | "content": { 731 | "type": "SEQ", 732 | "members": [ 733 | { 734 | "type": "FIELD", 735 | "name": "left", 736 | "content": { 737 | "type": "SYMBOL", 738 | "name": "_expr_op" 739 | } 740 | }, 741 | { 742 | "type": "FIELD", 743 | "name": "operator", 744 | "content": { 745 | "type": "STRING", 746 | "value": "==" 747 | } 748 | }, 749 | { 750 | "type": "FIELD", 751 | "name": "right", 752 | "content": { 753 | "type": "SYMBOL", 754 | "name": "_expr_op" 755 | } 756 | } 757 | ] 758 | } 759 | }, 760 | { 761 | "type": "PREC_LEFT", 762 | "value": 4, 763 | "content": { 764 | "type": "SEQ", 765 | "members": [ 766 | { 767 | "type": "FIELD", 768 | "name": "left", 769 | "content": { 770 | "type": "SYMBOL", 771 | "name": "_expr_op" 772 | } 773 | }, 774 | { 775 | "type": "FIELD", 776 | "name": "operator", 777 | "content": { 778 | "type": "STRING", 779 | "value": "!=" 780 | } 781 | }, 782 | { 783 | "type": "FIELD", 784 | "name": "right", 785 | "content": { 786 | "type": "SYMBOL", 787 | "name": "_expr_op" 788 | } 789 | } 790 | ] 791 | } 792 | }, 793 | { 794 | "type": "PREC_LEFT", 795 | "value": 5, 796 | "content": { 797 | "type": "SEQ", 798 | "members": [ 799 | { 800 | "type": "FIELD", 801 | "name": "left", 802 | "content": { 803 | "type": "SYMBOL", 804 | "name": "_expr_op" 805 | } 806 | }, 807 | { 808 | "type": "FIELD", 809 | "name": "operator", 810 | "content": { 811 | "type": "STRING", 812 | "value": "<" 813 | } 814 | }, 815 | { 816 | "type": "FIELD", 817 | "name": "right", 818 | "content": { 819 | "type": "SYMBOL", 820 | "name": "_expr_op" 821 | } 822 | } 823 | ] 824 | } 825 | }, 826 | { 827 | "type": "PREC_LEFT", 828 | "value": 5, 829 | "content": { 830 | "type": "SEQ", 831 | "members": [ 832 | { 833 | "type": "FIELD", 834 | "name": "left", 835 | "content": { 836 | "type": "SYMBOL", 837 | "name": "_expr_op" 838 | } 839 | }, 840 | { 841 | "type": "FIELD", 842 | "name": "operator", 843 | "content": { 844 | "type": "STRING", 845 | "value": "<=" 846 | } 847 | }, 848 | { 849 | "type": "FIELD", 850 | "name": "right", 851 | "content": { 852 | "type": "SYMBOL", 853 | "name": "_expr_op" 854 | } 855 | } 856 | ] 857 | } 858 | }, 859 | { 860 | "type": "PREC_LEFT", 861 | "value": 5, 862 | "content": { 863 | "type": "SEQ", 864 | "members": [ 865 | { 866 | "type": "FIELD", 867 | "name": "left", 868 | "content": { 869 | "type": "SYMBOL", 870 | "name": "_expr_op" 871 | } 872 | }, 873 | { 874 | "type": "FIELD", 875 | "name": "operator", 876 | "content": { 877 | "type": "STRING", 878 | "value": ">" 879 | } 880 | }, 881 | { 882 | "type": "FIELD", 883 | "name": "right", 884 | "content": { 885 | "type": "SYMBOL", 886 | "name": "_expr_op" 887 | } 888 | } 889 | ] 890 | } 891 | }, 892 | { 893 | "type": "PREC_LEFT", 894 | "value": 5, 895 | "content": { 896 | "type": "SEQ", 897 | "members": [ 898 | { 899 | "type": "FIELD", 900 | "name": "left", 901 | "content": { 902 | "type": "SYMBOL", 903 | "name": "_expr_op" 904 | } 905 | }, 906 | { 907 | "type": "FIELD", 908 | "name": "operator", 909 | "content": { 910 | "type": "STRING", 911 | "value": ">=" 912 | } 913 | }, 914 | { 915 | "type": "FIELD", 916 | "name": "right", 917 | "content": { 918 | "type": "SYMBOL", 919 | "name": "_expr_op" 920 | } 921 | } 922 | ] 923 | } 924 | }, 925 | { 926 | "type": "PREC_LEFT", 927 | "value": 3, 928 | "content": { 929 | "type": "SEQ", 930 | "members": [ 931 | { 932 | "type": "FIELD", 933 | "name": "left", 934 | "content": { 935 | "type": "SYMBOL", 936 | "name": "_expr_op" 937 | } 938 | }, 939 | { 940 | "type": "FIELD", 941 | "name": "operator", 942 | "content": { 943 | "type": "STRING", 944 | "value": "&&" 945 | } 946 | }, 947 | { 948 | "type": "FIELD", 949 | "name": "right", 950 | "content": { 951 | "type": "SYMBOL", 952 | "name": "_expr_op" 953 | } 954 | } 955 | ] 956 | } 957 | }, 958 | { 959 | "type": "PREC_LEFT", 960 | "value": 2, 961 | "content": { 962 | "type": "SEQ", 963 | "members": [ 964 | { 965 | "type": "FIELD", 966 | "name": "left", 967 | "content": { 968 | "type": "SYMBOL", 969 | "name": "_expr_op" 970 | } 971 | }, 972 | { 973 | "type": "FIELD", 974 | "name": "operator", 975 | "content": { 976 | "type": "STRING", 977 | "value": "||" 978 | } 979 | }, 980 | { 981 | "type": "FIELD", 982 | "name": "right", 983 | "content": { 984 | "type": "SYMBOL", 985 | "name": "_expr_op" 986 | } 987 | } 988 | ] 989 | } 990 | }, 991 | { 992 | "type": "PREC_LEFT", 993 | "value": 8, 994 | "content": { 995 | "type": "SEQ", 996 | "members": [ 997 | { 998 | "type": "FIELD", 999 | "name": "left", 1000 | "content": { 1001 | "type": "SYMBOL", 1002 | "name": "_expr_op" 1003 | } 1004 | }, 1005 | { 1006 | "type": "FIELD", 1007 | "name": "operator", 1008 | "content": { 1009 | "type": "STRING", 1010 | "value": "+" 1011 | } 1012 | }, 1013 | { 1014 | "type": "FIELD", 1015 | "name": "right", 1016 | "content": { 1017 | "type": "SYMBOL", 1018 | "name": "_expr_op" 1019 | } 1020 | } 1021 | ] 1022 | } 1023 | }, 1024 | { 1025 | "type": "PREC_LEFT", 1026 | "value": 8, 1027 | "content": { 1028 | "type": "SEQ", 1029 | "members": [ 1030 | { 1031 | "type": "FIELD", 1032 | "name": "left", 1033 | "content": { 1034 | "type": "SYMBOL", 1035 | "name": "_expr_op" 1036 | } 1037 | }, 1038 | { 1039 | "type": "FIELD", 1040 | "name": "operator", 1041 | "content": { 1042 | "type": "STRING", 1043 | "value": "-" 1044 | } 1045 | }, 1046 | { 1047 | "type": "FIELD", 1048 | "name": "right", 1049 | "content": { 1050 | "type": "SYMBOL", 1051 | "name": "_expr_op" 1052 | } 1053 | } 1054 | ] 1055 | } 1056 | }, 1057 | { 1058 | "type": "PREC_LEFT", 1059 | "value": 9, 1060 | "content": { 1061 | "type": "SEQ", 1062 | "members": [ 1063 | { 1064 | "type": "FIELD", 1065 | "name": "left", 1066 | "content": { 1067 | "type": "SYMBOL", 1068 | "name": "_expr_op" 1069 | } 1070 | }, 1071 | { 1072 | "type": "FIELD", 1073 | "name": "operator", 1074 | "content": { 1075 | "type": "STRING", 1076 | "value": "*" 1077 | } 1078 | }, 1079 | { 1080 | "type": "FIELD", 1081 | "name": "right", 1082 | "content": { 1083 | "type": "SYMBOL", 1084 | "name": "_expr_op" 1085 | } 1086 | } 1087 | ] 1088 | } 1089 | }, 1090 | { 1091 | "type": "PREC_LEFT", 1092 | "value": 9, 1093 | "content": { 1094 | "type": "SEQ", 1095 | "members": [ 1096 | { 1097 | "type": "FIELD", 1098 | "name": "left", 1099 | "content": { 1100 | "type": "SYMBOL", 1101 | "name": "_expr_op" 1102 | } 1103 | }, 1104 | { 1105 | "type": "FIELD", 1106 | "name": "operator", 1107 | "content": { 1108 | "type": "STRING", 1109 | "value": "/" 1110 | } 1111 | }, 1112 | { 1113 | "type": "FIELD", 1114 | "name": "right", 1115 | "content": { 1116 | "type": "SYMBOL", 1117 | "name": "_expr_op" 1118 | } 1119 | } 1120 | ] 1121 | } 1122 | }, 1123 | { 1124 | "type": "PREC_RIGHT", 1125 | "value": 1, 1126 | "content": { 1127 | "type": "SEQ", 1128 | "members": [ 1129 | { 1130 | "type": "FIELD", 1131 | "name": "left", 1132 | "content": { 1133 | "type": "SYMBOL", 1134 | "name": "_expr_op" 1135 | } 1136 | }, 1137 | { 1138 | "type": "FIELD", 1139 | "name": "operator", 1140 | "content": { 1141 | "type": "STRING", 1142 | "value": "->" 1143 | } 1144 | }, 1145 | { 1146 | "type": "FIELD", 1147 | "name": "right", 1148 | "content": { 1149 | "type": "SYMBOL", 1150 | "name": "_expr_op" 1151 | } 1152 | } 1153 | ] 1154 | } 1155 | }, 1156 | { 1157 | "type": "PREC_RIGHT", 1158 | "value": 6, 1159 | "content": { 1160 | "type": "SEQ", 1161 | "members": [ 1162 | { 1163 | "type": "FIELD", 1164 | "name": "left", 1165 | "content": { 1166 | "type": "SYMBOL", 1167 | "name": "_expr_op" 1168 | } 1169 | }, 1170 | { 1171 | "type": "FIELD", 1172 | "name": "operator", 1173 | "content": { 1174 | "type": "STRING", 1175 | "value": "//" 1176 | } 1177 | }, 1178 | { 1179 | "type": "FIELD", 1180 | "name": "right", 1181 | "content": { 1182 | "type": "SYMBOL", 1183 | "name": "_expr_op" 1184 | } 1185 | } 1186 | ] 1187 | } 1188 | }, 1189 | { 1190 | "type": "PREC_RIGHT", 1191 | "value": 10, 1192 | "content": { 1193 | "type": "SEQ", 1194 | "members": [ 1195 | { 1196 | "type": "FIELD", 1197 | "name": "left", 1198 | "content": { 1199 | "type": "SYMBOL", 1200 | "name": "_expr_op" 1201 | } 1202 | }, 1203 | { 1204 | "type": "FIELD", 1205 | "name": "operator", 1206 | "content": { 1207 | "type": "STRING", 1208 | "value": "++" 1209 | } 1210 | }, 1211 | { 1212 | "type": "FIELD", 1213 | "name": "right", 1214 | "content": { 1215 | "type": "SYMBOL", 1216 | "name": "_expr_op" 1217 | } 1218 | } 1219 | ] 1220 | } 1221 | } 1222 | ] 1223 | }, 1224 | "_expr_apply_expression": { 1225 | "type": "CHOICE", 1226 | "members": [ 1227 | { 1228 | "type": "SYMBOL", 1229 | "name": "apply_expression" 1230 | }, 1231 | { 1232 | "type": "SYMBOL", 1233 | "name": "_expr_select_expression" 1234 | } 1235 | ] 1236 | }, 1237 | "apply_expression": { 1238 | "type": "SEQ", 1239 | "members": [ 1240 | { 1241 | "type": "FIELD", 1242 | "name": "function", 1243 | "content": { 1244 | "type": "SYMBOL", 1245 | "name": "_expr_apply_expression" 1246 | } 1247 | }, 1248 | { 1249 | "type": "FIELD", 1250 | "name": "argument", 1251 | "content": { 1252 | "type": "SYMBOL", 1253 | "name": "_expr_select_expression" 1254 | } 1255 | } 1256 | ] 1257 | }, 1258 | "_expr_select_expression": { 1259 | "type": "CHOICE", 1260 | "members": [ 1261 | { 1262 | "type": "SYMBOL", 1263 | "name": "select_expression" 1264 | }, 1265 | { 1266 | "type": "SYMBOL", 1267 | "name": "_expr_simple" 1268 | } 1269 | ] 1270 | }, 1271 | "select_expression": { 1272 | "type": "CHOICE", 1273 | "members": [ 1274 | { 1275 | "type": "SEQ", 1276 | "members": [ 1277 | { 1278 | "type": "FIELD", 1279 | "name": "expression", 1280 | "content": { 1281 | "type": "SYMBOL", 1282 | "name": "_expr_simple" 1283 | } 1284 | }, 1285 | { 1286 | "type": "STRING", 1287 | "value": "." 1288 | }, 1289 | { 1290 | "type": "FIELD", 1291 | "name": "attrpath", 1292 | "content": { 1293 | "type": "SYMBOL", 1294 | "name": "attrpath" 1295 | } 1296 | } 1297 | ] 1298 | }, 1299 | { 1300 | "type": "SEQ", 1301 | "members": [ 1302 | { 1303 | "type": "FIELD", 1304 | "name": "expression", 1305 | "content": { 1306 | "type": "SYMBOL", 1307 | "name": "_expr_simple" 1308 | } 1309 | }, 1310 | { 1311 | "type": "STRING", 1312 | "value": "." 1313 | }, 1314 | { 1315 | "type": "FIELD", 1316 | "name": "attrpath", 1317 | "content": { 1318 | "type": "SYMBOL", 1319 | "name": "attrpath" 1320 | } 1321 | }, 1322 | { 1323 | "type": "STRING", 1324 | "value": "or" 1325 | }, 1326 | { 1327 | "type": "FIELD", 1328 | "name": "default", 1329 | "content": { 1330 | "type": "SYMBOL", 1331 | "name": "_expr_select_expression" 1332 | } 1333 | } 1334 | ] 1335 | } 1336 | ] 1337 | }, 1338 | "_expr_simple": { 1339 | "type": "CHOICE", 1340 | "members": [ 1341 | { 1342 | "type": "SYMBOL", 1343 | "name": "variable_expression" 1344 | }, 1345 | { 1346 | "type": "SYMBOL", 1347 | "name": "integer_expression" 1348 | }, 1349 | { 1350 | "type": "SYMBOL", 1351 | "name": "float_expression" 1352 | }, 1353 | { 1354 | "type": "SYMBOL", 1355 | "name": "string_expression" 1356 | }, 1357 | { 1358 | "type": "SYMBOL", 1359 | "name": "indented_string_expression" 1360 | }, 1361 | { 1362 | "type": "SYMBOL", 1363 | "name": "path_expression" 1364 | }, 1365 | { 1366 | "type": "SYMBOL", 1367 | "name": "hpath_expression" 1368 | }, 1369 | { 1370 | "type": "SYMBOL", 1371 | "name": "spath_expression" 1372 | }, 1373 | { 1374 | "type": "SYMBOL", 1375 | "name": "uri_expression" 1376 | }, 1377 | { 1378 | "type": "SYMBOL", 1379 | "name": "parenthesized_expression" 1380 | }, 1381 | { 1382 | "type": "SYMBOL", 1383 | "name": "attrset_expression" 1384 | }, 1385 | { 1386 | "type": "SYMBOL", 1387 | "name": "let_attrset_expression" 1388 | }, 1389 | { 1390 | "type": "SYMBOL", 1391 | "name": "rec_attrset_expression" 1392 | }, 1393 | { 1394 | "type": "SYMBOL", 1395 | "name": "list_expression" 1396 | } 1397 | ] 1398 | }, 1399 | "parenthesized_expression": { 1400 | "type": "SEQ", 1401 | "members": [ 1402 | { 1403 | "type": "STRING", 1404 | "value": "(" 1405 | }, 1406 | { 1407 | "type": "FIELD", 1408 | "name": "expression", 1409 | "content": { 1410 | "type": "SYMBOL", 1411 | "name": "_expression" 1412 | } 1413 | }, 1414 | { 1415 | "type": "STRING", 1416 | "value": ")" 1417 | } 1418 | ] 1419 | }, 1420 | "attrset_expression": { 1421 | "type": "SEQ", 1422 | "members": [ 1423 | { 1424 | "type": "STRING", 1425 | "value": "{" 1426 | }, 1427 | { 1428 | "type": "CHOICE", 1429 | "members": [ 1430 | { 1431 | "type": "SYMBOL", 1432 | "name": "binding_set" 1433 | }, 1434 | { 1435 | "type": "BLANK" 1436 | } 1437 | ] 1438 | }, 1439 | { 1440 | "type": "STRING", 1441 | "value": "}" 1442 | } 1443 | ] 1444 | }, 1445 | "let_attrset_expression": { 1446 | "type": "SEQ", 1447 | "members": [ 1448 | { 1449 | "type": "STRING", 1450 | "value": "let" 1451 | }, 1452 | { 1453 | "type": "STRING", 1454 | "value": "{" 1455 | }, 1456 | { 1457 | "type": "CHOICE", 1458 | "members": [ 1459 | { 1460 | "type": "SYMBOL", 1461 | "name": "binding_set" 1462 | }, 1463 | { 1464 | "type": "BLANK" 1465 | } 1466 | ] 1467 | }, 1468 | { 1469 | "type": "STRING", 1470 | "value": "}" 1471 | } 1472 | ] 1473 | }, 1474 | "rec_attrset_expression": { 1475 | "type": "SEQ", 1476 | "members": [ 1477 | { 1478 | "type": "STRING", 1479 | "value": "rec" 1480 | }, 1481 | { 1482 | "type": "STRING", 1483 | "value": "{" 1484 | }, 1485 | { 1486 | "type": "CHOICE", 1487 | "members": [ 1488 | { 1489 | "type": "SYMBOL", 1490 | "name": "binding_set" 1491 | }, 1492 | { 1493 | "type": "BLANK" 1494 | } 1495 | ] 1496 | }, 1497 | { 1498 | "type": "STRING", 1499 | "value": "}" 1500 | } 1501 | ] 1502 | }, 1503 | "string_expression": { 1504 | "type": "SEQ", 1505 | "members": [ 1506 | { 1507 | "type": "STRING", 1508 | "value": "\"" 1509 | }, 1510 | { 1511 | "type": "REPEAT", 1512 | "content": { 1513 | "type": "CHOICE", 1514 | "members": [ 1515 | { 1516 | "type": "SYMBOL", 1517 | "name": "string_fragment" 1518 | }, 1519 | { 1520 | "type": "SYMBOL", 1521 | "name": "interpolation" 1522 | }, 1523 | { 1524 | "type": "CHOICE", 1525 | "members": [ 1526 | { 1527 | "type": "SYMBOL", 1528 | "name": "escape_sequence" 1529 | }, 1530 | { 1531 | "type": "SEQ", 1532 | "members": [ 1533 | { 1534 | "type": "SYMBOL", 1535 | "name": "dollar_escape" 1536 | }, 1537 | { 1538 | "type": "ALIAS", 1539 | "content": { 1540 | "type": "STRING", 1541 | "value": "$" 1542 | }, 1543 | "named": true, 1544 | "value": "string_fragment" 1545 | } 1546 | ] 1547 | } 1548 | ] 1549 | } 1550 | ] 1551 | } 1552 | }, 1553 | { 1554 | "type": "STRING", 1555 | "value": "\"" 1556 | } 1557 | ] 1558 | }, 1559 | "escape_sequence": { 1560 | "type": "IMMEDIATE_TOKEN", 1561 | "content": { 1562 | "type": "PATTERN", 1563 | "value": "\\\\([^$]|\\s)" 1564 | } 1565 | }, 1566 | "indented_string_expression": { 1567 | "type": "SEQ", 1568 | "members": [ 1569 | { 1570 | "type": "STRING", 1571 | "value": "''" 1572 | }, 1573 | { 1574 | "type": "REPEAT", 1575 | "content": { 1576 | "type": "CHOICE", 1577 | "members": [ 1578 | { 1579 | "type": "ALIAS", 1580 | "content": { 1581 | "type": "SYMBOL", 1582 | "name": "_indented_string_fragment" 1583 | }, 1584 | "named": true, 1585 | "value": "string_fragment" 1586 | }, 1587 | { 1588 | "type": "SYMBOL", 1589 | "name": "interpolation" 1590 | }, 1591 | { 1592 | "type": "CHOICE", 1593 | "members": [ 1594 | { 1595 | "type": "ALIAS", 1596 | "content": { 1597 | "type": "SYMBOL", 1598 | "name": "_indented_escape_sequence" 1599 | }, 1600 | "named": true, 1601 | "value": "escape_sequence" 1602 | }, 1603 | { 1604 | "type": "SEQ", 1605 | "members": [ 1606 | { 1607 | "type": "ALIAS", 1608 | "content": { 1609 | "type": "SYMBOL", 1610 | "name": "_indented_dollar_escape" 1611 | }, 1612 | "named": true, 1613 | "value": "dollar_escape" 1614 | }, 1615 | { 1616 | "type": "ALIAS", 1617 | "content": { 1618 | "type": "STRING", 1619 | "value": "$" 1620 | }, 1621 | "named": true, 1622 | "value": "string_fragment" 1623 | } 1624 | ] 1625 | } 1626 | ] 1627 | } 1628 | ] 1629 | } 1630 | }, 1631 | { 1632 | "type": "STRING", 1633 | "value": "''" 1634 | } 1635 | ] 1636 | }, 1637 | "_indented_escape_sequence": { 1638 | "type": "IMMEDIATE_TOKEN", 1639 | "content": { 1640 | "type": "PATTERN", 1641 | "value": "'''|''\\\\([^$]|\\s)" 1642 | } 1643 | }, 1644 | "binding_set": { 1645 | "type": "REPEAT1", 1646 | "content": { 1647 | "type": "FIELD", 1648 | "name": "binding", 1649 | "content": { 1650 | "type": "CHOICE", 1651 | "members": [ 1652 | { 1653 | "type": "SYMBOL", 1654 | "name": "binding" 1655 | }, 1656 | { 1657 | "type": "SYMBOL", 1658 | "name": "inherit" 1659 | }, 1660 | { 1661 | "type": "SYMBOL", 1662 | "name": "inherit_from" 1663 | } 1664 | ] 1665 | } 1666 | } 1667 | }, 1668 | "binding": { 1669 | "type": "SEQ", 1670 | "members": [ 1671 | { 1672 | "type": "FIELD", 1673 | "name": "attrpath", 1674 | "content": { 1675 | "type": "SYMBOL", 1676 | "name": "attrpath" 1677 | } 1678 | }, 1679 | { 1680 | "type": "STRING", 1681 | "value": "=" 1682 | }, 1683 | { 1684 | "type": "FIELD", 1685 | "name": "expression", 1686 | "content": { 1687 | "type": "SYMBOL", 1688 | "name": "_expression" 1689 | } 1690 | }, 1691 | { 1692 | "type": "STRING", 1693 | "value": ";" 1694 | } 1695 | ] 1696 | }, 1697 | "inherit": { 1698 | "type": "SEQ", 1699 | "members": [ 1700 | { 1701 | "type": "STRING", 1702 | "value": "inherit" 1703 | }, 1704 | { 1705 | "type": "FIELD", 1706 | "name": "attrs", 1707 | "content": { 1708 | "type": "SYMBOL", 1709 | "name": "inherited_attrs" 1710 | } 1711 | }, 1712 | { 1713 | "type": "STRING", 1714 | "value": ";" 1715 | } 1716 | ] 1717 | }, 1718 | "inherit_from": { 1719 | "type": "SEQ", 1720 | "members": [ 1721 | { 1722 | "type": "STRING", 1723 | "value": "inherit" 1724 | }, 1725 | { 1726 | "type": "STRING", 1727 | "value": "(" 1728 | }, 1729 | { 1730 | "type": "FIELD", 1731 | "name": "expression", 1732 | "content": { 1733 | "type": "SYMBOL", 1734 | "name": "_expression" 1735 | } 1736 | }, 1737 | { 1738 | "type": "STRING", 1739 | "value": ")" 1740 | }, 1741 | { 1742 | "type": "FIELD", 1743 | "name": "attrs", 1744 | "content": { 1745 | "type": "SYMBOL", 1746 | "name": "inherited_attrs" 1747 | } 1748 | }, 1749 | { 1750 | "type": "STRING", 1751 | "value": ";" 1752 | } 1753 | ] 1754 | }, 1755 | "attrpath": { 1756 | "type": "SEQ", 1757 | "members": [ 1758 | { 1759 | "type": "FIELD", 1760 | "name": "attr", 1761 | "content": { 1762 | "type": "CHOICE", 1763 | "members": [ 1764 | { 1765 | "type": "SYMBOL", 1766 | "name": "identifier" 1767 | }, 1768 | { 1769 | "type": "SYMBOL", 1770 | "name": "string_expression" 1771 | }, 1772 | { 1773 | "type": "SYMBOL", 1774 | "name": "interpolation" 1775 | } 1776 | ] 1777 | } 1778 | }, 1779 | { 1780 | "type": "REPEAT", 1781 | "content": { 1782 | "type": "SEQ", 1783 | "members": [ 1784 | { 1785 | "type": "STRING", 1786 | "value": "." 1787 | }, 1788 | { 1789 | "type": "FIELD", 1790 | "name": "attr", 1791 | "content": { 1792 | "type": "CHOICE", 1793 | "members": [ 1794 | { 1795 | "type": "SYMBOL", 1796 | "name": "identifier" 1797 | }, 1798 | { 1799 | "type": "SYMBOL", 1800 | "name": "string_expression" 1801 | }, 1802 | { 1803 | "type": "SYMBOL", 1804 | "name": "interpolation" 1805 | } 1806 | ] 1807 | } 1808 | } 1809 | ] 1810 | } 1811 | } 1812 | ] 1813 | }, 1814 | "inherited_attrs": { 1815 | "type": "REPEAT1", 1816 | "content": { 1817 | "type": "FIELD", 1818 | "name": "attr", 1819 | "content": { 1820 | "type": "CHOICE", 1821 | "members": [ 1822 | { 1823 | "type": "SYMBOL", 1824 | "name": "identifier" 1825 | }, 1826 | { 1827 | "type": "SYMBOL", 1828 | "name": "string_expression" 1829 | }, 1830 | { 1831 | "type": "SYMBOL", 1832 | "name": "interpolation" 1833 | } 1834 | ] 1835 | } 1836 | } 1837 | }, 1838 | "_immediate_interpolation": { 1839 | "type": "SEQ", 1840 | "members": [ 1841 | { 1842 | "type": "IMMEDIATE_TOKEN", 1843 | "content": { 1844 | "type": "STRING", 1845 | "value": "${" 1846 | } 1847 | }, 1848 | { 1849 | "type": "FIELD", 1850 | "name": "expression", 1851 | "content": { 1852 | "type": "SYMBOL", 1853 | "name": "_expression" 1854 | } 1855 | }, 1856 | { 1857 | "type": "STRING", 1858 | "value": "}" 1859 | } 1860 | ] 1861 | }, 1862 | "interpolation": { 1863 | "type": "SEQ", 1864 | "members": [ 1865 | { 1866 | "type": "STRING", 1867 | "value": "${" 1868 | }, 1869 | { 1870 | "type": "FIELD", 1871 | "name": "expression", 1872 | "content": { 1873 | "type": "SYMBOL", 1874 | "name": "_expression" 1875 | } 1876 | }, 1877 | { 1878 | "type": "STRING", 1879 | "value": "}" 1880 | } 1881 | ] 1882 | }, 1883 | "list_expression": { 1884 | "type": "SEQ", 1885 | "members": [ 1886 | { 1887 | "type": "STRING", 1888 | "value": "[" 1889 | }, 1890 | { 1891 | "type": "REPEAT", 1892 | "content": { 1893 | "type": "FIELD", 1894 | "name": "element", 1895 | "content": { 1896 | "type": "SYMBOL", 1897 | "name": "_expr_select_expression" 1898 | } 1899 | } 1900 | }, 1901 | { 1902 | "type": "STRING", 1903 | "value": "]" 1904 | } 1905 | ] 1906 | }, 1907 | "comment": { 1908 | "type": "TOKEN", 1909 | "content": { 1910 | "type": "CHOICE", 1911 | "members": [ 1912 | { 1913 | "type": "SEQ", 1914 | "members": [ 1915 | { 1916 | "type": "STRING", 1917 | "value": "#" 1918 | }, 1919 | { 1920 | "type": "PATTERN", 1921 | "value": ".*" 1922 | } 1923 | ] 1924 | }, 1925 | { 1926 | "type": "SEQ", 1927 | "members": [ 1928 | { 1929 | "type": "STRING", 1930 | "value": "/*" 1931 | }, 1932 | { 1933 | "type": "PATTERN", 1934 | "value": "[^*]*\\*+([^/*][^*]*\\*+)*" 1935 | }, 1936 | { 1937 | "type": "STRING", 1938 | "value": "/" 1939 | } 1940 | ] 1941 | } 1942 | ] 1943 | } 1944 | } 1945 | }, 1946 | "extras": [ 1947 | { 1948 | "type": "PATTERN", 1949 | "value": "\\s" 1950 | }, 1951 | { 1952 | "type": "SYMBOL", 1953 | "name": "comment" 1954 | } 1955 | ], 1956 | "conflicts": [], 1957 | "precedences": [], 1958 | "externals": [ 1959 | { 1960 | "type": "SYMBOL", 1961 | "name": "string_fragment" 1962 | }, 1963 | { 1964 | "type": "SYMBOL", 1965 | "name": "_indented_string_fragment" 1966 | }, 1967 | { 1968 | "type": "SYMBOL", 1969 | "name": "_path_start" 1970 | }, 1971 | { 1972 | "type": "SYMBOL", 1973 | "name": "path_fragment" 1974 | }, 1975 | { 1976 | "type": "SYMBOL", 1977 | "name": "dollar_escape" 1978 | }, 1979 | { 1980 | "type": "SYMBOL", 1981 | "name": "_indented_dollar_escape" 1982 | } 1983 | ], 1984 | "inline": [], 1985 | "supertypes": [ 1986 | "_expression" 1987 | ] 1988 | } 1989 | 1990 | -------------------------------------------------------------------------------- /src/node-types.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "_expression", 4 | "named": true, 5 | "subtypes": [ 6 | { 7 | "type": "apply_expression", 8 | "named": true 9 | }, 10 | { 11 | "type": "assert_expression", 12 | "named": true 13 | }, 14 | { 15 | "type": "attrset_expression", 16 | "named": true 17 | }, 18 | { 19 | "type": "binary_expression", 20 | "named": true 21 | }, 22 | { 23 | "type": "float_expression", 24 | "named": true 25 | }, 26 | { 27 | "type": "function_expression", 28 | "named": true 29 | }, 30 | { 31 | "type": "has_attr_expression", 32 | "named": true 33 | }, 34 | { 35 | "type": "hpath_expression", 36 | "named": true 37 | }, 38 | { 39 | "type": "if_expression", 40 | "named": true 41 | }, 42 | { 43 | "type": "indented_string_expression", 44 | "named": true 45 | }, 46 | { 47 | "type": "integer_expression", 48 | "named": true 49 | }, 50 | { 51 | "type": "let_attrset_expression", 52 | "named": true 53 | }, 54 | { 55 | "type": "let_expression", 56 | "named": true 57 | }, 58 | { 59 | "type": "list_expression", 60 | "named": true 61 | }, 62 | { 63 | "type": "parenthesized_expression", 64 | "named": true 65 | }, 66 | { 67 | "type": "path_expression", 68 | "named": true 69 | }, 70 | { 71 | "type": "rec_attrset_expression", 72 | "named": true 73 | }, 74 | { 75 | "type": "select_expression", 76 | "named": true 77 | }, 78 | { 79 | "type": "spath_expression", 80 | "named": true 81 | }, 82 | { 83 | "type": "string_expression", 84 | "named": true 85 | }, 86 | { 87 | "type": "unary_expression", 88 | "named": true 89 | }, 90 | { 91 | "type": "uri_expression", 92 | "named": true 93 | }, 94 | { 95 | "type": "variable_expression", 96 | "named": true 97 | }, 98 | { 99 | "type": "with_expression", 100 | "named": true 101 | } 102 | ] 103 | }, 104 | { 105 | "type": "apply_expression", 106 | "named": true, 107 | "fields": { 108 | "argument": { 109 | "multiple": false, 110 | "required": true, 111 | "types": [ 112 | { 113 | "type": "attrset_expression", 114 | "named": true 115 | }, 116 | { 117 | "type": "float_expression", 118 | "named": true 119 | }, 120 | { 121 | "type": "hpath_expression", 122 | "named": true 123 | }, 124 | { 125 | "type": "indented_string_expression", 126 | "named": true 127 | }, 128 | { 129 | "type": "integer_expression", 130 | "named": true 131 | }, 132 | { 133 | "type": "let_attrset_expression", 134 | "named": true 135 | }, 136 | { 137 | "type": "list_expression", 138 | "named": true 139 | }, 140 | { 141 | "type": "parenthesized_expression", 142 | "named": true 143 | }, 144 | { 145 | "type": "path_expression", 146 | "named": true 147 | }, 148 | { 149 | "type": "rec_attrset_expression", 150 | "named": true 151 | }, 152 | { 153 | "type": "select_expression", 154 | "named": true 155 | }, 156 | { 157 | "type": "spath_expression", 158 | "named": true 159 | }, 160 | { 161 | "type": "string_expression", 162 | "named": true 163 | }, 164 | { 165 | "type": "uri_expression", 166 | "named": true 167 | }, 168 | { 169 | "type": "variable_expression", 170 | "named": true 171 | } 172 | ] 173 | }, 174 | "function": { 175 | "multiple": false, 176 | "required": true, 177 | "types": [ 178 | { 179 | "type": "apply_expression", 180 | "named": true 181 | }, 182 | { 183 | "type": "attrset_expression", 184 | "named": true 185 | }, 186 | { 187 | "type": "float_expression", 188 | "named": true 189 | }, 190 | { 191 | "type": "hpath_expression", 192 | "named": true 193 | }, 194 | { 195 | "type": "indented_string_expression", 196 | "named": true 197 | }, 198 | { 199 | "type": "integer_expression", 200 | "named": true 201 | }, 202 | { 203 | "type": "let_attrset_expression", 204 | "named": true 205 | }, 206 | { 207 | "type": "list_expression", 208 | "named": true 209 | }, 210 | { 211 | "type": "parenthesized_expression", 212 | "named": true 213 | }, 214 | { 215 | "type": "path_expression", 216 | "named": true 217 | }, 218 | { 219 | "type": "rec_attrset_expression", 220 | "named": true 221 | }, 222 | { 223 | "type": "select_expression", 224 | "named": true 225 | }, 226 | { 227 | "type": "spath_expression", 228 | "named": true 229 | }, 230 | { 231 | "type": "string_expression", 232 | "named": true 233 | }, 234 | { 235 | "type": "uri_expression", 236 | "named": true 237 | }, 238 | { 239 | "type": "variable_expression", 240 | "named": true 241 | } 242 | ] 243 | } 244 | } 245 | }, 246 | { 247 | "type": "assert_expression", 248 | "named": true, 249 | "fields": { 250 | "body": { 251 | "multiple": false, 252 | "required": true, 253 | "types": [ 254 | { 255 | "type": "apply_expression", 256 | "named": true 257 | }, 258 | { 259 | "type": "assert_expression", 260 | "named": true 261 | }, 262 | { 263 | "type": "attrset_expression", 264 | "named": true 265 | }, 266 | { 267 | "type": "binary_expression", 268 | "named": true 269 | }, 270 | { 271 | "type": "float_expression", 272 | "named": true 273 | }, 274 | { 275 | "type": "function_expression", 276 | "named": true 277 | }, 278 | { 279 | "type": "has_attr_expression", 280 | "named": true 281 | }, 282 | { 283 | "type": "hpath_expression", 284 | "named": true 285 | }, 286 | { 287 | "type": "if_expression", 288 | "named": true 289 | }, 290 | { 291 | "type": "indented_string_expression", 292 | "named": true 293 | }, 294 | { 295 | "type": "integer_expression", 296 | "named": true 297 | }, 298 | { 299 | "type": "let_attrset_expression", 300 | "named": true 301 | }, 302 | { 303 | "type": "let_expression", 304 | "named": true 305 | }, 306 | { 307 | "type": "list_expression", 308 | "named": true 309 | }, 310 | { 311 | "type": "parenthesized_expression", 312 | "named": true 313 | }, 314 | { 315 | "type": "path_expression", 316 | "named": true 317 | }, 318 | { 319 | "type": "rec_attrset_expression", 320 | "named": true 321 | }, 322 | { 323 | "type": "select_expression", 324 | "named": true 325 | }, 326 | { 327 | "type": "spath_expression", 328 | "named": true 329 | }, 330 | { 331 | "type": "string_expression", 332 | "named": true 333 | }, 334 | { 335 | "type": "unary_expression", 336 | "named": true 337 | }, 338 | { 339 | "type": "uri_expression", 340 | "named": true 341 | }, 342 | { 343 | "type": "variable_expression", 344 | "named": true 345 | }, 346 | { 347 | "type": "with_expression", 348 | "named": true 349 | } 350 | ] 351 | }, 352 | "condition": { 353 | "multiple": false, 354 | "required": true, 355 | "types": [ 356 | { 357 | "type": "_expression", 358 | "named": true 359 | } 360 | ] 361 | } 362 | } 363 | }, 364 | { 365 | "type": "attrpath", 366 | "named": true, 367 | "fields": { 368 | "attr": { 369 | "multiple": true, 370 | "required": true, 371 | "types": [ 372 | { 373 | "type": "identifier", 374 | "named": true 375 | }, 376 | { 377 | "type": "interpolation", 378 | "named": true 379 | }, 380 | { 381 | "type": "string_expression", 382 | "named": true 383 | } 384 | ] 385 | } 386 | } 387 | }, 388 | { 389 | "type": "attrset_expression", 390 | "named": true, 391 | "fields": {}, 392 | "children": { 393 | "multiple": false, 394 | "required": false, 395 | "types": [ 396 | { 397 | "type": "binding_set", 398 | "named": true 399 | } 400 | ] 401 | } 402 | }, 403 | { 404 | "type": "binary_expression", 405 | "named": true, 406 | "fields": { 407 | "left": { 408 | "multiple": false, 409 | "required": true, 410 | "types": [ 411 | { 412 | "type": "apply_expression", 413 | "named": true 414 | }, 415 | { 416 | "type": "attrset_expression", 417 | "named": true 418 | }, 419 | { 420 | "type": "binary_expression", 421 | "named": true 422 | }, 423 | { 424 | "type": "float_expression", 425 | "named": true 426 | }, 427 | { 428 | "type": "has_attr_expression", 429 | "named": true 430 | }, 431 | { 432 | "type": "hpath_expression", 433 | "named": true 434 | }, 435 | { 436 | "type": "indented_string_expression", 437 | "named": true 438 | }, 439 | { 440 | "type": "integer_expression", 441 | "named": true 442 | }, 443 | { 444 | "type": "let_attrset_expression", 445 | "named": true 446 | }, 447 | { 448 | "type": "list_expression", 449 | "named": true 450 | }, 451 | { 452 | "type": "parenthesized_expression", 453 | "named": true 454 | }, 455 | { 456 | "type": "path_expression", 457 | "named": true 458 | }, 459 | { 460 | "type": "rec_attrset_expression", 461 | "named": true 462 | }, 463 | { 464 | "type": "select_expression", 465 | "named": true 466 | }, 467 | { 468 | "type": "spath_expression", 469 | "named": true 470 | }, 471 | { 472 | "type": "string_expression", 473 | "named": true 474 | }, 475 | { 476 | "type": "unary_expression", 477 | "named": true 478 | }, 479 | { 480 | "type": "uri_expression", 481 | "named": true 482 | }, 483 | { 484 | "type": "variable_expression", 485 | "named": true 486 | } 487 | ] 488 | }, 489 | "operator": { 490 | "multiple": false, 491 | "required": true, 492 | "types": [ 493 | { 494 | "type": "!=", 495 | "named": false 496 | }, 497 | { 498 | "type": "&&", 499 | "named": false 500 | }, 501 | { 502 | "type": "*", 503 | "named": false 504 | }, 505 | { 506 | "type": "+", 507 | "named": false 508 | }, 509 | { 510 | "type": "++", 511 | "named": false 512 | }, 513 | { 514 | "type": "-", 515 | "named": false 516 | }, 517 | { 518 | "type": "->", 519 | "named": false 520 | }, 521 | { 522 | "type": "/", 523 | "named": false 524 | }, 525 | { 526 | "type": "//", 527 | "named": false 528 | }, 529 | { 530 | "type": "<", 531 | "named": false 532 | }, 533 | { 534 | "type": "<=", 535 | "named": false 536 | }, 537 | { 538 | "type": "==", 539 | "named": false 540 | }, 541 | { 542 | "type": ">", 543 | "named": false 544 | }, 545 | { 546 | "type": ">=", 547 | "named": false 548 | }, 549 | { 550 | "type": "||", 551 | "named": false 552 | } 553 | ] 554 | }, 555 | "right": { 556 | "multiple": false, 557 | "required": true, 558 | "types": [ 559 | { 560 | "type": "apply_expression", 561 | "named": true 562 | }, 563 | { 564 | "type": "attrset_expression", 565 | "named": true 566 | }, 567 | { 568 | "type": "binary_expression", 569 | "named": true 570 | }, 571 | { 572 | "type": "float_expression", 573 | "named": true 574 | }, 575 | { 576 | "type": "has_attr_expression", 577 | "named": true 578 | }, 579 | { 580 | "type": "hpath_expression", 581 | "named": true 582 | }, 583 | { 584 | "type": "indented_string_expression", 585 | "named": true 586 | }, 587 | { 588 | "type": "integer_expression", 589 | "named": true 590 | }, 591 | { 592 | "type": "let_attrset_expression", 593 | "named": true 594 | }, 595 | { 596 | "type": "list_expression", 597 | "named": true 598 | }, 599 | { 600 | "type": "parenthesized_expression", 601 | "named": true 602 | }, 603 | { 604 | "type": "path_expression", 605 | "named": true 606 | }, 607 | { 608 | "type": "rec_attrset_expression", 609 | "named": true 610 | }, 611 | { 612 | "type": "select_expression", 613 | "named": true 614 | }, 615 | { 616 | "type": "spath_expression", 617 | "named": true 618 | }, 619 | { 620 | "type": "string_expression", 621 | "named": true 622 | }, 623 | { 624 | "type": "unary_expression", 625 | "named": true 626 | }, 627 | { 628 | "type": "uri_expression", 629 | "named": true 630 | }, 631 | { 632 | "type": "variable_expression", 633 | "named": true 634 | } 635 | ] 636 | } 637 | } 638 | }, 639 | { 640 | "type": "binding", 641 | "named": true, 642 | "fields": { 643 | "attrpath": { 644 | "multiple": false, 645 | "required": true, 646 | "types": [ 647 | { 648 | "type": "attrpath", 649 | "named": true 650 | } 651 | ] 652 | }, 653 | "expression": { 654 | "multiple": false, 655 | "required": true, 656 | "types": [ 657 | { 658 | "type": "_expression", 659 | "named": true 660 | } 661 | ] 662 | } 663 | } 664 | }, 665 | { 666 | "type": "binding_set", 667 | "named": true, 668 | "fields": { 669 | "binding": { 670 | "multiple": true, 671 | "required": true, 672 | "types": [ 673 | { 674 | "type": "binding", 675 | "named": true 676 | }, 677 | { 678 | "type": "inherit", 679 | "named": true 680 | }, 681 | { 682 | "type": "inherit_from", 683 | "named": true 684 | } 685 | ] 686 | } 687 | } 688 | }, 689 | { 690 | "type": "formal", 691 | "named": true, 692 | "fields": { 693 | "default": { 694 | "multiple": false, 695 | "required": false, 696 | "types": [ 697 | { 698 | "type": "_expression", 699 | "named": true 700 | } 701 | ] 702 | }, 703 | "name": { 704 | "multiple": false, 705 | "required": true, 706 | "types": [ 707 | { 708 | "type": "identifier", 709 | "named": true 710 | } 711 | ] 712 | } 713 | } 714 | }, 715 | { 716 | "type": "formals", 717 | "named": true, 718 | "fields": { 719 | "ellipses": { 720 | "multiple": false, 721 | "required": false, 722 | "types": [ 723 | { 724 | "type": "ellipses", 725 | "named": true 726 | } 727 | ] 728 | }, 729 | "formal": { 730 | "multiple": true, 731 | "required": false, 732 | "types": [ 733 | { 734 | "type": "formal", 735 | "named": true 736 | } 737 | ] 738 | } 739 | } 740 | }, 741 | { 742 | "type": "function_expression", 743 | "named": true, 744 | "fields": { 745 | "body": { 746 | "multiple": false, 747 | "required": true, 748 | "types": [ 749 | { 750 | "type": "apply_expression", 751 | "named": true 752 | }, 753 | { 754 | "type": "assert_expression", 755 | "named": true 756 | }, 757 | { 758 | "type": "attrset_expression", 759 | "named": true 760 | }, 761 | { 762 | "type": "binary_expression", 763 | "named": true 764 | }, 765 | { 766 | "type": "float_expression", 767 | "named": true 768 | }, 769 | { 770 | "type": "function_expression", 771 | "named": true 772 | }, 773 | { 774 | "type": "has_attr_expression", 775 | "named": true 776 | }, 777 | { 778 | "type": "hpath_expression", 779 | "named": true 780 | }, 781 | { 782 | "type": "if_expression", 783 | "named": true 784 | }, 785 | { 786 | "type": "indented_string_expression", 787 | "named": true 788 | }, 789 | { 790 | "type": "integer_expression", 791 | "named": true 792 | }, 793 | { 794 | "type": "let_attrset_expression", 795 | "named": true 796 | }, 797 | { 798 | "type": "let_expression", 799 | "named": true 800 | }, 801 | { 802 | "type": "list_expression", 803 | "named": true 804 | }, 805 | { 806 | "type": "parenthesized_expression", 807 | "named": true 808 | }, 809 | { 810 | "type": "path_expression", 811 | "named": true 812 | }, 813 | { 814 | "type": "rec_attrset_expression", 815 | "named": true 816 | }, 817 | { 818 | "type": "select_expression", 819 | "named": true 820 | }, 821 | { 822 | "type": "spath_expression", 823 | "named": true 824 | }, 825 | { 826 | "type": "string_expression", 827 | "named": true 828 | }, 829 | { 830 | "type": "unary_expression", 831 | "named": true 832 | }, 833 | { 834 | "type": "uri_expression", 835 | "named": true 836 | }, 837 | { 838 | "type": "variable_expression", 839 | "named": true 840 | }, 841 | { 842 | "type": "with_expression", 843 | "named": true 844 | } 845 | ] 846 | }, 847 | "formals": { 848 | "multiple": false, 849 | "required": false, 850 | "types": [ 851 | { 852 | "type": "formals", 853 | "named": true 854 | } 855 | ] 856 | }, 857 | "universal": { 858 | "multiple": false, 859 | "required": false, 860 | "types": [ 861 | { 862 | "type": "identifier", 863 | "named": true 864 | } 865 | ] 866 | } 867 | } 868 | }, 869 | { 870 | "type": "has_attr_expression", 871 | "named": true, 872 | "fields": { 873 | "attrpath": { 874 | "multiple": false, 875 | "required": true, 876 | "types": [ 877 | { 878 | "type": "attrpath", 879 | "named": true 880 | } 881 | ] 882 | }, 883 | "expression": { 884 | "multiple": false, 885 | "required": true, 886 | "types": [ 887 | { 888 | "type": "apply_expression", 889 | "named": true 890 | }, 891 | { 892 | "type": "attrset_expression", 893 | "named": true 894 | }, 895 | { 896 | "type": "binary_expression", 897 | "named": true 898 | }, 899 | { 900 | "type": "float_expression", 901 | "named": true 902 | }, 903 | { 904 | "type": "has_attr_expression", 905 | "named": true 906 | }, 907 | { 908 | "type": "hpath_expression", 909 | "named": true 910 | }, 911 | { 912 | "type": "indented_string_expression", 913 | "named": true 914 | }, 915 | { 916 | "type": "integer_expression", 917 | "named": true 918 | }, 919 | { 920 | "type": "let_attrset_expression", 921 | "named": true 922 | }, 923 | { 924 | "type": "list_expression", 925 | "named": true 926 | }, 927 | { 928 | "type": "parenthesized_expression", 929 | "named": true 930 | }, 931 | { 932 | "type": "path_expression", 933 | "named": true 934 | }, 935 | { 936 | "type": "rec_attrset_expression", 937 | "named": true 938 | }, 939 | { 940 | "type": "select_expression", 941 | "named": true 942 | }, 943 | { 944 | "type": "spath_expression", 945 | "named": true 946 | }, 947 | { 948 | "type": "string_expression", 949 | "named": true 950 | }, 951 | { 952 | "type": "unary_expression", 953 | "named": true 954 | }, 955 | { 956 | "type": "uri_expression", 957 | "named": true 958 | }, 959 | { 960 | "type": "variable_expression", 961 | "named": true 962 | } 963 | ] 964 | }, 965 | "operator": { 966 | "multiple": false, 967 | "required": true, 968 | "types": [ 969 | { 970 | "type": "?", 971 | "named": false 972 | } 973 | ] 974 | } 975 | } 976 | }, 977 | { 978 | "type": "hpath_expression", 979 | "named": true, 980 | "fields": {}, 981 | "children": { 982 | "multiple": true, 983 | "required": true, 984 | "types": [ 985 | { 986 | "type": "interpolation", 987 | "named": true 988 | }, 989 | { 990 | "type": "path_fragment", 991 | "named": true 992 | } 993 | ] 994 | } 995 | }, 996 | { 997 | "type": "if_expression", 998 | "named": true, 999 | "fields": { 1000 | "alternative": { 1001 | "multiple": false, 1002 | "required": true, 1003 | "types": [ 1004 | { 1005 | "type": "_expression", 1006 | "named": true 1007 | } 1008 | ] 1009 | }, 1010 | "condition": { 1011 | "multiple": false, 1012 | "required": true, 1013 | "types": [ 1014 | { 1015 | "type": "_expression", 1016 | "named": true 1017 | } 1018 | ] 1019 | }, 1020 | "consequence": { 1021 | "multiple": false, 1022 | "required": true, 1023 | "types": [ 1024 | { 1025 | "type": "_expression", 1026 | "named": true 1027 | } 1028 | ] 1029 | } 1030 | } 1031 | }, 1032 | { 1033 | "type": "indented_string_expression", 1034 | "named": true, 1035 | "fields": {}, 1036 | "children": { 1037 | "multiple": true, 1038 | "required": false, 1039 | "types": [ 1040 | { 1041 | "type": "dollar_escape", 1042 | "named": true 1043 | }, 1044 | { 1045 | "type": "escape_sequence", 1046 | "named": true 1047 | }, 1048 | { 1049 | "type": "interpolation", 1050 | "named": true 1051 | }, 1052 | { 1053 | "type": "string_fragment", 1054 | "named": true 1055 | } 1056 | ] 1057 | } 1058 | }, 1059 | { 1060 | "type": "inherit", 1061 | "named": true, 1062 | "fields": { 1063 | "attrs": { 1064 | "multiple": false, 1065 | "required": true, 1066 | "types": [ 1067 | { 1068 | "type": "inherited_attrs", 1069 | "named": true 1070 | } 1071 | ] 1072 | } 1073 | } 1074 | }, 1075 | { 1076 | "type": "inherit_from", 1077 | "named": true, 1078 | "fields": { 1079 | "attrs": { 1080 | "multiple": false, 1081 | "required": true, 1082 | "types": [ 1083 | { 1084 | "type": "inherited_attrs", 1085 | "named": true 1086 | } 1087 | ] 1088 | }, 1089 | "expression": { 1090 | "multiple": false, 1091 | "required": true, 1092 | "types": [ 1093 | { 1094 | "type": "_expression", 1095 | "named": true 1096 | } 1097 | ] 1098 | } 1099 | } 1100 | }, 1101 | { 1102 | "type": "inherited_attrs", 1103 | "named": true, 1104 | "fields": { 1105 | "attr": { 1106 | "multiple": true, 1107 | "required": true, 1108 | "types": [ 1109 | { 1110 | "type": "identifier", 1111 | "named": true 1112 | }, 1113 | { 1114 | "type": "interpolation", 1115 | "named": true 1116 | }, 1117 | { 1118 | "type": "string_expression", 1119 | "named": true 1120 | } 1121 | ] 1122 | } 1123 | } 1124 | }, 1125 | { 1126 | "type": "interpolation", 1127 | "named": true, 1128 | "fields": { 1129 | "expression": { 1130 | "multiple": false, 1131 | "required": true, 1132 | "types": [ 1133 | { 1134 | "type": "_expression", 1135 | "named": true 1136 | } 1137 | ] 1138 | } 1139 | } 1140 | }, 1141 | { 1142 | "type": "let_attrset_expression", 1143 | "named": true, 1144 | "fields": {}, 1145 | "children": { 1146 | "multiple": false, 1147 | "required": false, 1148 | "types": [ 1149 | { 1150 | "type": "binding_set", 1151 | "named": true 1152 | } 1153 | ] 1154 | } 1155 | }, 1156 | { 1157 | "type": "let_expression", 1158 | "named": true, 1159 | "fields": { 1160 | "body": { 1161 | "multiple": false, 1162 | "required": true, 1163 | "types": [ 1164 | { 1165 | "type": "apply_expression", 1166 | "named": true 1167 | }, 1168 | { 1169 | "type": "assert_expression", 1170 | "named": true 1171 | }, 1172 | { 1173 | "type": "attrset_expression", 1174 | "named": true 1175 | }, 1176 | { 1177 | "type": "binary_expression", 1178 | "named": true 1179 | }, 1180 | { 1181 | "type": "float_expression", 1182 | "named": true 1183 | }, 1184 | { 1185 | "type": "function_expression", 1186 | "named": true 1187 | }, 1188 | { 1189 | "type": "has_attr_expression", 1190 | "named": true 1191 | }, 1192 | { 1193 | "type": "hpath_expression", 1194 | "named": true 1195 | }, 1196 | { 1197 | "type": "if_expression", 1198 | "named": true 1199 | }, 1200 | { 1201 | "type": "indented_string_expression", 1202 | "named": true 1203 | }, 1204 | { 1205 | "type": "integer_expression", 1206 | "named": true 1207 | }, 1208 | { 1209 | "type": "let_attrset_expression", 1210 | "named": true 1211 | }, 1212 | { 1213 | "type": "let_expression", 1214 | "named": true 1215 | }, 1216 | { 1217 | "type": "list_expression", 1218 | "named": true 1219 | }, 1220 | { 1221 | "type": "parenthesized_expression", 1222 | "named": true 1223 | }, 1224 | { 1225 | "type": "path_expression", 1226 | "named": true 1227 | }, 1228 | { 1229 | "type": "rec_attrset_expression", 1230 | "named": true 1231 | }, 1232 | { 1233 | "type": "select_expression", 1234 | "named": true 1235 | }, 1236 | { 1237 | "type": "spath_expression", 1238 | "named": true 1239 | }, 1240 | { 1241 | "type": "string_expression", 1242 | "named": true 1243 | }, 1244 | { 1245 | "type": "unary_expression", 1246 | "named": true 1247 | }, 1248 | { 1249 | "type": "uri_expression", 1250 | "named": true 1251 | }, 1252 | { 1253 | "type": "variable_expression", 1254 | "named": true 1255 | }, 1256 | { 1257 | "type": "with_expression", 1258 | "named": true 1259 | } 1260 | ] 1261 | } 1262 | }, 1263 | "children": { 1264 | "multiple": false, 1265 | "required": false, 1266 | "types": [ 1267 | { 1268 | "type": "binding_set", 1269 | "named": true 1270 | } 1271 | ] 1272 | } 1273 | }, 1274 | { 1275 | "type": "list_expression", 1276 | "named": true, 1277 | "fields": { 1278 | "element": { 1279 | "multiple": true, 1280 | "required": false, 1281 | "types": [ 1282 | { 1283 | "type": "attrset_expression", 1284 | "named": true 1285 | }, 1286 | { 1287 | "type": "float_expression", 1288 | "named": true 1289 | }, 1290 | { 1291 | "type": "hpath_expression", 1292 | "named": true 1293 | }, 1294 | { 1295 | "type": "indented_string_expression", 1296 | "named": true 1297 | }, 1298 | { 1299 | "type": "integer_expression", 1300 | "named": true 1301 | }, 1302 | { 1303 | "type": "let_attrset_expression", 1304 | "named": true 1305 | }, 1306 | { 1307 | "type": "list_expression", 1308 | "named": true 1309 | }, 1310 | { 1311 | "type": "parenthesized_expression", 1312 | "named": true 1313 | }, 1314 | { 1315 | "type": "path_expression", 1316 | "named": true 1317 | }, 1318 | { 1319 | "type": "rec_attrset_expression", 1320 | "named": true 1321 | }, 1322 | { 1323 | "type": "select_expression", 1324 | "named": true 1325 | }, 1326 | { 1327 | "type": "spath_expression", 1328 | "named": true 1329 | }, 1330 | { 1331 | "type": "string_expression", 1332 | "named": true 1333 | }, 1334 | { 1335 | "type": "uri_expression", 1336 | "named": true 1337 | }, 1338 | { 1339 | "type": "variable_expression", 1340 | "named": true 1341 | } 1342 | ] 1343 | } 1344 | } 1345 | }, 1346 | { 1347 | "type": "parenthesized_expression", 1348 | "named": true, 1349 | "fields": { 1350 | "expression": { 1351 | "multiple": false, 1352 | "required": true, 1353 | "types": [ 1354 | { 1355 | "type": "_expression", 1356 | "named": true 1357 | } 1358 | ] 1359 | } 1360 | } 1361 | }, 1362 | { 1363 | "type": "path_expression", 1364 | "named": true, 1365 | "fields": {}, 1366 | "children": { 1367 | "multiple": true, 1368 | "required": true, 1369 | "types": [ 1370 | { 1371 | "type": "interpolation", 1372 | "named": true 1373 | }, 1374 | { 1375 | "type": "path_fragment", 1376 | "named": true 1377 | } 1378 | ] 1379 | } 1380 | }, 1381 | { 1382 | "type": "rec_attrset_expression", 1383 | "named": true, 1384 | "fields": {}, 1385 | "children": { 1386 | "multiple": false, 1387 | "required": false, 1388 | "types": [ 1389 | { 1390 | "type": "binding_set", 1391 | "named": true 1392 | } 1393 | ] 1394 | } 1395 | }, 1396 | { 1397 | "type": "select_expression", 1398 | "named": true, 1399 | "fields": { 1400 | "attrpath": { 1401 | "multiple": false, 1402 | "required": true, 1403 | "types": [ 1404 | { 1405 | "type": "attrpath", 1406 | "named": true 1407 | } 1408 | ] 1409 | }, 1410 | "default": { 1411 | "multiple": false, 1412 | "required": false, 1413 | "types": [ 1414 | { 1415 | "type": "attrset_expression", 1416 | "named": true 1417 | }, 1418 | { 1419 | "type": "float_expression", 1420 | "named": true 1421 | }, 1422 | { 1423 | "type": "hpath_expression", 1424 | "named": true 1425 | }, 1426 | { 1427 | "type": "indented_string_expression", 1428 | "named": true 1429 | }, 1430 | { 1431 | "type": "integer_expression", 1432 | "named": true 1433 | }, 1434 | { 1435 | "type": "let_attrset_expression", 1436 | "named": true 1437 | }, 1438 | { 1439 | "type": "list_expression", 1440 | "named": true 1441 | }, 1442 | { 1443 | "type": "parenthesized_expression", 1444 | "named": true 1445 | }, 1446 | { 1447 | "type": "path_expression", 1448 | "named": true 1449 | }, 1450 | { 1451 | "type": "rec_attrset_expression", 1452 | "named": true 1453 | }, 1454 | { 1455 | "type": "select_expression", 1456 | "named": true 1457 | }, 1458 | { 1459 | "type": "spath_expression", 1460 | "named": true 1461 | }, 1462 | { 1463 | "type": "string_expression", 1464 | "named": true 1465 | }, 1466 | { 1467 | "type": "uri_expression", 1468 | "named": true 1469 | }, 1470 | { 1471 | "type": "variable_expression", 1472 | "named": true 1473 | } 1474 | ] 1475 | }, 1476 | "expression": { 1477 | "multiple": false, 1478 | "required": true, 1479 | "types": [ 1480 | { 1481 | "type": "attrset_expression", 1482 | "named": true 1483 | }, 1484 | { 1485 | "type": "float_expression", 1486 | "named": true 1487 | }, 1488 | { 1489 | "type": "hpath_expression", 1490 | "named": true 1491 | }, 1492 | { 1493 | "type": "indented_string_expression", 1494 | "named": true 1495 | }, 1496 | { 1497 | "type": "integer_expression", 1498 | "named": true 1499 | }, 1500 | { 1501 | "type": "let_attrset_expression", 1502 | "named": true 1503 | }, 1504 | { 1505 | "type": "list_expression", 1506 | "named": true 1507 | }, 1508 | { 1509 | "type": "parenthesized_expression", 1510 | "named": true 1511 | }, 1512 | { 1513 | "type": "path_expression", 1514 | "named": true 1515 | }, 1516 | { 1517 | "type": "rec_attrset_expression", 1518 | "named": true 1519 | }, 1520 | { 1521 | "type": "spath_expression", 1522 | "named": true 1523 | }, 1524 | { 1525 | "type": "string_expression", 1526 | "named": true 1527 | }, 1528 | { 1529 | "type": "uri_expression", 1530 | "named": true 1531 | }, 1532 | { 1533 | "type": "variable_expression", 1534 | "named": true 1535 | } 1536 | ] 1537 | } 1538 | } 1539 | }, 1540 | { 1541 | "type": "source_code", 1542 | "named": true, 1543 | "fields": { 1544 | "expression": { 1545 | "multiple": false, 1546 | "required": false, 1547 | "types": [ 1548 | { 1549 | "type": "_expression", 1550 | "named": true 1551 | } 1552 | ] 1553 | } 1554 | } 1555 | }, 1556 | { 1557 | "type": "string_expression", 1558 | "named": true, 1559 | "fields": {}, 1560 | "children": { 1561 | "multiple": true, 1562 | "required": false, 1563 | "types": [ 1564 | { 1565 | "type": "dollar_escape", 1566 | "named": true 1567 | }, 1568 | { 1569 | "type": "escape_sequence", 1570 | "named": true 1571 | }, 1572 | { 1573 | "type": "interpolation", 1574 | "named": true 1575 | }, 1576 | { 1577 | "type": "string_fragment", 1578 | "named": true 1579 | } 1580 | ] 1581 | } 1582 | }, 1583 | { 1584 | "type": "unary_expression", 1585 | "named": true, 1586 | "fields": { 1587 | "argument": { 1588 | "multiple": false, 1589 | "required": true, 1590 | "types": [ 1591 | { 1592 | "type": "apply_expression", 1593 | "named": true 1594 | }, 1595 | { 1596 | "type": "attrset_expression", 1597 | "named": true 1598 | }, 1599 | { 1600 | "type": "binary_expression", 1601 | "named": true 1602 | }, 1603 | { 1604 | "type": "float_expression", 1605 | "named": true 1606 | }, 1607 | { 1608 | "type": "has_attr_expression", 1609 | "named": true 1610 | }, 1611 | { 1612 | "type": "hpath_expression", 1613 | "named": true 1614 | }, 1615 | { 1616 | "type": "indented_string_expression", 1617 | "named": true 1618 | }, 1619 | { 1620 | "type": "integer_expression", 1621 | "named": true 1622 | }, 1623 | { 1624 | "type": "let_attrset_expression", 1625 | "named": true 1626 | }, 1627 | { 1628 | "type": "list_expression", 1629 | "named": true 1630 | }, 1631 | { 1632 | "type": "parenthesized_expression", 1633 | "named": true 1634 | }, 1635 | { 1636 | "type": "path_expression", 1637 | "named": true 1638 | }, 1639 | { 1640 | "type": "rec_attrset_expression", 1641 | "named": true 1642 | }, 1643 | { 1644 | "type": "select_expression", 1645 | "named": true 1646 | }, 1647 | { 1648 | "type": "spath_expression", 1649 | "named": true 1650 | }, 1651 | { 1652 | "type": "string_expression", 1653 | "named": true 1654 | }, 1655 | { 1656 | "type": "unary_expression", 1657 | "named": true 1658 | }, 1659 | { 1660 | "type": "uri_expression", 1661 | "named": true 1662 | }, 1663 | { 1664 | "type": "variable_expression", 1665 | "named": true 1666 | } 1667 | ] 1668 | }, 1669 | "operator": { 1670 | "multiple": false, 1671 | "required": true, 1672 | "types": [ 1673 | { 1674 | "type": "!", 1675 | "named": false 1676 | }, 1677 | { 1678 | "type": "-", 1679 | "named": false 1680 | } 1681 | ] 1682 | } 1683 | } 1684 | }, 1685 | { 1686 | "type": "variable_expression", 1687 | "named": true, 1688 | "fields": { 1689 | "name": { 1690 | "multiple": false, 1691 | "required": true, 1692 | "types": [ 1693 | { 1694 | "type": "identifier", 1695 | "named": true 1696 | } 1697 | ] 1698 | } 1699 | } 1700 | }, 1701 | { 1702 | "type": "with_expression", 1703 | "named": true, 1704 | "fields": { 1705 | "body": { 1706 | "multiple": false, 1707 | "required": true, 1708 | "types": [ 1709 | { 1710 | "type": "apply_expression", 1711 | "named": true 1712 | }, 1713 | { 1714 | "type": "assert_expression", 1715 | "named": true 1716 | }, 1717 | { 1718 | "type": "attrset_expression", 1719 | "named": true 1720 | }, 1721 | { 1722 | "type": "binary_expression", 1723 | "named": true 1724 | }, 1725 | { 1726 | "type": "float_expression", 1727 | "named": true 1728 | }, 1729 | { 1730 | "type": "function_expression", 1731 | "named": true 1732 | }, 1733 | { 1734 | "type": "has_attr_expression", 1735 | "named": true 1736 | }, 1737 | { 1738 | "type": "hpath_expression", 1739 | "named": true 1740 | }, 1741 | { 1742 | "type": "if_expression", 1743 | "named": true 1744 | }, 1745 | { 1746 | "type": "indented_string_expression", 1747 | "named": true 1748 | }, 1749 | { 1750 | "type": "integer_expression", 1751 | "named": true 1752 | }, 1753 | { 1754 | "type": "let_attrset_expression", 1755 | "named": true 1756 | }, 1757 | { 1758 | "type": "let_expression", 1759 | "named": true 1760 | }, 1761 | { 1762 | "type": "list_expression", 1763 | "named": true 1764 | }, 1765 | { 1766 | "type": "parenthesized_expression", 1767 | "named": true 1768 | }, 1769 | { 1770 | "type": "path_expression", 1771 | "named": true 1772 | }, 1773 | { 1774 | "type": "rec_attrset_expression", 1775 | "named": true 1776 | }, 1777 | { 1778 | "type": "select_expression", 1779 | "named": true 1780 | }, 1781 | { 1782 | "type": "spath_expression", 1783 | "named": true 1784 | }, 1785 | { 1786 | "type": "string_expression", 1787 | "named": true 1788 | }, 1789 | { 1790 | "type": "unary_expression", 1791 | "named": true 1792 | }, 1793 | { 1794 | "type": "uri_expression", 1795 | "named": true 1796 | }, 1797 | { 1798 | "type": "variable_expression", 1799 | "named": true 1800 | }, 1801 | { 1802 | "type": "with_expression", 1803 | "named": true 1804 | } 1805 | ] 1806 | }, 1807 | "environment": { 1808 | "multiple": false, 1809 | "required": true, 1810 | "types": [ 1811 | { 1812 | "type": "_expression", 1813 | "named": true 1814 | } 1815 | ] 1816 | } 1817 | } 1818 | }, 1819 | { 1820 | "type": "!", 1821 | "named": false 1822 | }, 1823 | { 1824 | "type": "!=", 1825 | "named": false 1826 | }, 1827 | { 1828 | "type": "\"", 1829 | "named": false 1830 | }, 1831 | { 1832 | "type": "${", 1833 | "named": false 1834 | }, 1835 | { 1836 | "type": "&&", 1837 | "named": false 1838 | }, 1839 | { 1840 | "type": "''", 1841 | "named": false 1842 | }, 1843 | { 1844 | "type": "(", 1845 | "named": false 1846 | }, 1847 | { 1848 | "type": ")", 1849 | "named": false 1850 | }, 1851 | { 1852 | "type": "*", 1853 | "named": false 1854 | }, 1855 | { 1856 | "type": "+", 1857 | "named": false 1858 | }, 1859 | { 1860 | "type": "++", 1861 | "named": false 1862 | }, 1863 | { 1864 | "type": ",", 1865 | "named": false 1866 | }, 1867 | { 1868 | "type": "-", 1869 | "named": false 1870 | }, 1871 | { 1872 | "type": "->", 1873 | "named": false 1874 | }, 1875 | { 1876 | "type": ".", 1877 | "named": false 1878 | }, 1879 | { 1880 | "type": "/", 1881 | "named": false 1882 | }, 1883 | { 1884 | "type": "//", 1885 | "named": false 1886 | }, 1887 | { 1888 | "type": ":", 1889 | "named": false 1890 | }, 1891 | { 1892 | "type": ";", 1893 | "named": false 1894 | }, 1895 | { 1896 | "type": "<", 1897 | "named": false 1898 | }, 1899 | { 1900 | "type": "<=", 1901 | "named": false 1902 | }, 1903 | { 1904 | "type": "=", 1905 | "named": false 1906 | }, 1907 | { 1908 | "type": "==", 1909 | "named": false 1910 | }, 1911 | { 1912 | "type": ">", 1913 | "named": false 1914 | }, 1915 | { 1916 | "type": ">=", 1917 | "named": false 1918 | }, 1919 | { 1920 | "type": "?", 1921 | "named": false 1922 | }, 1923 | { 1924 | "type": "@", 1925 | "named": false 1926 | }, 1927 | { 1928 | "type": "[", 1929 | "named": false 1930 | }, 1931 | { 1932 | "type": "]", 1933 | "named": false 1934 | }, 1935 | { 1936 | "type": "assert", 1937 | "named": false 1938 | }, 1939 | { 1940 | "type": "comment", 1941 | "named": true 1942 | }, 1943 | { 1944 | "type": "dollar_escape", 1945 | "named": true 1946 | }, 1947 | { 1948 | "type": "ellipses", 1949 | "named": true 1950 | }, 1951 | { 1952 | "type": "else", 1953 | "named": false 1954 | }, 1955 | { 1956 | "type": "escape_sequence", 1957 | "named": true 1958 | }, 1959 | { 1960 | "type": "float_expression", 1961 | "named": true 1962 | }, 1963 | { 1964 | "type": "identifier", 1965 | "named": true 1966 | }, 1967 | { 1968 | "type": "if", 1969 | "named": false 1970 | }, 1971 | { 1972 | "type": "in", 1973 | "named": false 1974 | }, 1975 | { 1976 | "type": "inherit", 1977 | "named": false 1978 | }, 1979 | { 1980 | "type": "integer_expression", 1981 | "named": true 1982 | }, 1983 | { 1984 | "type": "let", 1985 | "named": false 1986 | }, 1987 | { 1988 | "type": "or", 1989 | "named": false 1990 | }, 1991 | { 1992 | "type": "path_fragment", 1993 | "named": true 1994 | }, 1995 | { 1996 | "type": "rec", 1997 | "named": false 1998 | }, 1999 | { 2000 | "type": "spath_expression", 2001 | "named": true 2002 | }, 2003 | { 2004 | "type": "string_fragment", 2005 | "named": true 2006 | }, 2007 | { 2008 | "type": "then", 2009 | "named": false 2010 | }, 2011 | { 2012 | "type": "uri_expression", 2013 | "named": true 2014 | }, 2015 | { 2016 | "type": "with", 2017 | "named": false 2018 | }, 2019 | { 2020 | "type": "{", 2021 | "named": false 2022 | }, 2023 | { 2024 | "type": "||", 2025 | "named": false 2026 | }, 2027 | { 2028 | "type": "}", 2029 | "named": false 2030 | } 2031 | ] -------------------------------------------------------------------------------- /src/scanner.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | enum TokenType { 4 | STRING_FRAGMENT, 5 | INDENTED_STRING_FRAGMENT, 6 | PATH_START, 7 | PATH_FRAGMENT, 8 | DOLLAR_ESCAPE, 9 | INDENTED_DOLLAR_ESCAPE, 10 | }; 11 | 12 | static void advance(TSLexer *lexer) { lexer->advance(lexer, false); } 13 | 14 | static void skip(TSLexer *lexer) { lexer->advance(lexer, true); } 15 | 16 | static bool scan_dollar_escape(TSLexer *lexer) { 17 | lexer->result_symbol = DOLLAR_ESCAPE; 18 | advance(lexer); 19 | lexer->mark_end(lexer); 20 | if (lexer->lookahead == '$') { 21 | return true; 22 | } else { 23 | return false; 24 | } 25 | } 26 | 27 | static bool scan_indented_dollar_escape(TSLexer *lexer) { 28 | lexer->result_symbol = INDENTED_DOLLAR_ESCAPE; 29 | advance(lexer); 30 | lexer->mark_end(lexer); 31 | if (lexer->lookahead == '$') { 32 | return true; 33 | } else { 34 | if (lexer->lookahead == '\\') { 35 | advance(lexer); 36 | if (lexer->lookahead == '$') { 37 | lexer->mark_end(lexer); 38 | return true; 39 | } 40 | } 41 | return false; 42 | } 43 | } 44 | 45 | // Here we only parse literal fragment inside a string. 46 | // Delimiter, interpolation and escape sequence are handled by the parser and we 47 | // simply stop at them. 48 | // 49 | // The implementation is inspired by tree-sitter-javascript: 50 | // https://github.com/tree-sitter/tree-sitter-javascript/blob/fdeb68ac8d2bd5a78b943528bb68ceda3aade2eb/src/scanner.c#L19 51 | static bool scan_string_fragment(TSLexer *lexer) { 52 | lexer->result_symbol = STRING_FRAGMENT; 53 | for (bool has_content = false;; has_content = true) { 54 | lexer->mark_end(lexer); 55 | switch (lexer->lookahead) { 56 | case '"': 57 | case '\\': 58 | return has_content; 59 | case '$': 60 | advance(lexer); 61 | if (lexer->lookahead == '{') { 62 | return has_content; 63 | } else if (lexer->lookahead != '"' && lexer->lookahead != '\\') { 64 | // Any char following '$' other than '"', '\\' and '{' (which was 65 | // handled above) should be consumed as additional string content. This 66 | // means `$${` doesn't start an interpolation, but `$$${` does. 67 | advance(lexer); 68 | } 69 | break; 70 | // Simply give up on EOF or '\0'. 71 | case '\0': 72 | return false; 73 | default: 74 | advance(lexer); 75 | } 76 | } 77 | } 78 | 79 | // See comments of scan_string_fragment. 80 | static bool scan_indented_string_fragment(TSLexer *lexer) { 81 | lexer->result_symbol = INDENTED_STRING_FRAGMENT; 82 | for (bool has_content = false;; has_content = true) { 83 | lexer->mark_end(lexer); 84 | switch (lexer->lookahead) { 85 | case '$': 86 | advance(lexer); 87 | if (lexer->lookahead == '{') { 88 | return has_content; 89 | } else if (lexer->lookahead != '\'') { 90 | // Any char following '$' other than '\'' and '{' (which was handled 91 | // above) should be consumed as additional string content. This means 92 | // `$${` doesn't start an interpolation, but `$$${` does. 93 | advance(lexer); 94 | } 95 | break; 96 | case '\'': 97 | advance(lexer); 98 | if (lexer->lookahead == '\'') { 99 | // Two single quotes always stop current string fragment. 100 | // It can be either an end delimiter '', or escape sequences ''', ''$, 101 | // ''\ 102 | return has_content; 103 | } 104 | break; 105 | // Simply give up on EOF or '\0'. 106 | case '\0': 107 | return false; 108 | default: 109 | advance(lexer); 110 | } 111 | } 112 | } 113 | 114 | static bool is_path_char(int32_t c) { 115 | return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || 116 | (c >= 'A' && c <= 'Z') || c == '-' || c == '+' || c == '_' || 117 | c == '.' || c == '/'; 118 | } 119 | 120 | static bool scan_path_start(TSLexer *lexer) { 121 | lexer->result_symbol = PATH_START; 122 | 123 | bool have_sep = false; 124 | bool have_after_sep = false; 125 | int32_t c = lexer->lookahead; 126 | 127 | // unlike string_fragments which which are preceded by initial token (i.e. 128 | // '"') and thus will have all leading external whitespace consumed, we have 129 | // no such luxury with the path_start token. 130 | // 131 | // so we must skip over any leading whitespace here. 132 | while (c == ' ' || c == '\n' || c == '\r' || c == '\t') { 133 | skip(lexer); 134 | c = lexer->lookahead; 135 | } 136 | 137 | while (true) { 138 | lexer->mark_end(lexer); 139 | c = lexer->lookahead; 140 | 141 | if (c == '/') { 142 | have_sep = true; 143 | } else if (is_path_char(c)) { 144 | if (have_sep) { 145 | have_after_sep = true; 146 | } 147 | } else if (c == '$') { 148 | // starting a interpolation, 149 | // so we have a valid token as long as we've seen a separator. 150 | // example: a/${x} 151 | return have_sep; 152 | } else { 153 | // we have a valid token if we've consumed anything after a separator. 154 | // example: a/b 155 | return have_after_sep; 156 | } 157 | 158 | advance(lexer); 159 | } 160 | } 161 | 162 | static bool scan_path_fragment(TSLexer *lexer) { 163 | lexer->result_symbol = PATH_FRAGMENT; 164 | 165 | for (bool has_content = false;; has_content = true) { 166 | lexer->mark_end(lexer); 167 | if (!is_path_char(lexer->lookahead)) { 168 | return has_content; 169 | } 170 | advance(lexer); 171 | } 172 | } 173 | 174 | void *tree_sitter_nix_external_scanner_create() { return NULL; } 175 | 176 | bool tree_sitter_nix_external_scanner_scan(void *payload, TSLexer *lexer, 177 | const bool *valid_symbols) { 178 | // This never happens in valid grammar. Only during error recovery, everything 179 | // becomes valid. See: https://github.com/tree-sitter/tree-sitter/issues/1259 180 | // 181 | // We should not consume any content as string fragment during error recovery, 182 | // or we'll break more valid grammar below. The test 'attrset typing field 183 | // following string' covers this. 184 | if (valid_symbols[STRING_FRAGMENT] && 185 | valid_symbols[INDENTED_STRING_FRAGMENT] && valid_symbols[PATH_START] && 186 | valid_symbols[PATH_FRAGMENT] && valid_symbols[DOLLAR_ESCAPE] && 187 | valid_symbols[INDENTED_DOLLAR_ESCAPE]) { 188 | return false; 189 | } else if (valid_symbols[STRING_FRAGMENT]) { 190 | if (lexer->lookahead == '\\') { 191 | return scan_dollar_escape(lexer); 192 | } 193 | return scan_string_fragment(lexer); 194 | } else if (valid_symbols[INDENTED_STRING_FRAGMENT]) { 195 | if (lexer->lookahead == '\'') { 196 | lexer->mark_end(lexer); 197 | advance(lexer); 198 | if (lexer->lookahead == '\'') { 199 | return scan_indented_dollar_escape(lexer); 200 | } 201 | } 202 | return scan_indented_string_fragment(lexer); 203 | } else if (valid_symbols[PATH_FRAGMENT] && is_path_char(lexer->lookahead)) { 204 | // path_fragments should be scanned as immediate tokens, with no preceding 205 | // extras. so we assert that the very first token is a path character, and 206 | // otherwise we fall through to the case below. example: 207 | // a/b${c} d/e${f} 208 | // ^--- note that scanning for the path_fragment will start here. 209 | // this *should* be parsed as a function application. 210 | // so we want to fall through to the path_start case below, 211 | // which will skip the whitespace and correctly scan the 212 | // following path_start. 213 | // 214 | // also, we want this above path_start, because wherever there's ambiguity 215 | // we want to parse another fragment instead of starting a new path. 216 | // example: 217 | // a/b${c}d/e${f} 218 | // if we swap the precedence, we'd effectively parse the above as the 219 | // following function application: 220 | // (a/b${c}) (d/e${f}) 221 | return scan_path_fragment(lexer); 222 | } else if (valid_symbols[PATH_START]) { 223 | return scan_path_start(lexer); 224 | } 225 | 226 | return false; 227 | } 228 | 229 | unsigned tree_sitter_nix_external_scanner_serialize(void *payload, 230 | char *buffer) { 231 | return 0; 232 | } 233 | 234 | void tree_sitter_nix_external_scanner_deserialize(void *payload, 235 | const char *buffer, 236 | unsigned length) {} 237 | 238 | void tree_sitter_nix_external_scanner_destroy(void *payload) {} 239 | -------------------------------------------------------------------------------- /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 | #endif 22 | 23 | typedef struct { 24 | TSFieldId field_id; 25 | uint8_t child_index; 26 | bool inherited; 27 | } TSFieldMapEntry; 28 | 29 | typedef struct { 30 | uint16_t index; 31 | uint16_t length; 32 | } TSFieldMapSlice; 33 | 34 | typedef struct { 35 | bool visible; 36 | bool named; 37 | bool supertype; 38 | } TSSymbolMetadata; 39 | 40 | typedef struct TSLexer TSLexer; 41 | 42 | struct TSLexer { 43 | int32_t lookahead; 44 | TSSymbol result_symbol; 45 | void (*advance)(TSLexer *, bool); 46 | void (*mark_end)(TSLexer *); 47 | uint32_t (*get_column)(TSLexer *); 48 | bool (*is_at_included_range_start)(const TSLexer *); 49 | bool (*eof)(const TSLexer *); 50 | }; 51 | 52 | typedef enum { 53 | TSParseActionTypeShift, 54 | TSParseActionTypeReduce, 55 | TSParseActionTypeAccept, 56 | TSParseActionTypeRecover, 57 | } TSParseActionType; 58 | 59 | typedef union { 60 | struct { 61 | uint8_t type; 62 | TSStateId state; 63 | bool extra; 64 | bool repetition; 65 | } shift; 66 | struct { 67 | uint8_t type; 68 | uint8_t child_count; 69 | TSSymbol symbol; 70 | int16_t dynamic_precedence; 71 | uint16_t production_id; 72 | } reduce; 73 | uint8_t type; 74 | } TSParseAction; 75 | 76 | typedef struct { 77 | uint16_t lex_state; 78 | uint16_t external_lex_state; 79 | } TSLexMode; 80 | 81 | typedef union { 82 | TSParseAction action; 83 | struct { 84 | uint8_t count; 85 | bool reusable; 86 | } entry; 87 | } TSParseActionEntry; 88 | 89 | struct TSLanguage { 90 | uint32_t version; 91 | uint32_t symbol_count; 92 | uint32_t alias_count; 93 | uint32_t token_count; 94 | uint32_t external_token_count; 95 | uint32_t state_count; 96 | uint32_t large_state_count; 97 | uint32_t production_id_count; 98 | uint32_t field_count; 99 | uint16_t max_alias_sequence_length; 100 | const uint16_t *parse_table; 101 | const uint16_t *small_parse_table; 102 | const uint32_t *small_parse_table_map; 103 | const TSParseActionEntry *parse_actions; 104 | const char * const *symbol_names; 105 | const char * const *field_names; 106 | const TSFieldMapSlice *field_map_slices; 107 | const TSFieldMapEntry *field_map_entries; 108 | const TSSymbolMetadata *symbol_metadata; 109 | const TSSymbol *public_symbol_map; 110 | const uint16_t *alias_map; 111 | const TSSymbol *alias_sequences; 112 | const TSLexMode *lex_modes; 113 | bool (*lex_fn)(TSLexer *, TSStateId); 114 | bool (*keyword_lex_fn)(TSLexer *, TSStateId); 115 | TSSymbol keyword_capture_token; 116 | struct { 117 | const bool *states; 118 | const TSSymbol *symbol_map; 119 | void *(*create)(void); 120 | void (*destroy)(void *); 121 | bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist); 122 | unsigned (*serialize)(void *, char *); 123 | void (*deserialize)(void *, const char *, unsigned); 124 | } external_scanner; 125 | const TSStateId *primary_state_ids; 126 | }; 127 | 128 | /* 129 | * Lexer Macros 130 | */ 131 | 132 | #ifdef _MSC_VER 133 | #define UNUSED __pragma(warning(suppress : 4101)) 134 | #else 135 | #define UNUSED __attribute__((unused)) 136 | #endif 137 | 138 | #define START_LEXER() \ 139 | bool result = false; \ 140 | bool skip = false; \ 141 | UNUSED \ 142 | bool eof = false; \ 143 | int32_t lookahead; \ 144 | goto start; \ 145 | next_state: \ 146 | lexer->advance(lexer, skip); \ 147 | start: \ 148 | skip = false; \ 149 | lookahead = lexer->lookahead; 150 | 151 | #define ADVANCE(state_value) \ 152 | { \ 153 | state = state_value; \ 154 | goto next_state; \ 155 | } 156 | 157 | #define SKIP(state_value) \ 158 | { \ 159 | skip = true; \ 160 | state = state_value; \ 161 | goto next_state; \ 162 | } 163 | 164 | #define ACCEPT_TOKEN(symbol_value) \ 165 | result = true; \ 166 | lexer->result_symbol = symbol_value; \ 167 | lexer->mark_end(lexer); 168 | 169 | #define END_STATE() return result; 170 | 171 | /* 172 | * Parse Table Macros 173 | */ 174 | 175 | #define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT) 176 | 177 | #define STATE(id) id 178 | 179 | #define ACTIONS(id) id 180 | 181 | #define SHIFT(state_value) \ 182 | {{ \ 183 | .shift = { \ 184 | .type = TSParseActionTypeShift, \ 185 | .state = (state_value) \ 186 | } \ 187 | }} 188 | 189 | #define SHIFT_REPEAT(state_value) \ 190 | {{ \ 191 | .shift = { \ 192 | .type = TSParseActionTypeShift, \ 193 | .state = (state_value), \ 194 | .repetition = true \ 195 | } \ 196 | }} 197 | 198 | #define SHIFT_EXTRA() \ 199 | {{ \ 200 | .shift = { \ 201 | .type = TSParseActionTypeShift, \ 202 | .extra = true \ 203 | } \ 204 | }} 205 | 206 | #define REDUCE(symbol_val, child_count_val, ...) \ 207 | {{ \ 208 | .reduce = { \ 209 | .type = TSParseActionTypeReduce, \ 210 | .symbol = symbol_val, \ 211 | .child_count = child_count_val, \ 212 | __VA_ARGS__ \ 213 | }, \ 214 | }} 215 | 216 | #define RECOVER() \ 217 | {{ \ 218 | .type = TSParseActionTypeRecover \ 219 | }} 220 | 221 | #define ACCEPT_INPUT() \ 222 | {{ \ 223 | .type = TSParseActionTypeAccept \ 224 | }} 225 | 226 | #ifdef __cplusplus 227 | } 228 | #endif 229 | 230 | #endif // TREE_SITTER_PARSER_H_ 231 | -------------------------------------------------------------------------------- /test/highlight/basic.nix: -------------------------------------------------------------------------------- 1 | { 2 | or = { or = 1; }.or or 42; 3 | # <- property 4 | # ^ punctuation.delimiter 5 | # ^ property 6 | # ^ property 7 | # ^ keyword 8 | the-question = if builtins.true then "to be" else "not to be"; 9 | # <- property 10 | # ^ property 11 | # ^ property 12 | # ^ keyword 13 | # ^ variable.builtin 14 | # ^ property 15 | # ^ keyword 16 | # ^ string 17 | # ^ keyword 18 | # ^ string 19 | null = if null then true else false; 20 | # <- property 21 | # ^ variable.builtin 22 | # ^ variable.builtin 23 | # ^ variable.builtin 24 | pkgs' = { inherit (pkgs) stdenv lib; }; 25 | # <- property 26 | # ^ property 27 | # ^ keyword 28 | # ^ variable 29 | # ^ property 30 | # ^ property 31 | thing' = 32 | # <- property 33 | let inherit (pkgs) stdenv lib; 34 | # <- keyword 35 | # ^ keyword 36 | # ^ variable 37 | # ^ property 38 | # ^ property 39 | in derivation rec { 40 | # <- keyword 41 | # ^ function.builtin 42 | # ^ keyword 43 | pname = "thing"; 44 | # <- property 45 | # ^ string 46 | version = "v1.2.3"; 47 | name = "${pname}-${version}"; 48 | # <- property 49 | # ^ string 50 | # ^ punctuation.special 51 | # ^ variable 52 | # ^ punctuation.bracket 53 | # ^ string 54 | # ^ variable 55 | # ^ string 56 | buildInputs = with pkgs; [ thing_a thing_b ]; 57 | # <- property 58 | # ^ keyword 59 | # ^ variable 60 | # ^ variable 61 | # ^ variable 62 | }; 63 | assert_bool = bool: assert lib.isBool bool; bool; 64 | # <- property 65 | # ^ variable.parameter 66 | # ^ keyword 67 | # ^ variable 68 | # ^ function 69 | # ^ variable 70 | # ^ variable 71 | import = import ./overlays.nix { inherit pkgs; }; 72 | # <- property 73 | # ^ function.builtin 74 | # ^ string.special.path 75 | # ^ keyword 76 | # ^ property 77 | uri = https://github.com; 78 | # ^ string.special.uri 79 | # ^ string.special.uri 80 | } 81 | -------------------------------------------------------------------------------- /treefmt.toml: -------------------------------------------------------------------------------- 1 | [formatter.nix] 2 | command = "nixpkgs-fmt" 3 | includes = ["*.nix"] 4 | excludes = ["test/**.nix"] 5 | 6 | [formatter.prettier] 7 | command = "prettier" 8 | options = ["--write"] 9 | includes = [ 10 | "*.css", 11 | "*.html", 12 | "*.js", 13 | "*.json", 14 | "*.jsx", 15 | "*.md", 16 | "*.mdx", 17 | "*.scss", 18 | "*.ts", 19 | ] 20 | excludes = ["src/**.json"] 21 | 22 | [formatter.rust] 23 | command = "rustfmt" 24 | options = ["--edition", "2018"] 25 | includes = ["*.rs"] 26 | 27 | [formatter.c] 28 | command = "clang-format" 29 | options = [ "-i" ] 30 | includes = [ "*.c", "*.cpp", "*.cc", "*.h", "*.hpp" ] 31 | excludes = [ 32 | "bindings/node/binding.cc", 33 | "src/parser.c", 34 | "src/tree_sitter/parser.h", 35 | ] 36 | --------------------------------------------------------------------------------