├── .envrc ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── binding.gyp ├── bindings ├── node │ ├── binding.cc │ └── index.js └── rust │ ├── build.rs │ └── lib.rs ├── corpus ├── attribute.txt ├── block.txt ├── collection.txt ├── comment.txt ├── conditional.txt ├── for.txt ├── function.txt ├── huge.txt ├── numeric.txt ├── operation.txt └── template.txt ├── flake.lock ├── flake.nix ├── grammar.js ├── package.json ├── project.nix ├── queries ├── folds.scm └── highlights.scm ├── shell.nix └── src ├── grammar.json ├── node-types.json ├── parser.c ├── scanner.cc └── tree_sitter └── parser.h /.envrc: -------------------------------------------------------------------------------- 1 | # If we are a computer with nix-shell available, then use that to setup 2 | # the build environment with exactly what we need. 3 | if has nix-shell; then 4 | use nix 5 | fi 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Cargo.lock 2 | node_modules 3 | build 4 | package-lock.json 5 | target 6 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tree-sitter-hcl" 3 | description = "hcl grammar for the tree-sitter parsing library" 4 | version = "0.0.1" 5 | keywords = ["incremental", "parsing", "hcl"] 6 | categories = ["parsing", "text-editors"] 7 | repository = "https://github.com/tree-sitter/tree-sitter-javascript" 8 | edition = "2018" 9 | license = "MIT" 10 | 11 | build = "bindings/rust/build.rs" 12 | include = [ 13 | "bindings/rust/*", 14 | "grammar.js", 15 | "queries/*", 16 | "src/*", 17 | ] 18 | 19 | [lib] 20 | path = "bindings/rust/lib.rs" 21 | 22 | [dependencies] 23 | tree-sitter = "0.19.3" 24 | 25 | [build-dependencies] 26 | cc = "1.0" 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Mitchell Hashimoto 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-hcl 2 | 3 | **Update: check out this more full-featured tree-sitter-hcl plugin here:** 4 | https://github.com/MichaHoffmann/tree-sitter-hcl 5 | 6 | [tree-sitter][] grammar for [HCL (HashiCorp Configuration Language)][hcl] files. 7 | HCL is the configuration format used by projects such as Terraform, Vault, 8 | Waypoint, Nomad, etc. 9 | 10 | [hcl]: https://github.com/hashicorp/hcl 11 | [tree-sitter]: https://github.com/tree-sitter/tree-sitter 12 | 13 | ## Status 14 | 15 | **Important: This is not an officially supported HashiCorp project.** 16 | I am one of the founders of HashiCorp, but I built this in my personal 17 | free time and there are no dedicated resources (people or otherwise) 18 | from the company on this project. 19 | 20 | The grammar parses most HCL files I've thrown at it. It doesn't handle 21 | interpolations yet (in strings or heredocs) and instead treats the full string 22 | as just a string. This is the biggest feature missing at the moment. Regardless, 23 | I am using this day to day for general HCL highlighting. 24 | 25 | ## Screenshot 26 | 27 | The screenshot shows a Terraform example syntax highlighted. 28 | 29 | ![Screenshot](https://user-images.githubusercontent.com/1299/122850915-e442bf00-d2c2-11eb-85a1-a92ce9ac0644.png) 30 | 31 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_hcl_binding", 5 | "include_dirs": [ 6 | " 3 | #include "nan.h" 4 | 5 | using namespace v8; 6 | 7 | extern "C" TSLanguage * tree_sitter_hcl(); 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_hcl()); 21 | 22 | Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("hcl").ToLocalChecked()); 23 | Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance); 24 | } 25 | 26 | NODE_MODULE(tree_sitter_hcl_binding, Init) 27 | 28 | } // namespace 29 | -------------------------------------------------------------------------------- /bindings/node/index.js: -------------------------------------------------------------------------------- 1 | try { 2 | module.exports = require("../../build/Release/tree_sitter_hcl_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_hcl_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 | /* 17 | let scanner_path = src_dir.join("scanner.c"); 18 | c_config.file(&scanner_path); 19 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 20 | */ 21 | 22 | c_config.compile("parser"); 23 | println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); 24 | 25 | // If your language uses an external scanner written in C++, 26 | // then include this block of code: 27 | 28 | /* 29 | let mut cpp_config = cc::Build::new(); 30 | cpp_config.cpp(true); 31 | cpp_config.include(&src_dir); 32 | cpp_config 33 | .flag_if_supported("-Wno-unused-parameter") 34 | .flag_if_supported("-Wno-unused-but-set-variable"); 35 | let scanner_path = src_dir.join("scanner.cc"); 36 | cpp_config.file(&scanner_path); 37 | cpp_config.compile("scanner"); 38 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 39 | */ 40 | } 41 | -------------------------------------------------------------------------------- /bindings/rust/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate provides hcl 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 | //! let code = ""; 8 | //! let mut parser = tree_sitter::Parser::new(); 9 | //! parser.set_language(tree_sitter_hcl::language()).expect("Error loading hcl grammar"); 10 | //! let tree = parser.parse(code, None).unwrap(); 11 | //! ``` 12 | //! 13 | //! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html 14 | //! [language func]: fn.language.html 15 | //! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html 16 | //! [tree-sitter]: https://tree-sitter.github.io/ 17 | 18 | use tree_sitter::Language; 19 | 20 | extern "C" { 21 | fn tree_sitter_hcl() -> Language; 22 | } 23 | 24 | /// Get the tree-sitter [Language][] for this grammar. 25 | /// 26 | /// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html 27 | pub fn language() -> Language { 28 | unsafe { tree_sitter_hcl() } 29 | } 30 | 31 | /// The content of the [`node-types.json`][] file for this grammar. 32 | /// 33 | /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types 34 | pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json"); 35 | 36 | // Uncomment these to include any queries that this grammar contains 37 | 38 | // pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm"); 39 | // pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm"); 40 | // pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm"); 41 | // pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.scm"); 42 | 43 | #[cfg(test)] 44 | mod tests { 45 | #[test] 46 | fn test_can_load_grammar() { 47 | let mut parser = tree_sitter::Parser::new(); 48 | parser 49 | .set_language(super::language()) 50 | .expect("Error loading hcl language"); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /corpus/attribute.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | attribute 3 | ================================================================================ 4 | 5 | foo = true 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (source_file 10 | (body 11 | (attribute 12 | (identifier) 13 | (expression 14 | (expr_term 15 | (literal_value 16 | (true))))))) 17 | 18 | ================================================================================ 19 | attribute with hyphen id 20 | ================================================================================ 21 | 22 | foo-bar = true 23 | 24 | -------------------------------------------------------------------------------- 25 | 26 | (source_file 27 | (body 28 | (attribute 29 | (identifier) 30 | (expression 31 | (expr_term 32 | (literal_value 33 | (true))))))) 34 | 35 | ================================================================================ 36 | attribute variable value 37 | ================================================================================ 38 | 39 | foo = bar 40 | 41 | -------------------------------------------------------------------------------- 42 | 43 | (source_file 44 | (body 45 | (attribute 46 | (identifier) 47 | (expression 48 | (expr_term 49 | (variable_expr 50 | (identifier))))))) 51 | 52 | ================================================================================ 53 | index 54 | ================================================================================ 55 | 56 | foo = bar[0] 57 | 58 | -------------------------------------------------------------------------------- 59 | 60 | (source_file 61 | (body 62 | (attribute 63 | (identifier) 64 | (expression 65 | (expr_term 66 | (expr_term 67 | (variable_expr 68 | (identifier))) 69 | (index 70 | (expression 71 | (expr_term 72 | (literal_value 73 | (numeric_literal)))))))))) 74 | 75 | ================================================================================ 76 | getattr 77 | ================================================================================ 78 | 79 | foo = node.os.name 80 | 81 | -------------------------------------------------------------------------------- 82 | 83 | (source_file 84 | (body 85 | (attribute 86 | (identifier) 87 | (expression 88 | (expr_term 89 | (expr_term 90 | (expr_term 91 | (variable_expr 92 | (identifier))) 93 | (get_attr 94 | (identifier))) 95 | (get_attr 96 | (identifier))))))) 97 | 98 | ================================================================================ 99 | splat 100 | ================================================================================ 101 | 102 | foo = node.* 103 | bar = node.*.name 104 | 105 | -------------------------------------------------------------------------------- 106 | 107 | (source_file 108 | (body 109 | (attribute 110 | (identifier) 111 | (expression 112 | (expr_term 113 | (expr_term 114 | (variable_expr 115 | (identifier))) 116 | (splat 117 | (splat_attr))))) 118 | (attribute 119 | (identifier) 120 | (expression 121 | (expr_term 122 | (expr_term 123 | (variable_expr 124 | (identifier))) 125 | (splat 126 | (splat_attr 127 | (get_attr 128 | (identifier))))))))) 129 | -------------------------------------------------------------------------------- /corpus/block.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | block 3 | ================================================================================ 4 | 5 | resource "aws_instance" "foo" { 6 | a = b 7 | } 8 | 9 | -------------------------------------------------------------------------------- 10 | 11 | (source_file 12 | (body 13 | (block 14 | (identifier) 15 | (string_literal 16 | (quoted_template)) 17 | (string_literal 18 | (quoted_template)) 19 | (body 20 | (attribute 21 | (identifier) 22 | (expression 23 | (expr_term 24 | (variable_expr 25 | (identifier))))))))) 26 | 27 | ================================================================================ 28 | one line block 29 | ================================================================================ 30 | 31 | resource aws_instance foo {} 32 | 33 | -------------------------------------------------------------------------------- 34 | 35 | (source_file 36 | (body 37 | (one_line_block 38 | (identifier) 39 | (identifier) 40 | (identifier)))) 41 | 42 | ================================================================================ 43 | empty block 44 | ================================================================================ 45 | 46 | resource aws_instance foo { 47 | } 48 | 49 | -------------------------------------------------------------------------------- 50 | 51 | (source_file 52 | (body 53 | (block 54 | (identifier) 55 | (identifier) 56 | (identifier)))) 57 | -------------------------------------------------------------------------------- /corpus/collection.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | empty tuple 3 | ================================================================================ 4 | 5 | foo = [] 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (source_file 10 | (body 11 | (attribute 12 | (identifier) 13 | (expression 14 | (expr_term 15 | (collection_value 16 | (tuple))))))) 17 | 18 | ================================================================================ 19 | tuple with values 20 | ================================================================================ 21 | 22 | foo = [42,] 23 | bar = [1,2,3,4] 24 | 25 | -------------------------------------------------------------------------------- 26 | 27 | (source_file 28 | (body 29 | (attribute 30 | (identifier) 31 | (expression 32 | (expr_term 33 | (collection_value 34 | (tuple 35 | (expression 36 | (expr_term 37 | (literal_value 38 | (numeric_literal))))))))) 39 | (attribute 40 | (identifier) 41 | (expression 42 | (expr_term 43 | (collection_value 44 | (tuple 45 | (expression 46 | (expr_term 47 | (literal_value 48 | (numeric_literal)))) 49 | (expression 50 | (expr_term 51 | (literal_value 52 | (numeric_literal)))) 53 | (expression 54 | (expr_term 55 | (literal_value 56 | (numeric_literal)))) 57 | (expression 58 | (expr_term 59 | (literal_value 60 | (numeric_literal))))))))))) 61 | 62 | ================================================================================ 63 | object with values 64 | ================================================================================ 65 | 66 | foo = { 67 | a = 42, 68 | b: 24 69 | } 70 | 71 | -------------------------------------------------------------------------------- 72 | 73 | (source_file 74 | (body 75 | (attribute 76 | (identifier) 77 | (expression 78 | (expr_term 79 | (collection_value 80 | (object 81 | (object_elem 82 | (identifier) 83 | (expression 84 | (expr_term 85 | (literal_value 86 | (numeric_literal))))) 87 | (object_elem 88 | (identifier) 89 | (expression 90 | (expr_term 91 | (literal_value 92 | (numeric_literal)))))))))))) 93 | 94 | ================================================================================ 95 | object with no comma 96 | ================================================================================ 97 | 98 | foo = { 99 | a = 42 100 | b = 24 101 | } 102 | 103 | -------------------------------------------------------------------------------- 104 | 105 | (source_file 106 | (body 107 | (attribute 108 | (identifier) 109 | (expression 110 | (expr_term 111 | (collection_value 112 | (object 113 | (object_elem 114 | (identifier) 115 | (expression 116 | (expr_term 117 | (literal_value 118 | (numeric_literal))))) 119 | (object_elem 120 | (identifier) 121 | (expression 122 | (expr_term 123 | (literal_value 124 | (numeric_literal)))))))))))) 125 | -------------------------------------------------------------------------------- /corpus/comment.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | one line command 3 | ================================================================================ 4 | 5 | // foo 6 | resource "aws_instance" "foo" { 7 | a = b // bar 8 | } 9 | 10 | -------------------------------------------------------------------------------- 11 | 12 | (source_file 13 | (comment) 14 | (body 15 | (block 16 | (identifier) 17 | (string_literal 18 | (quoted_template)) 19 | (string_literal 20 | (quoted_template)) 21 | (body 22 | (attribute 23 | (identifier) 24 | (expression 25 | (expr_term 26 | (variable_expr 27 | (identifier)))) 28 | (comment)))))) 29 | 30 | ================================================================================ 31 | multi-line-comment 32 | ================================================================================ 33 | 34 | /* 35 | resource aws_instance foo {} 36 | */ 37 | a = b 38 | 39 | -------------------------------------------------------------------------------- 40 | 41 | (source_file 42 | (comment) 43 | (body 44 | (attribute 45 | (identifier) 46 | (expression 47 | (expr_term 48 | (variable_expr 49 | (identifier))))))) 50 | -------------------------------------------------------------------------------- /corpus/conditional.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | single 3 | ================================================================================ 4 | 5 | foo = bar ? true : 42 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (source_file 10 | (body 11 | (attribute 12 | (identifier) 13 | (expression 14 | (conditional 15 | (expression 16 | (expr_term 17 | (variable_expr 18 | (identifier)))) 19 | (expression 20 | (expr_term 21 | (literal_value 22 | (true)))) 23 | (expression 24 | (expr_term 25 | (literal_value 26 | (numeric_literal))))))))) 27 | 28 | ================================================================================ 29 | nested 30 | ================================================================================ 31 | 32 | foo = bar ? true : baz ? 1 : 2 33 | 34 | -------------------------------------------------------------------------------- 35 | 36 | (source_file 37 | (body 38 | (attribute 39 | (identifier) 40 | (expression 41 | (conditional 42 | (expression 43 | (conditional 44 | (expression 45 | (expr_term 46 | (variable_expr 47 | (identifier)))) 48 | (expression 49 | (expr_term 50 | (literal_value 51 | (true)))) 52 | (expression 53 | (expr_term 54 | (variable_expr 55 | (identifier)))))) 56 | (expression 57 | (expr_term 58 | (literal_value 59 | (numeric_literal)))) 60 | (expression 61 | (expr_term 62 | (literal_value 63 | (numeric_literal))))))))) 64 | -------------------------------------------------------------------------------- /corpus/for.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | tuple 3 | ================================================================================ 4 | 5 | foo = [for s in var.list : upper(s)] 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (source_file 10 | (body 11 | (attribute 12 | (identifier) 13 | (expression 14 | (expr_term 15 | (for_expr 16 | (for_intro 17 | (identifier) 18 | (expression 19 | (expr_term 20 | (expr_term 21 | (variable_expr 22 | (identifier))) 23 | (get_attr 24 | (identifier))))) 25 | (expression 26 | (expr_term 27 | (function_call 28 | (identifier) 29 | (expression 30 | (expr_term 31 | (variable_expr 32 | (identifier))))))))))))) 33 | 34 | ================================================================================ 35 | tuple (kv) 36 | ================================================================================ 37 | 38 | foo = [for k, v in var.map : length(k)] 39 | 40 | -------------------------------------------------------------------------------- 41 | 42 | (source_file 43 | (body 44 | (attribute 45 | (identifier) 46 | (expression 47 | (expr_term 48 | (for_expr 49 | (for_intro 50 | (identifier) 51 | (identifier) 52 | (expression 53 | (expr_term 54 | (expr_term 55 | (variable_expr 56 | (identifier))) 57 | (get_attr 58 | (identifier))))) 59 | (expression 60 | (expr_term 61 | (function_call 62 | (identifier) 63 | (expression 64 | (expr_term 65 | (variable_expr 66 | (identifier))))))))))))) 67 | 68 | ================================================================================ 69 | object 70 | ================================================================================ 71 | 72 | foo = {for s in var.list : s => upper(s)} 73 | 74 | -------------------------------------------------------------------------------- 75 | 76 | (source_file 77 | (body 78 | (attribute 79 | (identifier) 80 | (expression 81 | (expr_term 82 | (for_expr 83 | (for_intro 84 | (identifier) 85 | (expression 86 | (expr_term 87 | (expr_term 88 | (variable_expr 89 | (identifier))) 90 | (get_attr 91 | (identifier))))) 92 | (expression 93 | (expr_term 94 | (variable_expr 95 | (identifier)))) 96 | (expression 97 | (expr_term 98 | (function_call 99 | (identifier) 100 | (expression 101 | (expr_term 102 | (variable_expr 103 | (identifier))))))))))))) 104 | -------------------------------------------------------------------------------- /corpus/function.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | function call 3 | ================================================================================ 4 | 5 | foo = func() 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (source_file 10 | (body 11 | (attribute 12 | (identifier) 13 | (expression 14 | (expr_term 15 | (function_call 16 | (identifier))))))) 17 | 18 | ================================================================================ 19 | argument 20 | ================================================================================ 21 | 22 | foo-bar = func(42) 23 | 24 | -------------------------------------------------------------------------------- 25 | 26 | (source_file 27 | (body 28 | (attribute 29 | (identifier) 30 | (expression 31 | (expr_term 32 | (function_call 33 | (identifier) 34 | (expression 35 | (expr_term 36 | (literal_value 37 | (numeric_literal)))))))))) 38 | 39 | ================================================================================ 40 | argument with ... 41 | ================================================================================ 42 | 43 | foo = bar(foo...) 44 | 45 | -------------------------------------------------------------------------------- 46 | 47 | (source_file 48 | (body 49 | (attribute 50 | (identifier) 51 | (expression 52 | (expr_term 53 | (function_call 54 | (identifier) 55 | (expression 56 | (expr_term 57 | (variable_expr 58 | (identifier)))))))))) 59 | -------------------------------------------------------------------------------- /corpus/numeric.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | integer 3 | ================================================================================ 4 | 5 | foo = 42 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (source_file 10 | (body 11 | (attribute 12 | (identifier) 13 | (expression 14 | (expr_term 15 | (literal_value 16 | (numeric_literal))))))) 17 | 18 | ================================================================================ 19 | decimal 20 | ================================================================================ 21 | 22 | foo = 42.12 23 | 24 | -------------------------------------------------------------------------------- 25 | 26 | (source_file 27 | (body 28 | (attribute 29 | (identifier) 30 | (expression 31 | (expr_term 32 | (literal_value 33 | (numeric_literal))))))) 34 | 35 | ================================================================================ 36 | exponent 37 | ================================================================================ 38 | 39 | foo = 42e12 40 | foo = 42e+12 41 | foo = 42e-12 42 | foo = 42E-12 43 | 44 | -------------------------------------------------------------------------------- 45 | 46 | (source_file 47 | (body 48 | (attribute 49 | (identifier) 50 | (expression 51 | (expr_term 52 | (literal_value 53 | (numeric_literal))))) 54 | (attribute 55 | (identifier) 56 | (expression 57 | (expr_term 58 | (literal_value 59 | (numeric_literal))))) 60 | (attribute 61 | (identifier) 62 | (expression 63 | (expr_term 64 | (literal_value 65 | (numeric_literal))))) 66 | (attribute 67 | (identifier) 68 | (expression 69 | (expr_term 70 | (literal_value 71 | (numeric_literal))))))) 72 | -------------------------------------------------------------------------------- /corpus/operation.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | operations 3 | ================================================================================ 4 | 5 | foo = !4 6 | foo = 1 + 1 7 | foo = 1 + 2 * 4 8 | 9 | -------------------------------------------------------------------------------- 10 | 11 | (source_file 12 | (body 13 | (attribute 14 | (identifier) 15 | (expression 16 | (operation 17 | (unary_op 18 | (expr_term 19 | (literal_value 20 | (numeric_literal))))))) 21 | (attribute 22 | (identifier) 23 | (expression 24 | (operation 25 | (binary_op 26 | (expression 27 | (expr_term 28 | (literal_value 29 | (numeric_literal)))) 30 | (expression 31 | (expr_term 32 | (literal_value 33 | (numeric_literal)))))))) 34 | (attribute 35 | (identifier) 36 | (expression 37 | (operation 38 | (binary_op 39 | (expression 40 | (expr_term 41 | (literal_value 42 | (numeric_literal)))) 43 | (expression 44 | (operation 45 | (binary_op 46 | (expression 47 | (expr_term 48 | (literal_value 49 | (numeric_literal)))) 50 | (expression 51 | (expr_term 52 | (literal_value 53 | (numeric_literal))))))))))))) 54 | -------------------------------------------------------------------------------- /corpus/template.txt: -------------------------------------------------------------------------------- 1 | ================================================================================ 2 | string 3 | ================================================================================ 4 | 5 | foo = "foo!" 6 | 7 | -------------------------------------------------------------------------------- 8 | 9 | (source_file 10 | (body 11 | (attribute 12 | (identifier) 13 | (expression 14 | (expr_term 15 | (template_expr 16 | (quoted_template))))))) 17 | 18 | ================================================================================ 19 | heredoc 20 | ================================================================================ 21 | 22 | foo = < [ 29 | $.heredoc, 30 | ], 31 | 32 | extras: $ => [ 33 | $.comment, 34 | /\s/ 35 | ], 36 | 37 | rules: { 38 | source_file: $ => $.body, 39 | 40 | // Body = (Attribute | Block | OneLineBlock)*; 41 | body: $ => repeat1(choice( 42 | $.attribute, 43 | $.block, 44 | $.one_line_block, 45 | )), 46 | 47 | // Block = Identifier (StringLit|Identifier)* "{" Newline Body "}" Newline; 48 | block: $ => seq( 49 | $.identifier, 50 | repeat(choice( 51 | $.string_literal, 52 | $.identifier, 53 | )), 54 | '{', 55 | terminator, 56 | optional($.body), 57 | '}', 58 | terminator, 59 | ), 60 | 61 | // OneLineBlock = Identifier (StringLit|Identifier)* "{" (Identifier "=" Expression)? "}" Newline; 62 | one_line_block: $ => seq( 63 | $.identifier, 64 | repeat(choice( 65 | $.string_literal, 66 | $.identifier, 67 | )), 68 | '{', 69 | optional(seq( 70 | $.identifier, 71 | '=', 72 | $.expression, 73 | )), 74 | '}', 75 | terminator, 76 | ), 77 | 78 | // Attribute = Identifier "=" Expression Newline; 79 | attribute: $ => seq( 80 | $.identifier, 81 | '=', 82 | $.expression, 83 | terminator, 84 | ), 85 | 86 | // Expression = ( 87 | // ExprTerm | 88 | // Operation | 89 | // Conditional 90 | // ); 91 | expression: $ => choice( 92 | $.expr_term, 93 | $.operation, 94 | $.conditional, 95 | ), 96 | 97 | // Conditional = Expression "?" Expression ":" Expression; 98 | conditional: $ => prec.left(seq( 99 | $.expression, 100 | '?', 101 | $.expression, 102 | ':', 103 | $.expression, 104 | )), 105 | 106 | // Operation = unaryOp | binaryOp; 107 | // unaryOp = ("-" | "!") ExprTerm; 108 | // binaryOp = ExprTerm binaryOperator ExprTerm; 109 | // binaryOperator = compareOperator | arithmeticOperator | logicOperator; 110 | // compareOperator = "==" | "!=" | "<" | ">" | "<=" | ">="; 111 | // arithmeticOperator = "+" | "-" | "*" | "/" | "%"; 112 | // logicOperator = "&&" | "||" | "!"; 113 | operation: $ => choice($.unary_op, $.binary_op), 114 | 115 | unary_op: $ => prec(PREC.unary, seq( 116 | choice('-', '!'), 117 | $.expr_term, 118 | )), 119 | 120 | binary_op: $ => { 121 | const table = [ 122 | [PREC.multiplicative, choice('*', '/', '%')], 123 | [PREC.additive, choice('+', '-')], 124 | [PREC.comparative, choice('>', '>=', '<', '<=')], 125 | [PREC.equal, choice('==', '!=')], 126 | [PREC.and, '&&'], 127 | [PREC.or, '||'], 128 | ]; 129 | 130 | return choice(...table.map(([precedence, operator]) => 131 | prec.left(precedence, seq( 132 | field('left', $.expression), 133 | field('operator', operator), 134 | field('right', $.expression) 135 | )) 136 | )); 137 | }, 138 | 139 | // ExprTerm = ( 140 | // LiteralValue | 141 | // CollectionValue | 142 | // TemplateExpr | 143 | // VariableExpr | 144 | // FunctionCall | 145 | // ForExpr | 146 | // ExprTerm Index | 147 | // ExprTerm GetAttr | 148 | // ExprTerm Splat | 149 | // "(" Expression ")" 150 | //); 151 | expr_term: $ => choice( 152 | $.literal_value, 153 | $.collection_value, 154 | $.template_expr, 155 | $.variable_expr, 156 | $.function_call, 157 | $.for_expr, 158 | seq($.expr_term, $.index), 159 | seq($.expr_term, $.get_attr), 160 | seq($.expr_term, $.splat), 161 | seq('(', $.expression, ')'), 162 | ), 163 | 164 | // TemplateExpr = quotedTemplate | heredocTemplate; 165 | // quotedTemplate = (as defined in prose above); 166 | // heredocTemplate = ( 167 | // ("<<" | "<<-") Identifier Newline 168 | // (content as defined in prose above) 169 | // Identifier Newline 170 | // ); 171 | template_expr: $ => choice($.quoted_template, $.heredoc), 172 | 173 | quoted_template: $ => seq( 174 | '"', 175 | repeat(choice( 176 | token.immediate(prec(1, /[^"\n\\]+/)), 177 | $.escape_sequence, 178 | )), 179 | '"' 180 | ), 181 | 182 | string_literal: $ => $.quoted_template, 183 | 184 | escape_sequence: $ => token.immediate(seq( 185 | '\\', 186 | choice( 187 | /[^xuU]/, 188 | /\d{2,3}/, 189 | /x[0-9a-fA-F]{2,}/, 190 | /u[0-9a-fA-F]{4}/, 191 | /U[0-9a-fA-F]{8}/ 192 | ) 193 | )), 194 | 195 | // ForExpr = forTupleExpr | forObjectExpr; 196 | // forTupleExpr = "[" forIntro Expression forCond? "]"; 197 | // forObjectExpr = "{" forIntro Expression "=>" Expression "..."? forCond? "}"; 198 | // forIntro = "for" Identifier ("," Identifier)? "in" Expression ":"; 199 | // forCond = "if" Expression; 200 | for_expr: $ => choice($._for_tuple, $._for_object), 201 | 202 | _for_tuple: $ => seq( 203 | '[', 204 | $.for_intro, 205 | $.expression, 206 | optional($.for_cond), 207 | ']', 208 | ), 209 | 210 | _for_object: $ => seq( 211 | '{', 212 | $.for_intro, 213 | $.expression, 214 | '=>', 215 | $.expression, 216 | optional('...'), 217 | optional($.for_cond), 218 | '}', 219 | ), 220 | 221 | for_intro: $ => seq( 222 | 'for', 223 | $.identifier, 224 | optional(seq(',', $.identifier)), 225 | 'in', 226 | $.expression, 227 | ':', 228 | ), 229 | 230 | for_cond: $ => seq('if', $.expression), 231 | 232 | // LiteralValue = ( 233 | // NumericLit | 234 | // "true" | 235 | // "false" | 236 | // "null" 237 | //); 238 | literal_value: $ => choice( 239 | $.numeric_literal, 240 | $.true, 241 | $.false, 242 | $.null, 243 | ), 244 | 245 | // Index = "[" Expression "]"; 246 | index: $ => seq('[', $.expression, ']'), 247 | 248 | // GetAttr = "." Identifier; 249 | get_attr: $ => seq('.', $.identifier), 250 | 251 | // Splat = attrSplat | fullSplat; 252 | // attrSplat = "." "*" GetAttr*; 253 | // fullSplat = "[" "*" "]" (GetAttr | Index)*; 254 | splat: $ => choice($.splat_attr, $.splat_full), 255 | splat_attr: $ => prec.right(seq('.', '*', repeat($.get_attr))), 256 | splat_full: $ => prec.right(seq('[', '*', ']', repeat(choice($.get_attr, $.index)))), 257 | 258 | // CollectionValue = tuple | object; 259 | // tuple = "[" ( 260 | // (Expression ("," Expression)* ","?)? 261 | // ) "]"; 262 | // object = "{" ( 263 | // (objectelem ("," objectelem)* ","?)? 264 | // ) "}"; 265 | // objectelem = (Identifier | Expression) ("=" | ":") Expression; 266 | collection_value: $ => choice( 267 | $.tuple, 268 | $.object, 269 | ), 270 | 271 | tuple: $ => seq( 272 | '[', 273 | optional(seq( 274 | $.expression, 275 | repeat(seq(',', $.expression)), 276 | optional(','), 277 | )), 278 | ']', 279 | ), 280 | 281 | object: $ => seq( 282 | '{', 283 | optional(seq( 284 | $.object_elem, 285 | repeat(seq( 286 | choice(',', terminator), 287 | $.object_elem, 288 | )), 289 | optional(choice(',', terminator)), 290 | )), 291 | '}', 292 | ), 293 | 294 | object_elem: $ => seq( 295 | choice($.identifier, $.expression), 296 | choice('=', ':'), 297 | $.expression, 298 | ), 299 | 300 | // VariableExpr = Identifier; 301 | variable_expr: $ => prec.right($.identifier), 302 | 303 | // FunctionCall = Identifier "(" arguments ")"; 304 | // Arguments = ( 305 | // () || 306 | // (Expression ("," Expression)* ("," | "...")?) 307 | // ); 308 | function_call: $ => seq( 309 | $.identifier, 310 | '(', 311 | optional(seq( 312 | $.expression, 313 | repeat(seq(',',$.expression)), 314 | optional(choice(',', '...')), 315 | )), 316 | ')', 317 | ), 318 | 319 | // NumericLit = decimal+ ("." decimal+)? (expmark decimal+)?; 320 | // decimal = '0' .. '9'; 321 | // expmark = ('e' | 'E') ("+" | "-")?; 322 | numeric_literal: $ => token(seq( 323 | repeat1(/[0-9]/), 324 | optional(seq('.', repeat1(/[0-9]/))), 325 | optional(seq( 326 | choice('e', 'E'), 327 | optional(choice('+', '-')), 328 | repeat1(/[0-9]/), 329 | )), 330 | )), 331 | 332 | identifier: $ => token(seq( 333 | letter, 334 | repeat(choice(letter, unicodeDigit, '-')) 335 | )), 336 | 337 | null: $ => 'null', 338 | true: $ => 'true', 339 | false: $ => 'false', 340 | 341 | // http://stackoverflow.com/questions/13014947/regex-to-match-a-c-style-multiline-comment/36328890#36328890 342 | comment: $ => token(choice( 343 | seq('//', /.*/), 344 | seq('#', /.*/), 345 | seq( 346 | '/*', 347 | /[^*]*\*+([^/*][^*]*\*+)*/, 348 | '/' 349 | ) 350 | )) 351 | } 352 | }); 353 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-hcl", 3 | "version": "0.1.0", 4 | "description": "A tree-sitter grammar for HCL (HashiCorp Configuration Language)", 5 | "main": "bindings/node", 6 | "scripts": { 7 | "build": "tree-sitter generate && node-gyp build", 8 | "test": "tree-sitter test", 9 | "test-windows": "tree-sitter test" 10 | }, 11 | "keywords": [ 12 | "tree-sitter", 13 | "hcl" 14 | ], 15 | "author": "Mitchell Hashimoto ", 16 | "license": "MIT", 17 | "dependencies": { 18 | "nan": "^2.14.0" 19 | }, 20 | "devDependencies": { 21 | "tree-sitter-cli": "^0.19.1" 22 | }, 23 | "tree-sitter": [ 24 | { 25 | "scope": "source.hcl", 26 | "file-types": [ 27 | "hcl" 28 | ] 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /project.nix: -------------------------------------------------------------------------------- 1 | /* This file is meant to provide all the all the fields for the 2 | * flake. 3 | */ 4 | { pkgs }: { 5 | shell = pkgs.mkShell rec { 6 | name = "tree-sitter-proto"; 7 | 8 | buildInputs = with pkgs; [ 9 | nodejs-14_x 10 | python3Full 11 | tree-sitter 12 | ]; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /queries/folds.scm: -------------------------------------------------------------------------------- 1 | [ 2 | (block) 3 | ] @fold 4 | -------------------------------------------------------------------------------- /queries/highlights.scm: -------------------------------------------------------------------------------- 1 | [ 2 | "for" 3 | ] @keyword 4 | 5 | (attribute (identifier) @property) 6 | (object_elem (identifier) @property) 7 | 8 | (block (identifier) @type) 9 | (one_line_block (identifier) @type) 10 | 11 | (function_call (identifier) @function) 12 | 13 | [ 14 | (string_literal) 15 | (quoted_template) 16 | (heredoc) 17 | ] @string 18 | 19 | (numeric_literal) @number 20 | 21 | [ 22 | (true) 23 | (false) 24 | (null) 25 | ] @constant.builtin 26 | 27 | (comment) @comment 28 | 29 | [ 30 | "(" 31 | ")" 32 | "[" 33 | "]" 34 | "{" 35 | "}" 36 | ] @punctuation.bracket 37 | -------------------------------------------------------------------------------- /shell.nix: -------------------------------------------------------------------------------- 1 | ( 2 | import (fetchTarball https://github.com/edolstra/flake-compat/archive/master.tar.gz) { 3 | src = builtins.fetchGit ./.; 4 | } 5 | ).shellNix 6 | -------------------------------------------------------------------------------- /src/grammar.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hcl", 3 | "rules": { 4 | "source_file": { 5 | "type": "SYMBOL", 6 | "name": "body" 7 | }, 8 | "body": { 9 | "type": "REPEAT1", 10 | "content": { 11 | "type": "CHOICE", 12 | "members": [ 13 | { 14 | "type": "SYMBOL", 15 | "name": "attribute" 16 | }, 17 | { 18 | "type": "SYMBOL", 19 | "name": "block" 20 | }, 21 | { 22 | "type": "SYMBOL", 23 | "name": "one_line_block" 24 | } 25 | ] 26 | } 27 | }, 28 | "block": { 29 | "type": "SEQ", 30 | "members": [ 31 | { 32 | "type": "SYMBOL", 33 | "name": "identifier" 34 | }, 35 | { 36 | "type": "REPEAT", 37 | "content": { 38 | "type": "CHOICE", 39 | "members": [ 40 | { 41 | "type": "SYMBOL", 42 | "name": "string_literal" 43 | }, 44 | { 45 | "type": "SYMBOL", 46 | "name": "identifier" 47 | } 48 | ] 49 | } 50 | }, 51 | { 52 | "type": "STRING", 53 | "value": "{" 54 | }, 55 | { 56 | "type": "CHOICE", 57 | "members": [ 58 | { 59 | "type": "STRING", 60 | "value": "\n" 61 | } 62 | ] 63 | }, 64 | { 65 | "type": "CHOICE", 66 | "members": [ 67 | { 68 | "type": "SYMBOL", 69 | "name": "body" 70 | }, 71 | { 72 | "type": "BLANK" 73 | } 74 | ] 75 | }, 76 | { 77 | "type": "STRING", 78 | "value": "}" 79 | }, 80 | { 81 | "type": "CHOICE", 82 | "members": [ 83 | { 84 | "type": "STRING", 85 | "value": "\n" 86 | } 87 | ] 88 | } 89 | ] 90 | }, 91 | "one_line_block": { 92 | "type": "SEQ", 93 | "members": [ 94 | { 95 | "type": "SYMBOL", 96 | "name": "identifier" 97 | }, 98 | { 99 | "type": "REPEAT", 100 | "content": { 101 | "type": "CHOICE", 102 | "members": [ 103 | { 104 | "type": "SYMBOL", 105 | "name": "string_literal" 106 | }, 107 | { 108 | "type": "SYMBOL", 109 | "name": "identifier" 110 | } 111 | ] 112 | } 113 | }, 114 | { 115 | "type": "STRING", 116 | "value": "{" 117 | }, 118 | { 119 | "type": "CHOICE", 120 | "members": [ 121 | { 122 | "type": "SEQ", 123 | "members": [ 124 | { 125 | "type": "SYMBOL", 126 | "name": "identifier" 127 | }, 128 | { 129 | "type": "STRING", 130 | "value": "=" 131 | }, 132 | { 133 | "type": "SYMBOL", 134 | "name": "expression" 135 | } 136 | ] 137 | }, 138 | { 139 | "type": "BLANK" 140 | } 141 | ] 142 | }, 143 | { 144 | "type": "STRING", 145 | "value": "}" 146 | }, 147 | { 148 | "type": "CHOICE", 149 | "members": [ 150 | { 151 | "type": "STRING", 152 | "value": "\n" 153 | } 154 | ] 155 | } 156 | ] 157 | }, 158 | "attribute": { 159 | "type": "SEQ", 160 | "members": [ 161 | { 162 | "type": "SYMBOL", 163 | "name": "identifier" 164 | }, 165 | { 166 | "type": "STRING", 167 | "value": "=" 168 | }, 169 | { 170 | "type": "SYMBOL", 171 | "name": "expression" 172 | }, 173 | { 174 | "type": "CHOICE", 175 | "members": [ 176 | { 177 | "type": "STRING", 178 | "value": "\n" 179 | } 180 | ] 181 | } 182 | ] 183 | }, 184 | "expression": { 185 | "type": "CHOICE", 186 | "members": [ 187 | { 188 | "type": "SYMBOL", 189 | "name": "expr_term" 190 | }, 191 | { 192 | "type": "SYMBOL", 193 | "name": "operation" 194 | }, 195 | { 196 | "type": "SYMBOL", 197 | "name": "conditional" 198 | } 199 | ] 200 | }, 201 | "conditional": { 202 | "type": "PREC_LEFT", 203 | "value": 0, 204 | "content": { 205 | "type": "SEQ", 206 | "members": [ 207 | { 208 | "type": "SYMBOL", 209 | "name": "expression" 210 | }, 211 | { 212 | "type": "STRING", 213 | "value": "?" 214 | }, 215 | { 216 | "type": "SYMBOL", 217 | "name": "expression" 218 | }, 219 | { 220 | "type": "STRING", 221 | "value": ":" 222 | }, 223 | { 224 | "type": "SYMBOL", 225 | "name": "expression" 226 | } 227 | ] 228 | } 229 | }, 230 | "operation": { 231 | "type": "CHOICE", 232 | "members": [ 233 | { 234 | "type": "SYMBOL", 235 | "name": "unary_op" 236 | }, 237 | { 238 | "type": "SYMBOL", 239 | "name": "binary_op" 240 | } 241 | ] 242 | }, 243 | "unary_op": { 244 | "type": "PREC", 245 | "value": 7, 246 | "content": { 247 | "type": "SEQ", 248 | "members": [ 249 | { 250 | "type": "CHOICE", 251 | "members": [ 252 | { 253 | "type": "STRING", 254 | "value": "-" 255 | }, 256 | { 257 | "type": "STRING", 258 | "value": "!" 259 | } 260 | ] 261 | }, 262 | { 263 | "type": "SYMBOL", 264 | "name": "expr_term" 265 | } 266 | ] 267 | } 268 | }, 269 | "binary_op": { 270 | "type": "CHOICE", 271 | "members": [ 272 | { 273 | "type": "PREC_LEFT", 274 | "value": 6, 275 | "content": { 276 | "type": "SEQ", 277 | "members": [ 278 | { 279 | "type": "FIELD", 280 | "name": "left", 281 | "content": { 282 | "type": "SYMBOL", 283 | "name": "expression" 284 | } 285 | }, 286 | { 287 | "type": "FIELD", 288 | "name": "operator", 289 | "content": { 290 | "type": "CHOICE", 291 | "members": [ 292 | { 293 | "type": "STRING", 294 | "value": "*" 295 | }, 296 | { 297 | "type": "STRING", 298 | "value": "/" 299 | }, 300 | { 301 | "type": "STRING", 302 | "value": "%" 303 | } 304 | ] 305 | } 306 | }, 307 | { 308 | "type": "FIELD", 309 | "name": "right", 310 | "content": { 311 | "type": "SYMBOL", 312 | "name": "expression" 313 | } 314 | } 315 | ] 316 | } 317 | }, 318 | { 319 | "type": "PREC_LEFT", 320 | "value": 5, 321 | "content": { 322 | "type": "SEQ", 323 | "members": [ 324 | { 325 | "type": "FIELD", 326 | "name": "left", 327 | "content": { 328 | "type": "SYMBOL", 329 | "name": "expression" 330 | } 331 | }, 332 | { 333 | "type": "FIELD", 334 | "name": "operator", 335 | "content": { 336 | "type": "CHOICE", 337 | "members": [ 338 | { 339 | "type": "STRING", 340 | "value": "+" 341 | }, 342 | { 343 | "type": "STRING", 344 | "value": "-" 345 | } 346 | ] 347 | } 348 | }, 349 | { 350 | "type": "FIELD", 351 | "name": "right", 352 | "content": { 353 | "type": "SYMBOL", 354 | "name": "expression" 355 | } 356 | } 357 | ] 358 | } 359 | }, 360 | { 361 | "type": "PREC_LEFT", 362 | "value": 4, 363 | "content": { 364 | "type": "SEQ", 365 | "members": [ 366 | { 367 | "type": "FIELD", 368 | "name": "left", 369 | "content": { 370 | "type": "SYMBOL", 371 | "name": "expression" 372 | } 373 | }, 374 | { 375 | "type": "FIELD", 376 | "name": "operator", 377 | "content": { 378 | "type": "CHOICE", 379 | "members": [ 380 | { 381 | "type": "STRING", 382 | "value": ">" 383 | }, 384 | { 385 | "type": "STRING", 386 | "value": ">=" 387 | }, 388 | { 389 | "type": "STRING", 390 | "value": "<" 391 | }, 392 | { 393 | "type": "STRING", 394 | "value": "<=" 395 | } 396 | ] 397 | } 398 | }, 399 | { 400 | "type": "FIELD", 401 | "name": "right", 402 | "content": { 403 | "type": "SYMBOL", 404 | "name": "expression" 405 | } 406 | } 407 | ] 408 | } 409 | }, 410 | { 411 | "type": "PREC_LEFT", 412 | "value": 3, 413 | "content": { 414 | "type": "SEQ", 415 | "members": [ 416 | { 417 | "type": "FIELD", 418 | "name": "left", 419 | "content": { 420 | "type": "SYMBOL", 421 | "name": "expression" 422 | } 423 | }, 424 | { 425 | "type": "FIELD", 426 | "name": "operator", 427 | "content": { 428 | "type": "CHOICE", 429 | "members": [ 430 | { 431 | "type": "STRING", 432 | "value": "==" 433 | }, 434 | { 435 | "type": "STRING", 436 | "value": "!=" 437 | } 438 | ] 439 | } 440 | }, 441 | { 442 | "type": "FIELD", 443 | "name": "right", 444 | "content": { 445 | "type": "SYMBOL", 446 | "name": "expression" 447 | } 448 | } 449 | ] 450 | } 451 | }, 452 | { 453 | "type": "PREC_LEFT", 454 | "value": 2, 455 | "content": { 456 | "type": "SEQ", 457 | "members": [ 458 | { 459 | "type": "FIELD", 460 | "name": "left", 461 | "content": { 462 | "type": "SYMBOL", 463 | "name": "expression" 464 | } 465 | }, 466 | { 467 | "type": "FIELD", 468 | "name": "operator", 469 | "content": { 470 | "type": "STRING", 471 | "value": "&&" 472 | } 473 | }, 474 | { 475 | "type": "FIELD", 476 | "name": "right", 477 | "content": { 478 | "type": "SYMBOL", 479 | "name": "expression" 480 | } 481 | } 482 | ] 483 | } 484 | }, 485 | { 486 | "type": "PREC_LEFT", 487 | "value": 1, 488 | "content": { 489 | "type": "SEQ", 490 | "members": [ 491 | { 492 | "type": "FIELD", 493 | "name": "left", 494 | "content": { 495 | "type": "SYMBOL", 496 | "name": "expression" 497 | } 498 | }, 499 | { 500 | "type": "FIELD", 501 | "name": "operator", 502 | "content": { 503 | "type": "STRING", 504 | "value": "||" 505 | } 506 | }, 507 | { 508 | "type": "FIELD", 509 | "name": "right", 510 | "content": { 511 | "type": "SYMBOL", 512 | "name": "expression" 513 | } 514 | } 515 | ] 516 | } 517 | } 518 | ] 519 | }, 520 | "expr_term": { 521 | "type": "CHOICE", 522 | "members": [ 523 | { 524 | "type": "SYMBOL", 525 | "name": "literal_value" 526 | }, 527 | { 528 | "type": "SYMBOL", 529 | "name": "collection_value" 530 | }, 531 | { 532 | "type": "SYMBOL", 533 | "name": "template_expr" 534 | }, 535 | { 536 | "type": "SYMBOL", 537 | "name": "variable_expr" 538 | }, 539 | { 540 | "type": "SYMBOL", 541 | "name": "function_call" 542 | }, 543 | { 544 | "type": "SYMBOL", 545 | "name": "for_expr" 546 | }, 547 | { 548 | "type": "SEQ", 549 | "members": [ 550 | { 551 | "type": "SYMBOL", 552 | "name": "expr_term" 553 | }, 554 | { 555 | "type": "SYMBOL", 556 | "name": "index" 557 | } 558 | ] 559 | }, 560 | { 561 | "type": "SEQ", 562 | "members": [ 563 | { 564 | "type": "SYMBOL", 565 | "name": "expr_term" 566 | }, 567 | { 568 | "type": "SYMBOL", 569 | "name": "get_attr" 570 | } 571 | ] 572 | }, 573 | { 574 | "type": "SEQ", 575 | "members": [ 576 | { 577 | "type": "SYMBOL", 578 | "name": "expr_term" 579 | }, 580 | { 581 | "type": "SYMBOL", 582 | "name": "splat" 583 | } 584 | ] 585 | }, 586 | { 587 | "type": "SEQ", 588 | "members": [ 589 | { 590 | "type": "STRING", 591 | "value": "(" 592 | }, 593 | { 594 | "type": "SYMBOL", 595 | "name": "expression" 596 | }, 597 | { 598 | "type": "STRING", 599 | "value": ")" 600 | } 601 | ] 602 | } 603 | ] 604 | }, 605 | "template_expr": { 606 | "type": "CHOICE", 607 | "members": [ 608 | { 609 | "type": "SYMBOL", 610 | "name": "quoted_template" 611 | }, 612 | { 613 | "type": "SYMBOL", 614 | "name": "heredoc" 615 | } 616 | ] 617 | }, 618 | "quoted_template": { 619 | "type": "SEQ", 620 | "members": [ 621 | { 622 | "type": "STRING", 623 | "value": "\"" 624 | }, 625 | { 626 | "type": "REPEAT", 627 | "content": { 628 | "type": "CHOICE", 629 | "members": [ 630 | { 631 | "type": "IMMEDIATE_TOKEN", 632 | "content": { 633 | "type": "PREC", 634 | "value": 1, 635 | "content": { 636 | "type": "PATTERN", 637 | "value": "[^\"\\n\\\\]+" 638 | } 639 | } 640 | }, 641 | { 642 | "type": "SYMBOL", 643 | "name": "escape_sequence" 644 | } 645 | ] 646 | } 647 | }, 648 | { 649 | "type": "STRING", 650 | "value": "\"" 651 | } 652 | ] 653 | }, 654 | "string_literal": { 655 | "type": "SYMBOL", 656 | "name": "quoted_template" 657 | }, 658 | "escape_sequence": { 659 | "type": "IMMEDIATE_TOKEN", 660 | "content": { 661 | "type": "SEQ", 662 | "members": [ 663 | { 664 | "type": "STRING", 665 | "value": "\\" 666 | }, 667 | { 668 | "type": "CHOICE", 669 | "members": [ 670 | { 671 | "type": "PATTERN", 672 | "value": "[^xuU]" 673 | }, 674 | { 675 | "type": "PATTERN", 676 | "value": "\\d{2,3}" 677 | }, 678 | { 679 | "type": "PATTERN", 680 | "value": "x[0-9a-fA-F]{2,}" 681 | }, 682 | { 683 | "type": "PATTERN", 684 | "value": "u[0-9a-fA-F]{4}" 685 | }, 686 | { 687 | "type": "PATTERN", 688 | "value": "U[0-9a-fA-F]{8}" 689 | } 690 | ] 691 | } 692 | ] 693 | } 694 | }, 695 | "for_expr": { 696 | "type": "CHOICE", 697 | "members": [ 698 | { 699 | "type": "SYMBOL", 700 | "name": "_for_tuple" 701 | }, 702 | { 703 | "type": "SYMBOL", 704 | "name": "_for_object" 705 | } 706 | ] 707 | }, 708 | "_for_tuple": { 709 | "type": "SEQ", 710 | "members": [ 711 | { 712 | "type": "STRING", 713 | "value": "[" 714 | }, 715 | { 716 | "type": "SYMBOL", 717 | "name": "for_intro" 718 | }, 719 | { 720 | "type": "SYMBOL", 721 | "name": "expression" 722 | }, 723 | { 724 | "type": "CHOICE", 725 | "members": [ 726 | { 727 | "type": "SYMBOL", 728 | "name": "for_cond" 729 | }, 730 | { 731 | "type": "BLANK" 732 | } 733 | ] 734 | }, 735 | { 736 | "type": "STRING", 737 | "value": "]" 738 | } 739 | ] 740 | }, 741 | "_for_object": { 742 | "type": "SEQ", 743 | "members": [ 744 | { 745 | "type": "STRING", 746 | "value": "{" 747 | }, 748 | { 749 | "type": "SYMBOL", 750 | "name": "for_intro" 751 | }, 752 | { 753 | "type": "SYMBOL", 754 | "name": "expression" 755 | }, 756 | { 757 | "type": "STRING", 758 | "value": "=>" 759 | }, 760 | { 761 | "type": "SYMBOL", 762 | "name": "expression" 763 | }, 764 | { 765 | "type": "CHOICE", 766 | "members": [ 767 | { 768 | "type": "STRING", 769 | "value": "..." 770 | }, 771 | { 772 | "type": "BLANK" 773 | } 774 | ] 775 | }, 776 | { 777 | "type": "CHOICE", 778 | "members": [ 779 | { 780 | "type": "SYMBOL", 781 | "name": "for_cond" 782 | }, 783 | { 784 | "type": "BLANK" 785 | } 786 | ] 787 | }, 788 | { 789 | "type": "STRING", 790 | "value": "}" 791 | } 792 | ] 793 | }, 794 | "for_intro": { 795 | "type": "SEQ", 796 | "members": [ 797 | { 798 | "type": "STRING", 799 | "value": "for" 800 | }, 801 | { 802 | "type": "SYMBOL", 803 | "name": "identifier" 804 | }, 805 | { 806 | "type": "CHOICE", 807 | "members": [ 808 | { 809 | "type": "SEQ", 810 | "members": [ 811 | { 812 | "type": "STRING", 813 | "value": "," 814 | }, 815 | { 816 | "type": "SYMBOL", 817 | "name": "identifier" 818 | } 819 | ] 820 | }, 821 | { 822 | "type": "BLANK" 823 | } 824 | ] 825 | }, 826 | { 827 | "type": "STRING", 828 | "value": "in" 829 | }, 830 | { 831 | "type": "SYMBOL", 832 | "name": "expression" 833 | }, 834 | { 835 | "type": "STRING", 836 | "value": ":" 837 | } 838 | ] 839 | }, 840 | "for_cond": { 841 | "type": "SEQ", 842 | "members": [ 843 | { 844 | "type": "STRING", 845 | "value": "if" 846 | }, 847 | { 848 | "type": "SYMBOL", 849 | "name": "expression" 850 | } 851 | ] 852 | }, 853 | "literal_value": { 854 | "type": "CHOICE", 855 | "members": [ 856 | { 857 | "type": "SYMBOL", 858 | "name": "numeric_literal" 859 | }, 860 | { 861 | "type": "SYMBOL", 862 | "name": "true" 863 | }, 864 | { 865 | "type": "SYMBOL", 866 | "name": "false" 867 | }, 868 | { 869 | "type": "SYMBOL", 870 | "name": "null" 871 | } 872 | ] 873 | }, 874 | "index": { 875 | "type": "SEQ", 876 | "members": [ 877 | { 878 | "type": "STRING", 879 | "value": "[" 880 | }, 881 | { 882 | "type": "SYMBOL", 883 | "name": "expression" 884 | }, 885 | { 886 | "type": "STRING", 887 | "value": "]" 888 | } 889 | ] 890 | }, 891 | "get_attr": { 892 | "type": "SEQ", 893 | "members": [ 894 | { 895 | "type": "STRING", 896 | "value": "." 897 | }, 898 | { 899 | "type": "SYMBOL", 900 | "name": "identifier" 901 | } 902 | ] 903 | }, 904 | "splat": { 905 | "type": "CHOICE", 906 | "members": [ 907 | { 908 | "type": "SYMBOL", 909 | "name": "splat_attr" 910 | }, 911 | { 912 | "type": "SYMBOL", 913 | "name": "splat_full" 914 | } 915 | ] 916 | }, 917 | "splat_attr": { 918 | "type": "PREC_RIGHT", 919 | "value": 0, 920 | "content": { 921 | "type": "SEQ", 922 | "members": [ 923 | { 924 | "type": "STRING", 925 | "value": "." 926 | }, 927 | { 928 | "type": "STRING", 929 | "value": "*" 930 | }, 931 | { 932 | "type": "REPEAT", 933 | "content": { 934 | "type": "SYMBOL", 935 | "name": "get_attr" 936 | } 937 | } 938 | ] 939 | } 940 | }, 941 | "splat_full": { 942 | "type": "PREC_RIGHT", 943 | "value": 0, 944 | "content": { 945 | "type": "SEQ", 946 | "members": [ 947 | { 948 | "type": "STRING", 949 | "value": "[" 950 | }, 951 | { 952 | "type": "STRING", 953 | "value": "*" 954 | }, 955 | { 956 | "type": "STRING", 957 | "value": "]" 958 | }, 959 | { 960 | "type": "REPEAT", 961 | "content": { 962 | "type": "CHOICE", 963 | "members": [ 964 | { 965 | "type": "SYMBOL", 966 | "name": "get_attr" 967 | }, 968 | { 969 | "type": "SYMBOL", 970 | "name": "index" 971 | } 972 | ] 973 | } 974 | } 975 | ] 976 | } 977 | }, 978 | "collection_value": { 979 | "type": "CHOICE", 980 | "members": [ 981 | { 982 | "type": "SYMBOL", 983 | "name": "tuple" 984 | }, 985 | { 986 | "type": "SYMBOL", 987 | "name": "object" 988 | } 989 | ] 990 | }, 991 | "tuple": { 992 | "type": "SEQ", 993 | "members": [ 994 | { 995 | "type": "STRING", 996 | "value": "[" 997 | }, 998 | { 999 | "type": "CHOICE", 1000 | "members": [ 1001 | { 1002 | "type": "SEQ", 1003 | "members": [ 1004 | { 1005 | "type": "SYMBOL", 1006 | "name": "expression" 1007 | }, 1008 | { 1009 | "type": "REPEAT", 1010 | "content": { 1011 | "type": "SEQ", 1012 | "members": [ 1013 | { 1014 | "type": "STRING", 1015 | "value": "," 1016 | }, 1017 | { 1018 | "type": "SYMBOL", 1019 | "name": "expression" 1020 | } 1021 | ] 1022 | } 1023 | }, 1024 | { 1025 | "type": "CHOICE", 1026 | "members": [ 1027 | { 1028 | "type": "STRING", 1029 | "value": "," 1030 | }, 1031 | { 1032 | "type": "BLANK" 1033 | } 1034 | ] 1035 | } 1036 | ] 1037 | }, 1038 | { 1039 | "type": "BLANK" 1040 | } 1041 | ] 1042 | }, 1043 | { 1044 | "type": "STRING", 1045 | "value": "]" 1046 | } 1047 | ] 1048 | }, 1049 | "object": { 1050 | "type": "SEQ", 1051 | "members": [ 1052 | { 1053 | "type": "STRING", 1054 | "value": "{" 1055 | }, 1056 | { 1057 | "type": "CHOICE", 1058 | "members": [ 1059 | { 1060 | "type": "SEQ", 1061 | "members": [ 1062 | { 1063 | "type": "SYMBOL", 1064 | "name": "object_elem" 1065 | }, 1066 | { 1067 | "type": "REPEAT", 1068 | "content": { 1069 | "type": "SEQ", 1070 | "members": [ 1071 | { 1072 | "type": "CHOICE", 1073 | "members": [ 1074 | { 1075 | "type": "STRING", 1076 | "value": "," 1077 | }, 1078 | { 1079 | "type": "CHOICE", 1080 | "members": [ 1081 | { 1082 | "type": "STRING", 1083 | "value": "\n" 1084 | } 1085 | ] 1086 | } 1087 | ] 1088 | }, 1089 | { 1090 | "type": "SYMBOL", 1091 | "name": "object_elem" 1092 | } 1093 | ] 1094 | } 1095 | }, 1096 | { 1097 | "type": "CHOICE", 1098 | "members": [ 1099 | { 1100 | "type": "CHOICE", 1101 | "members": [ 1102 | { 1103 | "type": "STRING", 1104 | "value": "," 1105 | }, 1106 | { 1107 | "type": "CHOICE", 1108 | "members": [ 1109 | { 1110 | "type": "STRING", 1111 | "value": "\n" 1112 | } 1113 | ] 1114 | } 1115 | ] 1116 | }, 1117 | { 1118 | "type": "BLANK" 1119 | } 1120 | ] 1121 | } 1122 | ] 1123 | }, 1124 | { 1125 | "type": "BLANK" 1126 | } 1127 | ] 1128 | }, 1129 | { 1130 | "type": "STRING", 1131 | "value": "}" 1132 | } 1133 | ] 1134 | }, 1135 | "object_elem": { 1136 | "type": "SEQ", 1137 | "members": [ 1138 | { 1139 | "type": "CHOICE", 1140 | "members": [ 1141 | { 1142 | "type": "SYMBOL", 1143 | "name": "identifier" 1144 | }, 1145 | { 1146 | "type": "SYMBOL", 1147 | "name": "expression" 1148 | } 1149 | ] 1150 | }, 1151 | { 1152 | "type": "CHOICE", 1153 | "members": [ 1154 | { 1155 | "type": "STRING", 1156 | "value": "=" 1157 | }, 1158 | { 1159 | "type": "STRING", 1160 | "value": ":" 1161 | } 1162 | ] 1163 | }, 1164 | { 1165 | "type": "SYMBOL", 1166 | "name": "expression" 1167 | } 1168 | ] 1169 | }, 1170 | "variable_expr": { 1171 | "type": "PREC_RIGHT", 1172 | "value": 0, 1173 | "content": { 1174 | "type": "SYMBOL", 1175 | "name": "identifier" 1176 | } 1177 | }, 1178 | "function_call": { 1179 | "type": "SEQ", 1180 | "members": [ 1181 | { 1182 | "type": "SYMBOL", 1183 | "name": "identifier" 1184 | }, 1185 | { 1186 | "type": "STRING", 1187 | "value": "(" 1188 | }, 1189 | { 1190 | "type": "CHOICE", 1191 | "members": [ 1192 | { 1193 | "type": "SEQ", 1194 | "members": [ 1195 | { 1196 | "type": "SYMBOL", 1197 | "name": "expression" 1198 | }, 1199 | { 1200 | "type": "REPEAT", 1201 | "content": { 1202 | "type": "SEQ", 1203 | "members": [ 1204 | { 1205 | "type": "STRING", 1206 | "value": "," 1207 | }, 1208 | { 1209 | "type": "SYMBOL", 1210 | "name": "expression" 1211 | } 1212 | ] 1213 | } 1214 | }, 1215 | { 1216 | "type": "CHOICE", 1217 | "members": [ 1218 | { 1219 | "type": "CHOICE", 1220 | "members": [ 1221 | { 1222 | "type": "STRING", 1223 | "value": "," 1224 | }, 1225 | { 1226 | "type": "STRING", 1227 | "value": "..." 1228 | } 1229 | ] 1230 | }, 1231 | { 1232 | "type": "BLANK" 1233 | } 1234 | ] 1235 | } 1236 | ] 1237 | }, 1238 | { 1239 | "type": "BLANK" 1240 | } 1241 | ] 1242 | }, 1243 | { 1244 | "type": "STRING", 1245 | "value": ")" 1246 | } 1247 | ] 1248 | }, 1249 | "numeric_literal": { 1250 | "type": "TOKEN", 1251 | "content": { 1252 | "type": "SEQ", 1253 | "members": [ 1254 | { 1255 | "type": "REPEAT1", 1256 | "content": { 1257 | "type": "PATTERN", 1258 | "value": "[0-9]" 1259 | } 1260 | }, 1261 | { 1262 | "type": "CHOICE", 1263 | "members": [ 1264 | { 1265 | "type": "SEQ", 1266 | "members": [ 1267 | { 1268 | "type": "STRING", 1269 | "value": "." 1270 | }, 1271 | { 1272 | "type": "REPEAT1", 1273 | "content": { 1274 | "type": "PATTERN", 1275 | "value": "[0-9]" 1276 | } 1277 | } 1278 | ] 1279 | }, 1280 | { 1281 | "type": "BLANK" 1282 | } 1283 | ] 1284 | }, 1285 | { 1286 | "type": "CHOICE", 1287 | "members": [ 1288 | { 1289 | "type": "SEQ", 1290 | "members": [ 1291 | { 1292 | "type": "CHOICE", 1293 | "members": [ 1294 | { 1295 | "type": "STRING", 1296 | "value": "e" 1297 | }, 1298 | { 1299 | "type": "STRING", 1300 | "value": "E" 1301 | } 1302 | ] 1303 | }, 1304 | { 1305 | "type": "CHOICE", 1306 | "members": [ 1307 | { 1308 | "type": "CHOICE", 1309 | "members": [ 1310 | { 1311 | "type": "STRING", 1312 | "value": "+" 1313 | }, 1314 | { 1315 | "type": "STRING", 1316 | "value": "-" 1317 | } 1318 | ] 1319 | }, 1320 | { 1321 | "type": "BLANK" 1322 | } 1323 | ] 1324 | }, 1325 | { 1326 | "type": "REPEAT1", 1327 | "content": { 1328 | "type": "PATTERN", 1329 | "value": "[0-9]" 1330 | } 1331 | } 1332 | ] 1333 | }, 1334 | { 1335 | "type": "BLANK" 1336 | } 1337 | ] 1338 | } 1339 | ] 1340 | } 1341 | }, 1342 | "identifier": { 1343 | "type": "TOKEN", 1344 | "content": { 1345 | "type": "SEQ", 1346 | "members": [ 1347 | { 1348 | "type": "CHOICE", 1349 | "members": [ 1350 | { 1351 | "type": "PATTERN", 1352 | "value": "\\p{L}" 1353 | }, 1354 | { 1355 | "type": "STRING", 1356 | "value": "_" 1357 | } 1358 | ] 1359 | }, 1360 | { 1361 | "type": "REPEAT", 1362 | "content": { 1363 | "type": "CHOICE", 1364 | "members": [ 1365 | { 1366 | "type": "CHOICE", 1367 | "members": [ 1368 | { 1369 | "type": "PATTERN", 1370 | "value": "\\p{L}" 1371 | }, 1372 | { 1373 | "type": "STRING", 1374 | "value": "_" 1375 | } 1376 | ] 1377 | }, 1378 | { 1379 | "type": "PATTERN", 1380 | "value": "[0-9]" 1381 | }, 1382 | { 1383 | "type": "STRING", 1384 | "value": "-" 1385 | } 1386 | ] 1387 | } 1388 | } 1389 | ] 1390 | } 1391 | }, 1392 | "null": { 1393 | "type": "STRING", 1394 | "value": "null" 1395 | }, 1396 | "true": { 1397 | "type": "STRING", 1398 | "value": "true" 1399 | }, 1400 | "false": { 1401 | "type": "STRING", 1402 | "value": "false" 1403 | }, 1404 | "comment": { 1405 | "type": "TOKEN", 1406 | "content": { 1407 | "type": "CHOICE", 1408 | "members": [ 1409 | { 1410 | "type": "SEQ", 1411 | "members": [ 1412 | { 1413 | "type": "STRING", 1414 | "value": "//" 1415 | }, 1416 | { 1417 | "type": "PATTERN", 1418 | "value": ".*" 1419 | } 1420 | ] 1421 | }, 1422 | { 1423 | "type": "SEQ", 1424 | "members": [ 1425 | { 1426 | "type": "STRING", 1427 | "value": "#" 1428 | }, 1429 | { 1430 | "type": "PATTERN", 1431 | "value": ".*" 1432 | } 1433 | ] 1434 | }, 1435 | { 1436 | "type": "SEQ", 1437 | "members": [ 1438 | { 1439 | "type": "STRING", 1440 | "value": "/*" 1441 | }, 1442 | { 1443 | "type": "PATTERN", 1444 | "value": "[^*]*\\*+([^/*][^*]*\\*+)*" 1445 | }, 1446 | { 1447 | "type": "STRING", 1448 | "value": "/" 1449 | } 1450 | ] 1451 | } 1452 | ] 1453 | } 1454 | } 1455 | }, 1456 | "extras": [ 1457 | { 1458 | "type": "SYMBOL", 1459 | "name": "comment" 1460 | }, 1461 | { 1462 | "type": "PATTERN", 1463 | "value": "\\s" 1464 | } 1465 | ], 1466 | "conflicts": [], 1467 | "precedences": [], 1468 | "externals": [ 1469 | { 1470 | "type": "SYMBOL", 1471 | "name": "heredoc" 1472 | } 1473 | ], 1474 | "inline": [], 1475 | "supertypes": [] 1476 | } 1477 | 1478 | -------------------------------------------------------------------------------- /src/node-types.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "attribute", 4 | "named": true, 5 | "fields": {}, 6 | "children": { 7 | "multiple": true, 8 | "required": true, 9 | "types": [ 10 | { 11 | "type": "expression", 12 | "named": true 13 | }, 14 | { 15 | "type": "identifier", 16 | "named": true 17 | } 18 | ] 19 | } 20 | }, 21 | { 22 | "type": "binary_op", 23 | "named": true, 24 | "fields": { 25 | "left": { 26 | "multiple": false, 27 | "required": true, 28 | "types": [ 29 | { 30 | "type": "expression", 31 | "named": true 32 | } 33 | ] 34 | }, 35 | "operator": { 36 | "multiple": false, 37 | "required": true, 38 | "types": [ 39 | { 40 | "type": "!=", 41 | "named": false 42 | }, 43 | { 44 | "type": "%", 45 | "named": false 46 | }, 47 | { 48 | "type": "&&", 49 | "named": false 50 | }, 51 | { 52 | "type": "*", 53 | "named": false 54 | }, 55 | { 56 | "type": "+", 57 | "named": false 58 | }, 59 | { 60 | "type": "-", 61 | "named": false 62 | }, 63 | { 64 | "type": "/", 65 | "named": false 66 | }, 67 | { 68 | "type": "<", 69 | "named": false 70 | }, 71 | { 72 | "type": "<=", 73 | "named": false 74 | }, 75 | { 76 | "type": "==", 77 | "named": false 78 | }, 79 | { 80 | "type": ">", 81 | "named": false 82 | }, 83 | { 84 | "type": ">=", 85 | "named": false 86 | }, 87 | { 88 | "type": "||", 89 | "named": false 90 | } 91 | ] 92 | }, 93 | "right": { 94 | "multiple": false, 95 | "required": true, 96 | "types": [ 97 | { 98 | "type": "expression", 99 | "named": true 100 | } 101 | ] 102 | } 103 | } 104 | }, 105 | { 106 | "type": "block", 107 | "named": true, 108 | "fields": {}, 109 | "children": { 110 | "multiple": true, 111 | "required": true, 112 | "types": [ 113 | { 114 | "type": "body", 115 | "named": true 116 | }, 117 | { 118 | "type": "identifier", 119 | "named": true 120 | }, 121 | { 122 | "type": "string_literal", 123 | "named": true 124 | } 125 | ] 126 | } 127 | }, 128 | { 129 | "type": "body", 130 | "named": true, 131 | "fields": {}, 132 | "children": { 133 | "multiple": true, 134 | "required": true, 135 | "types": [ 136 | { 137 | "type": "attribute", 138 | "named": true 139 | }, 140 | { 141 | "type": "block", 142 | "named": true 143 | }, 144 | { 145 | "type": "one_line_block", 146 | "named": true 147 | } 148 | ] 149 | } 150 | }, 151 | { 152 | "type": "collection_value", 153 | "named": true, 154 | "fields": {}, 155 | "children": { 156 | "multiple": false, 157 | "required": true, 158 | "types": [ 159 | { 160 | "type": "object", 161 | "named": true 162 | }, 163 | { 164 | "type": "tuple", 165 | "named": true 166 | } 167 | ] 168 | } 169 | }, 170 | { 171 | "type": "conditional", 172 | "named": true, 173 | "fields": {}, 174 | "children": { 175 | "multiple": true, 176 | "required": true, 177 | "types": [ 178 | { 179 | "type": "expression", 180 | "named": true 181 | } 182 | ] 183 | } 184 | }, 185 | { 186 | "type": "expr_term", 187 | "named": true, 188 | "fields": {}, 189 | "children": { 190 | "multiple": true, 191 | "required": true, 192 | "types": [ 193 | { 194 | "type": "collection_value", 195 | "named": true 196 | }, 197 | { 198 | "type": "expr_term", 199 | "named": true 200 | }, 201 | { 202 | "type": "expression", 203 | "named": true 204 | }, 205 | { 206 | "type": "for_expr", 207 | "named": true 208 | }, 209 | { 210 | "type": "function_call", 211 | "named": true 212 | }, 213 | { 214 | "type": "get_attr", 215 | "named": true 216 | }, 217 | { 218 | "type": "index", 219 | "named": true 220 | }, 221 | { 222 | "type": "literal_value", 223 | "named": true 224 | }, 225 | { 226 | "type": "splat", 227 | "named": true 228 | }, 229 | { 230 | "type": "template_expr", 231 | "named": true 232 | }, 233 | { 234 | "type": "variable_expr", 235 | "named": true 236 | } 237 | ] 238 | } 239 | }, 240 | { 241 | "type": "expression", 242 | "named": true, 243 | "fields": {}, 244 | "children": { 245 | "multiple": false, 246 | "required": true, 247 | "types": [ 248 | { 249 | "type": "conditional", 250 | "named": true 251 | }, 252 | { 253 | "type": "expr_term", 254 | "named": true 255 | }, 256 | { 257 | "type": "operation", 258 | "named": true 259 | } 260 | ] 261 | } 262 | }, 263 | { 264 | "type": "for_cond", 265 | "named": true, 266 | "fields": {}, 267 | "children": { 268 | "multiple": false, 269 | "required": true, 270 | "types": [ 271 | { 272 | "type": "expression", 273 | "named": true 274 | } 275 | ] 276 | } 277 | }, 278 | { 279 | "type": "for_expr", 280 | "named": true, 281 | "fields": {}, 282 | "children": { 283 | "multiple": true, 284 | "required": true, 285 | "types": [ 286 | { 287 | "type": "expression", 288 | "named": true 289 | }, 290 | { 291 | "type": "for_cond", 292 | "named": true 293 | }, 294 | { 295 | "type": "for_intro", 296 | "named": true 297 | } 298 | ] 299 | } 300 | }, 301 | { 302 | "type": "for_intro", 303 | "named": true, 304 | "fields": {}, 305 | "children": { 306 | "multiple": true, 307 | "required": true, 308 | "types": [ 309 | { 310 | "type": "expression", 311 | "named": true 312 | }, 313 | { 314 | "type": "identifier", 315 | "named": true 316 | } 317 | ] 318 | } 319 | }, 320 | { 321 | "type": "function_call", 322 | "named": true, 323 | "fields": {}, 324 | "children": { 325 | "multiple": true, 326 | "required": true, 327 | "types": [ 328 | { 329 | "type": "expression", 330 | "named": true 331 | }, 332 | { 333 | "type": "identifier", 334 | "named": true 335 | } 336 | ] 337 | } 338 | }, 339 | { 340 | "type": "get_attr", 341 | "named": true, 342 | "fields": {}, 343 | "children": { 344 | "multiple": false, 345 | "required": true, 346 | "types": [ 347 | { 348 | "type": "identifier", 349 | "named": true 350 | } 351 | ] 352 | } 353 | }, 354 | { 355 | "type": "index", 356 | "named": true, 357 | "fields": {}, 358 | "children": { 359 | "multiple": false, 360 | "required": true, 361 | "types": [ 362 | { 363 | "type": "expression", 364 | "named": true 365 | } 366 | ] 367 | } 368 | }, 369 | { 370 | "type": "literal_value", 371 | "named": true, 372 | "fields": {}, 373 | "children": { 374 | "multiple": false, 375 | "required": true, 376 | "types": [ 377 | { 378 | "type": "false", 379 | "named": true 380 | }, 381 | { 382 | "type": "null", 383 | "named": true 384 | }, 385 | { 386 | "type": "numeric_literal", 387 | "named": true 388 | }, 389 | { 390 | "type": "true", 391 | "named": true 392 | } 393 | ] 394 | } 395 | }, 396 | { 397 | "type": "object", 398 | "named": true, 399 | "fields": {}, 400 | "children": { 401 | "multiple": true, 402 | "required": false, 403 | "types": [ 404 | { 405 | "type": "object_elem", 406 | "named": true 407 | } 408 | ] 409 | } 410 | }, 411 | { 412 | "type": "object_elem", 413 | "named": true, 414 | "fields": {}, 415 | "children": { 416 | "multiple": true, 417 | "required": true, 418 | "types": [ 419 | { 420 | "type": "expression", 421 | "named": true 422 | }, 423 | { 424 | "type": "identifier", 425 | "named": true 426 | } 427 | ] 428 | } 429 | }, 430 | { 431 | "type": "one_line_block", 432 | "named": true, 433 | "fields": {}, 434 | "children": { 435 | "multiple": true, 436 | "required": true, 437 | "types": [ 438 | { 439 | "type": "expression", 440 | "named": true 441 | }, 442 | { 443 | "type": "identifier", 444 | "named": true 445 | }, 446 | { 447 | "type": "string_literal", 448 | "named": true 449 | } 450 | ] 451 | } 452 | }, 453 | { 454 | "type": "operation", 455 | "named": true, 456 | "fields": {}, 457 | "children": { 458 | "multiple": false, 459 | "required": true, 460 | "types": [ 461 | { 462 | "type": "binary_op", 463 | "named": true 464 | }, 465 | { 466 | "type": "unary_op", 467 | "named": true 468 | } 469 | ] 470 | } 471 | }, 472 | { 473 | "type": "quoted_template", 474 | "named": true, 475 | "fields": {}, 476 | "children": { 477 | "multiple": true, 478 | "required": false, 479 | "types": [ 480 | { 481 | "type": "escape_sequence", 482 | "named": true 483 | } 484 | ] 485 | } 486 | }, 487 | { 488 | "type": "source_file", 489 | "named": true, 490 | "fields": {}, 491 | "children": { 492 | "multiple": false, 493 | "required": true, 494 | "types": [ 495 | { 496 | "type": "body", 497 | "named": true 498 | } 499 | ] 500 | } 501 | }, 502 | { 503 | "type": "splat", 504 | "named": true, 505 | "fields": {}, 506 | "children": { 507 | "multiple": false, 508 | "required": true, 509 | "types": [ 510 | { 511 | "type": "splat_attr", 512 | "named": true 513 | }, 514 | { 515 | "type": "splat_full", 516 | "named": true 517 | } 518 | ] 519 | } 520 | }, 521 | { 522 | "type": "splat_attr", 523 | "named": true, 524 | "fields": {}, 525 | "children": { 526 | "multiple": true, 527 | "required": false, 528 | "types": [ 529 | { 530 | "type": "get_attr", 531 | "named": true 532 | } 533 | ] 534 | } 535 | }, 536 | { 537 | "type": "splat_full", 538 | "named": true, 539 | "fields": {}, 540 | "children": { 541 | "multiple": true, 542 | "required": false, 543 | "types": [ 544 | { 545 | "type": "get_attr", 546 | "named": true 547 | }, 548 | { 549 | "type": "index", 550 | "named": true 551 | } 552 | ] 553 | } 554 | }, 555 | { 556 | "type": "string_literal", 557 | "named": true, 558 | "fields": {}, 559 | "children": { 560 | "multiple": false, 561 | "required": true, 562 | "types": [ 563 | { 564 | "type": "quoted_template", 565 | "named": true 566 | } 567 | ] 568 | } 569 | }, 570 | { 571 | "type": "template_expr", 572 | "named": true, 573 | "fields": {}, 574 | "children": { 575 | "multiple": false, 576 | "required": true, 577 | "types": [ 578 | { 579 | "type": "heredoc", 580 | "named": true 581 | }, 582 | { 583 | "type": "quoted_template", 584 | "named": true 585 | } 586 | ] 587 | } 588 | }, 589 | { 590 | "type": "tuple", 591 | "named": true, 592 | "fields": {}, 593 | "children": { 594 | "multiple": true, 595 | "required": false, 596 | "types": [ 597 | { 598 | "type": "expression", 599 | "named": true 600 | } 601 | ] 602 | } 603 | }, 604 | { 605 | "type": "unary_op", 606 | "named": true, 607 | "fields": {}, 608 | "children": { 609 | "multiple": false, 610 | "required": true, 611 | "types": [ 612 | { 613 | "type": "expr_term", 614 | "named": true 615 | } 616 | ] 617 | } 618 | }, 619 | { 620 | "type": "variable_expr", 621 | "named": true, 622 | "fields": {}, 623 | "children": { 624 | "multiple": false, 625 | "required": true, 626 | "types": [ 627 | { 628 | "type": "identifier", 629 | "named": true 630 | } 631 | ] 632 | } 633 | }, 634 | { 635 | "type": "\n", 636 | "named": false 637 | }, 638 | { 639 | "type": "!", 640 | "named": false 641 | }, 642 | { 643 | "type": "!=", 644 | "named": false 645 | }, 646 | { 647 | "type": "\"", 648 | "named": false 649 | }, 650 | { 651 | "type": "%", 652 | "named": false 653 | }, 654 | { 655 | "type": "&&", 656 | "named": false 657 | }, 658 | { 659 | "type": "(", 660 | "named": false 661 | }, 662 | { 663 | "type": ")", 664 | "named": false 665 | }, 666 | { 667 | "type": "*", 668 | "named": false 669 | }, 670 | { 671 | "type": "+", 672 | "named": false 673 | }, 674 | { 675 | "type": ",", 676 | "named": false 677 | }, 678 | { 679 | "type": "-", 680 | "named": false 681 | }, 682 | { 683 | "type": ".", 684 | "named": false 685 | }, 686 | { 687 | "type": "...", 688 | "named": false 689 | }, 690 | { 691 | "type": "/", 692 | "named": false 693 | }, 694 | { 695 | "type": ":", 696 | "named": false 697 | }, 698 | { 699 | "type": "<", 700 | "named": false 701 | }, 702 | { 703 | "type": "<=", 704 | "named": false 705 | }, 706 | { 707 | "type": "=", 708 | "named": false 709 | }, 710 | { 711 | "type": "==", 712 | "named": false 713 | }, 714 | { 715 | "type": "=>", 716 | "named": false 717 | }, 718 | { 719 | "type": ">", 720 | "named": false 721 | }, 722 | { 723 | "type": ">=", 724 | "named": false 725 | }, 726 | { 727 | "type": "?", 728 | "named": false 729 | }, 730 | { 731 | "type": "[", 732 | "named": false 733 | }, 734 | { 735 | "type": "]", 736 | "named": false 737 | }, 738 | { 739 | "type": "comment", 740 | "named": true 741 | }, 742 | { 743 | "type": "escape_sequence", 744 | "named": true 745 | }, 746 | { 747 | "type": "false", 748 | "named": true 749 | }, 750 | { 751 | "type": "for", 752 | "named": false 753 | }, 754 | { 755 | "type": "heredoc", 756 | "named": true 757 | }, 758 | { 759 | "type": "identifier", 760 | "named": true 761 | }, 762 | { 763 | "type": "if", 764 | "named": false 765 | }, 766 | { 767 | "type": "in", 768 | "named": false 769 | }, 770 | { 771 | "type": "null", 772 | "named": true 773 | }, 774 | { 775 | "type": "numeric_literal", 776 | "named": true 777 | }, 778 | { 779 | "type": "true", 780 | "named": true 781 | }, 782 | { 783 | "type": "{", 784 | "named": false 785 | }, 786 | { 787 | "type": "||", 788 | "named": false 789 | }, 790 | { 791 | "type": "}", 792 | "named": false 793 | } 794 | ] -------------------------------------------------------------------------------- /src/scanner.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | namespace { 7 | 8 | using std::vector; 9 | using std::string; 10 | 11 | enum TokenType { 12 | HEREDOC, 13 | }; 14 | 15 | struct Heredoc { 16 | Heredoc() : end_word_indentation_allowed(false) {} 17 | 18 | string word; 19 | bool end_word_indentation_allowed; 20 | }; 21 | 22 | struct Scanner { 23 | bool has_leading_whitespace; 24 | vector open_heredocs; 25 | 26 | Scanner() : has_leading_whitespace(false) {} 27 | 28 | void reset() { 29 | open_heredocs.clear(); 30 | } 31 | 32 | enum ScanContentResult { 33 | Error, 34 | End 35 | }; 36 | 37 | unsigned serialize(char *buffer) { 38 | unsigned i = 0; 39 | 40 | buffer[i++] = open_heredocs.size(); 41 | for ( 42 | vector::iterator iter = open_heredocs.begin(), 43 | end = open_heredocs.end(); 44 | iter != end; 45 | ++iter 46 | ) { 47 | if (i + 2 + iter->word.size() >= TREE_SITTER_SERIALIZATION_BUFFER_SIZE) return 0; 48 | buffer[i++] = iter->end_word_indentation_allowed; 49 | buffer[i++] = iter->word.size(); 50 | iter->word.copy(&buffer[i], iter->word.size()); 51 | i += iter->word.size(); 52 | } 53 | 54 | return i; 55 | } 56 | 57 | void deserialize(const char *buffer, unsigned length) { 58 | unsigned i = 0; 59 | has_leading_whitespace = false; 60 | open_heredocs.clear(); 61 | 62 | if (length == 0) return; 63 | 64 | uint8_t open_heredoc_count = buffer[i++]; 65 | for (unsigned j = 0; j < open_heredoc_count; j++) { 66 | Heredoc heredoc; 67 | heredoc.end_word_indentation_allowed = buffer[i++]; 68 | uint8_t word_length = buffer[i++]; 69 | heredoc.word.assign(buffer + i, buffer + i + word_length); 70 | i += word_length; 71 | open_heredocs.push_back(heredoc); 72 | } 73 | } 74 | 75 | void skip(TSLexer *lexer) { 76 | has_leading_whitespace = true; 77 | lexer->advance(lexer, true); 78 | } 79 | 80 | void advance(TSLexer *lexer) { 81 | lexer->advance(lexer, false); 82 | } 83 | 84 | bool scan_whitespace(TSLexer *lexer) { 85 | for (;;) { 86 | while (iswspace(lexer->lookahead)) { 87 | advance(lexer); 88 | } 89 | 90 | if (lexer->lookahead == '/') { 91 | advance(lexer); 92 | 93 | if (lexer->lookahead == '/') { 94 | advance(lexer); 95 | while (lexer->lookahead != 0 && lexer->lookahead != '\n') { 96 | advance(lexer); 97 | } 98 | } else { 99 | return false; 100 | } 101 | } else { 102 | return true; 103 | } 104 | } 105 | } 106 | 107 | string scan_heredoc_word(TSLexer *lexer) { 108 | string result; 109 | int32_t quote; 110 | 111 | switch (lexer->lookahead) { 112 | case '\'': 113 | quote = lexer->lookahead; 114 | advance(lexer); 115 | while (lexer->lookahead != quote && lexer->lookahead != 0) { 116 | result += lexer->lookahead; 117 | advance(lexer); 118 | } 119 | advance(lexer); 120 | break; 121 | 122 | default: 123 | if (iswalnum(lexer->lookahead) || lexer->lookahead == '_') { 124 | result += lexer->lookahead; 125 | advance(lexer); 126 | while (iswalnum(lexer->lookahead) || lexer->lookahead == '_') { 127 | result += lexer->lookahead; 128 | advance(lexer); 129 | } 130 | } 131 | break; 132 | } 133 | 134 | return result; 135 | } 136 | 137 | 138 | ScanContentResult scan_heredoc_content(TSLexer *lexer) { 139 | if (open_heredocs.empty()) return Error; 140 | Heredoc heredoc = open_heredocs.front(); 141 | size_t position_in_word = 0; 142 | 143 | for (;;) { 144 | if (position_in_word == heredoc.word.size()) { 145 | if (lexer->lookahead == ';' || lexer->lookahead == '\n' || lexer->lookahead == '\r') { 146 | open_heredocs.erase(open_heredocs.begin()); 147 | return End; 148 | } 149 | 150 | position_in_word = 0; 151 | } 152 | if (lexer->lookahead == 0) { 153 | open_heredocs.erase(open_heredocs.begin()); 154 | return Error; 155 | } 156 | 157 | if (lexer->lookahead == heredoc.word[position_in_word]) { 158 | advance(lexer); 159 | position_in_word++; 160 | } else { 161 | position_in_word = 0; 162 | advance(lexer); 163 | } 164 | } 165 | } 166 | 167 | bool scan(TSLexer *lexer, const bool *valid_symbols) { 168 | has_leading_whitespace = false; 169 | 170 | lexer->mark_end(lexer); 171 | 172 | if (!scan_whitespace(lexer)) return false; 173 | 174 | if (valid_symbols[HEREDOC]) { 175 | if (lexer->lookahead == '<') { 176 | advance(lexer); 177 | if (lexer->lookahead != '<') return false; 178 | advance(lexer); 179 | 180 | if (!scan_whitespace(lexer)) return false; 181 | 182 | // Found a heredoc 183 | Heredoc heredoc; 184 | heredoc.word = scan_heredoc_word(lexer); 185 | if (heredoc.word.empty()) return false; 186 | open_heredocs.push_back(heredoc); 187 | 188 | switch (scan_heredoc_content(lexer)) { 189 | case Error: 190 | return false; 191 | case End: 192 | lexer->result_symbol = HEREDOC; 193 | lexer->mark_end(lexer); 194 | return true; 195 | } 196 | } 197 | } 198 | 199 | return false; 200 | } 201 | }; 202 | 203 | } 204 | 205 | extern "C" { 206 | 207 | void *tree_sitter_hcl_external_scanner_create() { 208 | return new Scanner(); 209 | } 210 | 211 | unsigned tree_sitter_hcl_external_scanner_serialize(void *payload, char *buffer) { 212 | Scanner *scanner = static_cast(payload); 213 | return scanner->serialize(buffer); 214 | } 215 | 216 | void tree_sitter_hcl_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) { 217 | Scanner *scanner = static_cast(payload); 218 | scanner->deserialize(buffer, length); 219 | } 220 | 221 | void tree_sitter_hcl_external_scanner_destroy(void *payload) { 222 | Scanner *scanner = static_cast(payload); 223 | delete scanner; 224 | } 225 | 226 | bool tree_sitter_hcl_external_scanner_scan(void *payload, TSLexer *lexer, 227 | const bool *valid_symbols) { 228 | 229 | Scanner *scanner = static_cast(payload); 230 | return scanner->scan(lexer, valid_symbols); 231 | } 232 | 233 | void tree_sitter_hcl_external_scanner_reset(void *p) {} 234 | 235 | } 236 | -------------------------------------------------------------------------------- /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 | typedef uint16_t TSStateId; 17 | 18 | #ifndef TREE_SITTER_API_H_ 19 | typedef uint16_t TSSymbol; 20 | typedef uint16_t TSFieldId; 21 | typedef struct TSLanguage TSLanguage; 22 | #endif 23 | 24 | typedef struct { 25 | TSFieldId field_id; 26 | uint8_t child_index; 27 | bool inherited; 28 | } TSFieldMapEntry; 29 | 30 | typedef struct { 31 | uint16_t index; 32 | uint16_t length; 33 | } TSFieldMapSlice; 34 | 35 | typedef struct { 36 | bool visible; 37 | bool named; 38 | bool supertype; 39 | } TSSymbolMetadata; 40 | 41 | typedef struct TSLexer TSLexer; 42 | 43 | struct TSLexer { 44 | int32_t lookahead; 45 | TSSymbol result_symbol; 46 | void (*advance)(TSLexer *, bool); 47 | void (*mark_end)(TSLexer *); 48 | uint32_t (*get_column)(TSLexer *); 49 | bool (*is_at_included_range_start)(const TSLexer *); 50 | bool (*eof)(const TSLexer *); 51 | }; 52 | 53 | typedef enum { 54 | TSParseActionTypeShift, 55 | TSParseActionTypeReduce, 56 | TSParseActionTypeAccept, 57 | TSParseActionTypeRecover, 58 | } TSParseActionType; 59 | 60 | typedef union { 61 | struct { 62 | uint8_t type; 63 | TSStateId state; 64 | bool extra; 65 | bool repetition; 66 | } shift; 67 | struct { 68 | uint8_t type; 69 | uint8_t child_count; 70 | TSSymbol symbol; 71 | int16_t dynamic_precedence; 72 | uint16_t production_id; 73 | } reduce; 74 | uint8_t type; 75 | } TSParseAction; 76 | 77 | typedef struct { 78 | uint16_t lex_state; 79 | uint16_t external_lex_state; 80 | } TSLexMode; 81 | 82 | typedef union { 83 | TSParseAction action; 84 | struct { 85 | uint8_t count; 86 | bool reusable; 87 | } entry; 88 | } TSParseActionEntry; 89 | 90 | struct TSLanguage { 91 | uint32_t version; 92 | uint32_t symbol_count; 93 | uint32_t alias_count; 94 | uint32_t token_count; 95 | uint32_t external_token_count; 96 | uint32_t state_count; 97 | uint32_t large_state_count; 98 | uint32_t production_id_count; 99 | uint32_t field_count; 100 | uint16_t max_alias_sequence_length; 101 | const uint16_t *parse_table; 102 | const uint16_t *small_parse_table; 103 | const uint32_t *small_parse_table_map; 104 | const TSParseActionEntry *parse_actions; 105 | const char * const *symbol_names; 106 | const char * const *field_names; 107 | const TSFieldMapSlice *field_map_slices; 108 | const TSFieldMapEntry *field_map_entries; 109 | const TSSymbolMetadata *symbol_metadata; 110 | const TSSymbol *public_symbol_map; 111 | const uint16_t *alias_map; 112 | const TSSymbol *alias_sequences; 113 | const TSLexMode *lex_modes; 114 | bool (*lex_fn)(TSLexer *, TSStateId); 115 | bool (*keyword_lex_fn)(TSLexer *, TSStateId); 116 | TSSymbol keyword_capture_token; 117 | struct { 118 | const bool *states; 119 | const TSSymbol *symbol_map; 120 | void *(*create)(void); 121 | void (*destroy)(void *); 122 | bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist); 123 | unsigned (*serialize)(void *, char *); 124 | void (*deserialize)(void *, const char *, unsigned); 125 | } external_scanner; 126 | }; 127 | 128 | /* 129 | * Lexer Macros 130 | */ 131 | 132 | #define START_LEXER() \ 133 | bool result = false; \ 134 | bool skip = false; \ 135 | bool eof = false; \ 136 | int32_t lookahead; \ 137 | goto start; \ 138 | next_state: \ 139 | lexer->advance(lexer, skip); \ 140 | start: \ 141 | skip = false; \ 142 | lookahead = lexer->lookahead; 143 | 144 | #define ADVANCE(state_value) \ 145 | { \ 146 | state = state_value; \ 147 | goto next_state; \ 148 | } 149 | 150 | #define SKIP(state_value) \ 151 | { \ 152 | skip = true; \ 153 | state = state_value; \ 154 | goto next_state; \ 155 | } 156 | 157 | #define ACCEPT_TOKEN(symbol_value) \ 158 | result = true; \ 159 | lexer->result_symbol = symbol_value; \ 160 | lexer->mark_end(lexer); 161 | 162 | #define END_STATE() return result; 163 | 164 | /* 165 | * Parse Table Macros 166 | */ 167 | 168 | #define SMALL_STATE(id) id - LARGE_STATE_COUNT 169 | 170 | #define STATE(id) id 171 | 172 | #define ACTIONS(id) id 173 | 174 | #define SHIFT(state_value) \ 175 | {{ \ 176 | .shift = { \ 177 | .type = TSParseActionTypeShift, \ 178 | .state = state_value \ 179 | } \ 180 | }} 181 | 182 | #define SHIFT_REPEAT(state_value) \ 183 | {{ \ 184 | .shift = { \ 185 | .type = TSParseActionTypeShift, \ 186 | .state = state_value, \ 187 | .repetition = true \ 188 | } \ 189 | }} 190 | 191 | #define SHIFT_EXTRA() \ 192 | {{ \ 193 | .shift = { \ 194 | .type = TSParseActionTypeShift, \ 195 | .extra = true \ 196 | } \ 197 | }} 198 | 199 | #define REDUCE(symbol_val, child_count_val, ...) \ 200 | {{ \ 201 | .reduce = { \ 202 | .type = TSParseActionTypeReduce, \ 203 | .symbol = symbol_val, \ 204 | .child_count = child_count_val, \ 205 | __VA_ARGS__ \ 206 | }, \ 207 | }} 208 | 209 | #define RECOVER() \ 210 | {{ \ 211 | .type = TSParseActionTypeRecover \ 212 | }} 213 | 214 | #define ACCEPT_INPUT() \ 215 | {{ \ 216 | .type = TSParseActionTypeAccept \ 217 | }} 218 | 219 | #ifdef __cplusplus 220 | } 221 | #endif 222 | 223 | #endif // TREE_SITTER_PARSER_H_ 224 | --------------------------------------------------------------------------------