├── bindings ├── python │ ├── tree_sitter_embedded_template │ │ ├── py.typed │ │ ├── __init__.pyi │ │ ├── binding.c │ │ └── __init__.py │ └── tests │ │ └── test_binding.py ├── node │ ├── binding_test.js │ ├── index.js │ ├── index.d.ts │ └── binding.cc ├── c │ ├── tree-sitter-embedded-template.pc.in │ └── tree_sitter │ │ └── tree-sitter-embedded-template.h ├── swift │ ├── TreeSitterEmbeddedTemplate │ │ └── embedded-template.h │ └── TreeSitterEmbeddedTemplateTests │ │ └── TreeSitterEmbeddedTemplateTests.swift ├── go │ ├── binding.go │ └── binding_test.go └── rust │ ├── build.rs │ └── lib.rs ├── eslint.config.mjs ├── queries ├── highlights.scm ├── injections-erb.scm ├── injections-etlua.scm └── injections-ejs.scm ├── go.mod ├── Package.resolved ├── .github ├── workflows │ ├── lint.yml │ ├── publish.yml │ └── ci.yml └── FUNDING.yml ├── .gitignore ├── .editorconfig ├── binding.gyp ├── Cargo.toml ├── pyproject.toml ├── LICENSE ├── .gitattributes ├── src ├── tree_sitter │ ├── alloc.h │ ├── parser.h │ └── array.h ├── node-types.json ├── grammar.json └── parser.c ├── grammar.js ├── Package.swift ├── package.json ├── README.md ├── tree-sitter.json ├── setup.py ├── CMakeLists.txt ├── test └── corpus │ └── main.txt ├── go.sum ├── Makefile └── Cargo.lock /bindings/python/tree_sitter_embedded_template/py.typed: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /eslint.config.mjs: -------------------------------------------------------------------------------- 1 | import treesitter from 'eslint-config-treesitter'; 2 | 3 | export default [ 4 | ...treesitter, 5 | ]; 6 | -------------------------------------------------------------------------------- /queries/highlights.scm: -------------------------------------------------------------------------------- 1 | (comment_directive) @comment 2 | 3 | [ 4 | "<%#" 5 | "<%" 6 | "<%=" 7 | "<%_" 8 | "<%-" 9 | "%>" 10 | "-%>" 11 | "_%>" 12 | ] @keyword 13 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/tree-sitter/tree-sitter-embedded-template 2 | 3 | go 1.22 4 | 5 | require github.com/tree-sitter/go-tree-sitter v0.24.0 6 | 7 | require github.com/mattn/go-pointer v0.0.1 // indirect 8 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_embedded_template/__init__.pyi: -------------------------------------------------------------------------------- 1 | from typing import Final 2 | 3 | HIGHLIGHTS_QUERY: Final[str] 4 | INJECTIONS_EJS_QUERY: Final[str] 5 | INJECTIONS_ERB_QUERY: Final[str] 6 | 7 | def language() -> object: ... 8 | -------------------------------------------------------------------------------- /queries/injections-erb.scm: -------------------------------------------------------------------------------- 1 | ((content) @injection.content 2 | (#set! injection.language "html") 3 | (#set! injection.combined)) 4 | 5 | ((code) @injection.content 6 | (#set! injection.language "ruby") 7 | (#set! injection.combined)) 8 | -------------------------------------------------------------------------------- /queries/injections-etlua.scm: -------------------------------------------------------------------------------- 1 | ((content) @injection.content 2 | (#set! injection.language "html") 3 | (#set! injection.combined)) 4 | 5 | ((code) @injection.content 6 | (#set! injection.language "lua") 7 | (#set! injection.combined)) 8 | -------------------------------------------------------------------------------- /queries/injections-ejs.scm: -------------------------------------------------------------------------------- 1 | ((content) @injection.content 2 | (#set! injection.language "html") 3 | (#set! injection.combined)) 4 | 5 | ((code) @injection.content 6 | (#set! injection.language "javascript") 7 | (#set! injection.combined)) 8 | -------------------------------------------------------------------------------- /bindings/node/binding_test.js: -------------------------------------------------------------------------------- 1 | const assert = require("node:assert"); 2 | const { test } = require("node:test"); 3 | 4 | const Parser = require("tree-sitter"); 5 | 6 | test("can load grammar", () => { 7 | const parser = new Parser(); 8 | assert.doesNotThrow(() => parser.setLanguage(require("."))); 9 | }); 10 | -------------------------------------------------------------------------------- /bindings/c/tree-sitter-embedded-template.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@CMAKE_INSTALL_PREFIX@ 2 | libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ 3 | includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ 4 | 5 | Name: tree-sitter-embedded-template 6 | Description: @PROJECT_DESCRIPTION@ 7 | URL: @PROJECT_HOMEPAGE_URL@ 8 | Version: @PROJECT_VERSION@ 9 | Libs: -L${libdir} -ltree-sitter-embedded-template 10 | Cflags: -I${includedir} 11 | -------------------------------------------------------------------------------- /bindings/c/tree_sitter/tree-sitter-embedded-template.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_EMBEDDED_TEMPLATE_H_ 2 | #define TREE_SITTER_EMBEDDED_TEMPLATE_H_ 3 | 4 | typedef struct TSLanguage TSLanguage; 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | const TSLanguage *tree_sitter_embedded_template(void); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif // TREE_SITTER_EMBEDDED_TEMPLATE_H_ 17 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "SwiftTreeSitter", 6 | "repositoryURL": "https://github.com/ChimeHQ/SwiftTreeSitter", 7 | "state": { 8 | "branch": null, 9 | "revision": "2599e95310b3159641469d8a21baf2d3d200e61f", 10 | "version": "0.8.0" 11 | } 12 | } 13 | ] 14 | }, 15 | "version": 1 16 | } 17 | -------------------------------------------------------------------------------- /bindings/python/tests/test_binding.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase 2 | 3 | import tree_sitter 4 | import tree_sitter_embedded_template 5 | 6 | 7 | class TestLanguage(TestCase): 8 | def test_can_load_grammar(self): 9 | try: 10 | tree_sitter.Language(tree_sitter_embedded_template.language()) 11 | except Exception: 12 | self.fail("Error loading EmbeddedTemplate grammar") 13 | -------------------------------------------------------------------------------- /bindings/swift/TreeSitterEmbeddedTemplate/embedded-template.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_EMBEDDED_TEMPLATE_H_ 2 | #define TREE_SITTER_EMBEDDED_TEMPLATE_H_ 3 | 4 | typedef struct TSLanguage TSLanguage; 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | const TSLanguage *tree_sitter_embedded_template(void); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | 16 | #endif // TREE_SITTER_EMBEDDED_TEMPLATE_H_ 17 | -------------------------------------------------------------------------------- /bindings/go/binding.go: -------------------------------------------------------------------------------- 1 | package tree_sitter_embedded_template 2 | 3 | // #cgo CFLAGS: -std=c11 -fPIC 4 | // #include "../../src/parser.c" 5 | // #if __has_include("../../src/scanner.c") 6 | // #include "../../src/scanner.c" 7 | // #endif 8 | import "C" 9 | 10 | import "unsafe" 11 | 12 | // Get the tree-sitter Language for this grammar. 13 | func Language() unsafe.Pointer { 14 | return unsafe.Pointer(C.tree_sitter_embedded_template()) 15 | } 16 | -------------------------------------------------------------------------------- /bindings/go/binding_test.go: -------------------------------------------------------------------------------- 1 | package tree_sitter_embedded_template_test 2 | 3 | import ( 4 | "testing" 5 | 6 | tree_sitter "github.com/tree-sitter/go-tree-sitter" 7 | tree_sitter_embedded_template "github.com/tree-sitter/tree-sitter-embedded-template/bindings/go" 8 | ) 9 | 10 | func TestCanLoadGrammar(t *testing.T) { 11 | language := tree_sitter.NewLanguage(tree_sitter_embedded_template.Language()) 12 | if language == nil { 13 | t.Errorf("Error loading EmbeddedTemplate grammar") 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /bindings/node/index.js: -------------------------------------------------------------------------------- 1 | const root = require("path").join(__dirname, "..", ".."); 2 | 3 | module.exports = 4 | typeof process.versions.bun === "string" 5 | // Support `bun build --compile` by being statically analyzable enough to find the .node file at build-time 6 | ? require(`../../prebuilds/${process.platform}-${process.arch}/tree-sitter-embedded-template.node`) 7 | : require("node-gyp-build")(root); 8 | 9 | try { 10 | module.exports.nodeTypeInfo = require("../../src/node-types.json"); 11 | } catch (_) {} 12 | -------------------------------------------------------------------------------- /bindings/swift/TreeSitterEmbeddedTemplateTests/TreeSitterEmbeddedTemplateTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | import SwiftTreeSitter 3 | import TreeSitterEmbeddedTemplate 4 | 5 | final class TreeSitterEmbeddedTemplateTests: XCTestCase { 6 | func testCanLoadGrammar() throws { 7 | let parser = Parser() 8 | let language = Language(language: tree_sitter_embedded_template()) 9 | XCTAssertNoThrow(try parser.setLanguage(language), 10 | "Error loading EmbeddedTemplate grammar") 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /bindings/node/index.d.ts: -------------------------------------------------------------------------------- 1 | type BaseNode = { 2 | type: string; 3 | named: boolean; 4 | }; 5 | 6 | type ChildNode = { 7 | multiple: boolean; 8 | required: boolean; 9 | types: BaseNode[]; 10 | }; 11 | 12 | type NodeInfo = 13 | | (BaseNode & { 14 | subtypes: BaseNode[]; 15 | }) 16 | | (BaseNode & { 17 | fields: { [name: string]: ChildNode }; 18 | children: ChildNode[]; 19 | }); 20 | 21 | type Language = { 22 | language: unknown; 23 | nodeTypeInfo: NodeInfo[]; 24 | }; 25 | 26 | declare const language: Language; 27 | export = language; 28 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | paths: 7 | - grammar.js 8 | pull_request: 9 | paths: 10 | - grammar.js 11 | 12 | jobs: 13 | lint: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | - name: Set up Node.js 19 | uses: actions/setup-node@v4 20 | with: 21 | cache: npm 22 | node-version: ${{vars.NODE_VERSION}} 23 | - name: Install modules 24 | run: npm ci --legacy-peer-deps 25 | - name: Run ESLint 26 | run: npm run lint 27 | -------------------------------------------------------------------------------- /bindings/node/binding.cc: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | extern "C" TSLanguage *tree_sitter_embedded_template(); 6 | 7 | // "tree-sitter", "language" hashed with BLAKE2 8 | const napi_type_tag LANGUAGE_TYPE_TAG = { 9 | 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16 10 | }; 11 | 12 | Napi::Object Init(Napi::Env env, Napi::Object exports) { 13 | auto language = Napi::External::New(env, tree_sitter_embedded_template()); 14 | language.TypeTag(&LANGUAGE_TYPE_TAG); 15 | exports["language"] = language; 16 | return exports; 17 | } 18 | 19 | NODE_API_MODULE(tree_sitter_embedded_template_binding, Init) 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Rust artifacts 2 | target/ 3 | Cargo.lock 4 | 5 | # Node artifacts 6 | build/ 7 | prebuilds/ 8 | node_modules/ 9 | package-lock.json 10 | 11 | # Swift artifacts 12 | .build/ 13 | Package.resolved 14 | 15 | # Go artifacts 16 | _obj/ 17 | 18 | # Python artifacts 19 | .venv/ 20 | dist/ 21 | *.egg-info 22 | *.whl 23 | 24 | # C artifacts 25 | *.a 26 | *.so 27 | *.so.* 28 | *.dylib 29 | *.dll 30 | *.pc 31 | *.exp 32 | *.lib 33 | 34 | # Zig artifacts 35 | .zig-cache/ 36 | zig-cache/ 37 | zig-out/ 38 | 39 | # Example dirs 40 | /examples/*/ 41 | 42 | # Grammar volatiles 43 | *.wasm 44 | *.obj 45 | *.o 46 | 47 | # Archives 48 | *.tar.gz 49 | *.tgz 50 | *.zip 51 | -------------------------------------------------------------------------------- /bindings/rust/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | let src_dir = std::path::Path::new("src"); 3 | 4 | let mut c_config = cc::Build::new(); 5 | c_config.std("c11").include(src_dir); 6 | 7 | #[cfg(target_env = "msvc")] 8 | c_config.flag("-utf-8"); 9 | 10 | let parser_path = src_dir.join("parser.c"); 11 | c_config.file(&parser_path); 12 | println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); 13 | 14 | let scanner_path = src_dir.join("scanner.c"); 15 | if scanner_path.exists() { 16 | c_config.file(&scanner_path); 17 | println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); 18 | } 19 | 20 | c_config.compile("tree-sitter-embedded-template"); 21 | } 22 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | 6 | [*.{json,toml,yml,gyp}] 7 | indent_style = space 8 | indent_size = 2 9 | 10 | [*.js] 11 | indent_style = space 12 | indent_size = 2 13 | 14 | [*.scm] 15 | indent_style = space 16 | indent_size = 2 17 | 18 | [*.{c,cc,h}] 19 | indent_style = space 20 | indent_size = 4 21 | 22 | [*.rs] 23 | indent_style = space 24 | indent_size = 4 25 | 26 | [*.{py,pyi}] 27 | indent_style = space 28 | indent_size = 4 29 | 30 | [*.swift] 31 | indent_style = space 32 | indent_size = 4 33 | 34 | [*.go] 35 | indent_style = tab 36 | indent_size = 8 37 | 38 | [Makefile] 39 | indent_style = tab 40 | indent_size = 8 41 | 42 | [parser.c] 43 | indent_size = 2 44 | 45 | [{alloc,array,parser}.h] 46 | indent_size = 2 47 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: tree-sitter 4 | patreon: # Replace with a single Patreon username 5 | open_collective: tree-sitter # Replace with a single Open Collective username 6 | ko_fi: amaanq 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /binding.gyp: -------------------------------------------------------------------------------- 1 | { 2 | "targets": [ 3 | { 4 | "target_name": "tree_sitter_embedded_template_binding", 5 | "dependencies": [ 6 | ""] 6 | license = "MIT" 7 | readme = "README.md" 8 | keywords = ["incremental", "parsing", "tree-sitter", "embedded-template"] 9 | categories = ["parser-implementations", "parsing", "text-editors"] 10 | repository = "https://github.com/tree-sitter/tree-sitter-embedded-template" 11 | edition = "2021" 12 | autoexamples = false 13 | 14 | build = "bindings/rust/build.rs" 15 | include = [ 16 | "bindings/rust/*", 17 | "grammar.js", 18 | "queries/*", 19 | "src/*", 20 | "tree-sitter.json", 21 | "LICENSE", 22 | ] 23 | 24 | [lib] 25 | path = "bindings/rust/lib.rs" 26 | 27 | [dependencies] 28 | tree-sitter-language = "0.1" 29 | 30 | [build-dependencies] 31 | cc = "1.2" 32 | 33 | [dev-dependencies] 34 | tree-sitter = "0.25.8" 35 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish packages 2 | 3 | on: 4 | push: 5 | tags: ["*"] 6 | 7 | permissions: 8 | contents: write 9 | id-token: write 10 | attestations: write 11 | 12 | jobs: 13 | github: 14 | uses: tree-sitter/workflows/.github/workflows/release.yml@main 15 | with: 16 | generate: true 17 | attestations: true 18 | npm: 19 | uses: tree-sitter/workflows/.github/workflows/package-npm.yml@main 20 | secrets: 21 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 22 | with: 23 | generate: true 24 | crates: 25 | uses: tree-sitter/workflows/.github/workflows/package-crates.yml@main 26 | secrets: 27 | CARGO_REGISTRY_TOKEN: ${{secrets.CARGO_REGISTRY_TOKEN}} 28 | with: 29 | generate: true 30 | pypi: 31 | uses: tree-sitter/workflows/.github/workflows/package-pypi.yml@main 32 | secrets: 33 | PYPI_API_TOKEN: ${{secrets.PYPI_API_TOKEN}} 34 | with: 35 | generate: true 36 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools>=62.4.0", "wheel"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | [project] 6 | name = "tree-sitter-embedded-template" 7 | description = "Embedded Template (ERB, EJS) grammar for tree-sitter" 8 | version = "0.25.0" 9 | keywords = ["incremental", "parsing", "tree-sitter", "embedded-template"] 10 | classifiers = [ 11 | "Intended Audience :: Developers", 12 | "Topic :: Software Development :: Compilers", 13 | "Topic :: Text Processing :: Linguistic", 14 | "Typing :: Typed", 15 | ] 16 | authors = [ 17 | { name = "Max Brunsfeld", email = "maxbrunsfeld@gmail.com" }, 18 | { name = "Amaan Qureshi", email = "amaanq12@gmail.com" }, 19 | ] 20 | requires-python = ">=3.10" 21 | license.text = "MIT" 22 | readme = "README.md" 23 | 24 | [project.urls] 25 | Homepage = "https://github.com/tree-sitter/tree-sitter-embedded-template" 26 | 27 | [project.optional-dependencies] 28 | core = ["tree-sitter~=0.24"] 29 | 30 | [tool.cibuildwheel] 31 | build = "cp310-*" 32 | build-frontend = "build" 33 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_embedded_template/binding.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct TSLanguage TSLanguage; 4 | 5 | TSLanguage *tree_sitter_embedded_template(void); 6 | 7 | static PyObject* _binding_language(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { 8 | return PyCapsule_New(tree_sitter_embedded_template(), "tree_sitter.Language", NULL); 9 | } 10 | 11 | static struct PyModuleDef_Slot slots[] = { 12 | #ifdef Py_GIL_DISABLED 13 | {Py_mod_gil, Py_MOD_GIL_NOT_USED}, 14 | #endif 15 | {0, NULL} 16 | }; 17 | 18 | static PyMethodDef methods[] = { 19 | {"language", _binding_language, METH_NOARGS, 20 | "Get the tree-sitter language for this grammar."}, 21 | {NULL, NULL, 0, NULL} 22 | }; 23 | 24 | static struct PyModuleDef module = { 25 | .m_base = PyModuleDef_HEAD_INIT, 26 | .m_name = "_binding", 27 | .m_doc = NULL, 28 | .m_size = 0, 29 | .m_methods = methods, 30 | .m_slots = slots, 31 | }; 32 | 33 | PyMODINIT_FUNC PyInit__binding(void) { 34 | return PyModuleDef_Init(&module); 35 | } 36 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | paths: 7 | - grammar.js 8 | - src/** 9 | - test/** 10 | - bindings/** 11 | - binding.gyp 12 | pull_request: 13 | paths: 14 | - grammar.js 15 | - src/** 16 | - test/** 17 | - bindings/** 18 | - binding.gyp 19 | 20 | concurrency: 21 | group: ${{github.workflow}}-${{github.ref}} 22 | cancel-in-progress: true 23 | 24 | jobs: 25 | test: 26 | name: Test parser 27 | runs-on: ${{matrix.os}} 28 | strategy: 29 | fail-fast: false 30 | matrix: 31 | os: [ubuntu-latest, windows-latest, macos-latest] 32 | steps: 33 | - name: Checkout repository 34 | uses: actions/checkout@v4 35 | - name: Set up tree-sitter 36 | uses: tree-sitter/setup-action/cli@v1 37 | - name: Run tests 38 | uses: tree-sitter/parser-test-action@v2 39 | with: 40 | test-rust: true 41 | test-node: true 42 | test-python: true 43 | test-go: true 44 | test-swift: true 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Max Brunsfeld 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | 3 | # Generated source files 4 | src/*.json linguist-generated 5 | src/parser.c linguist-generated 6 | src/tree_sitter/* linguist-generated 7 | 8 | # C bindings 9 | bindings/c/** linguist-generated 10 | CMakeLists.txt linguist-generated 11 | Makefile linguist-generated 12 | 13 | # Rust bindings 14 | bindings/rust/* linguist-generated 15 | Cargo.toml linguist-generated 16 | Cargo.lock linguist-generated 17 | 18 | # Node.js bindings 19 | bindings/node/* linguist-generated 20 | binding.gyp linguist-generated 21 | package.json linguist-generated 22 | package-lock.json linguist-generated 23 | 24 | # Python bindings 25 | bindings/python/** linguist-generated 26 | setup.py linguist-generated 27 | pyproject.toml linguist-generated 28 | 29 | # Go bindings 30 | bindings/go/* linguist-generated 31 | go.mod linguist-generated 32 | go.sum linguist-generated 33 | 34 | # Swift bindings 35 | bindings/swift/** linguist-generated 36 | Package.swift linguist-generated 37 | Package.resolved linguist-generated 38 | 39 | # Zig bindings 40 | bindings/zig/* linguist-generated 41 | build.zig linguist-generated 42 | build.zig.zon linguist-generated 43 | -------------------------------------------------------------------------------- /bindings/python/tree_sitter_embedded_template/__init__.py: -------------------------------------------------------------------------------- 1 | """Embedded Template (ERB, EJS) grammar for tree-sitter""" 2 | 3 | from importlib.resources import files as _files 4 | 5 | from ._binding import language 6 | 7 | 8 | def _get_query(name, file): 9 | query = _files(f"{__package__}.queries") / file 10 | globals()[name] = query.read_text() 11 | return globals()[name] 12 | 13 | 14 | def __getattr__(name): 15 | if name == "HIGHLIGHTS_QUERY": 16 | return _get_query("HIGHLIGHTS_QUERY", "highlights.scm") 17 | if name == "INJECTIONS_EJS_QUERY": 18 | return _get_query("INJECTIONS_EJS_QUERY", "injections-ejs.scm") 19 | if name == "INJECTIONS_ERB_QUERY": 20 | return _get_query("INJECTIONS_ERB_QUERY", "injections-erb.scm") 21 | 22 | raise AttributeError(f"module {__name__!r} has no attribute {name!r}") 23 | 24 | 25 | __all__ = [ 26 | "language", 27 | "HIGHLIGHTS_QUERY", 28 | "INJECTIONS_EJS_QUERY", 29 | "INJECTIONS_ERB_QUERY", 30 | ] 31 | 32 | 33 | def __dir__(): 34 | return sorted(__all__ + [ 35 | "__all__", "__builtins__", "__cached__", "__doc__", "__file__", 36 | "__loader__", "__name__", "__package__", "__path__", "__spec__", 37 | ]) 38 | -------------------------------------------------------------------------------- /src/tree_sitter/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_ALLOC_H_ 2 | #define TREE_SITTER_ALLOC_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | // Allow clients to override allocation functions 13 | #ifdef TREE_SITTER_REUSE_ALLOCATOR 14 | 15 | extern void *(*ts_current_malloc)(size_t size); 16 | extern void *(*ts_current_calloc)(size_t count, size_t size); 17 | extern void *(*ts_current_realloc)(void *ptr, size_t size); 18 | extern void (*ts_current_free)(void *ptr); 19 | 20 | #ifndef ts_malloc 21 | #define ts_malloc ts_current_malloc 22 | #endif 23 | #ifndef ts_calloc 24 | #define ts_calloc ts_current_calloc 25 | #endif 26 | #ifndef ts_realloc 27 | #define ts_realloc ts_current_realloc 28 | #endif 29 | #ifndef ts_free 30 | #define ts_free ts_current_free 31 | #endif 32 | 33 | #else 34 | 35 | #ifndef ts_malloc 36 | #define ts_malloc malloc 37 | #endif 38 | #ifndef ts_calloc 39 | #define ts_calloc calloc 40 | #endif 41 | #ifndef ts_realloc 42 | #define ts_realloc realloc 43 | #endif 44 | #ifndef ts_free 45 | #define ts_free free 46 | #endif 47 | 48 | #endif 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif // TREE_SITTER_ALLOC_H_ 55 | -------------------------------------------------------------------------------- /grammar.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Embedded Template grammar for tree-sitter 3 | * @author Max Brunsfeld 4 | * @license MIT 5 | */ 6 | 7 | /// 8 | // @ts-check 9 | 10 | module.exports = grammar({ 11 | name: 'embedded_template', 12 | 13 | extras: _ => [], 14 | 15 | rules: { 16 | template: $ => repeat(choice( 17 | $.directive, 18 | $.output_directive, 19 | $.comment_directive, 20 | $.graphql_directive, 21 | $.content, 22 | )), 23 | 24 | code: _ => repeat1(choice(/[^%=_-]+|[%=_-]/, '%%>')), 25 | 26 | content: _ => prec.right(repeat1(choice(/[^<]+| seq( 29 | choice('<%', '<%_', '<%|', '<%~'), 30 | optional($.code), 31 | choice('%>', '-%>', '_%>'), 32 | ), 33 | 34 | output_directive: $ => seq( 35 | choice('<%=', '<%==', '<%|=', '<%|==', '<%-', 'xyz'), 36 | optional($.code), 37 | choice('%>', '-%>', '=%>'), 38 | ), 39 | 40 | comment_directive: $ => seq( 41 | '<%#', 42 | optional(alias($.code, $.comment)), 43 | '%>', 44 | ), 45 | 46 | graphql_directive: $ => seq( 47 | '<%graphql', 48 | optional($.code), 49 | '%>', 50 | ), 51 | }, 52 | }); 53 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.3 2 | 3 | import Foundation 4 | import PackageDescription 5 | 6 | var sources = ["src/parser.c"] 7 | if FileManager.default.fileExists(atPath: "src/scanner.c") { 8 | sources.append("src/scanner.c") 9 | } 10 | 11 | let package = Package( 12 | name: "TreeSitterEmbeddedTemplate", 13 | products: [ 14 | .library(name: "TreeSitterEmbeddedTemplate", targets: ["TreeSitterEmbeddedTemplate"]), 15 | ], 16 | dependencies: [ 17 | .package(name: "SwiftTreeSitter", url: "https://github.com/tree-sitter/swift-tree-sitter", from: "0.9.0"), 18 | ], 19 | targets: [ 20 | .target( 21 | name: "TreeSitterEmbeddedTemplate", 22 | dependencies: [], 23 | path: ".", 24 | sources: sources, 25 | resources: [ 26 | .copy("queries") 27 | ], 28 | publicHeadersPath: "bindings/swift", 29 | cSettings: [.headerSearchPath("src")] 30 | ), 31 | .testTarget( 32 | name: "TreeSitterEmbeddedTemplateTests", 33 | dependencies: [ 34 | "SwiftTreeSitter", 35 | "TreeSitterEmbeddedTemplate", 36 | ], 37 | path: "bindings/swift/TreeSitterEmbeddedTemplateTests" 38 | ) 39 | ], 40 | cLanguageStandard: .c11 41 | ) 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tree-sitter-embedded-template", 3 | "version": "0.25.0", 4 | "description": "Embedded Template (ERB, EJS) grammar for tree-sitter", 5 | "repository": "https://github.com/tree-sitter/tree-sitter-embedded-template", 6 | "license": "MIT", 7 | "author": { 8 | "name": "Max Brunsfeld", 9 | "email": "maxbrunsfeld@gmail.com" 10 | }, 11 | "maintainers": [ 12 | { 13 | "name": "Amaan Qureshi", 14 | "email": "amaanq12@gmail.com" 15 | } 16 | ], 17 | "main": "bindings/node", 18 | "types": "bindings/node", 19 | "keywords": [ 20 | "incremental", 21 | "parsing", 22 | "tree-sitter", 23 | "embedded-template" 24 | ], 25 | "files": [ 26 | "grammar.js", 27 | "tree-sitter.json", 28 | "binding.gyp", 29 | "prebuilds/**", 30 | "bindings/node/*", 31 | "queries/*", 32 | "src/**", 33 | "*.wasm" 34 | ], 35 | "dependencies": { 36 | "node-addon-api": "^8.3.1", 37 | "node-gyp-build": "^4.8.4" 38 | }, 39 | "devDependencies": { 40 | "eslint": ">=9.14.0", 41 | "eslint-config-treesitter": "^1.0.2", 42 | "prebuildify": "^6.0.1", 43 | "tree-sitter-cli": "^0.25.8" 44 | }, 45 | "peerDependencies": { 46 | "tree-sitter": "^0.25.0" 47 | }, 48 | "peerDependenciesMeta": { 49 | "tree-sitter": { 50 | "optional": true 51 | } 52 | }, 53 | "scripts": { 54 | "install": "node-gyp-build", 55 | "lint": "eslint grammar.js", 56 | "prestart": "tree-sitter build --wasm", 57 | "start": "tree-sitter playground", 58 | "test": "node --test bindings/node/*_test.js" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tree-sitter-embedded-template 2 | 3 | [![CI][ci]](https://github.com/tree-sitter/tree-sitter-embedded-template/actions/workflows/ci.yml) 4 | [![discord][discord]](https://discord.gg/w7nTvsVJhm) 5 | [![matrix][matrix]](https://matrix.to/#/#tree-sitter-chat:matrix.org) 6 | [![crates][crates]](https://crates.io/crates/tree-sitter-embedded-template) 7 | [![npm][npm]](https://www.npmjs.com/package/tree-sitter-embedded-template) 8 | [![pypi][pypi]](https://pypi.org/project/tree-sitter-embedded-template) 9 | 10 | A [tree-sitter](https://github.com/tree-sitter/tree-sitter) parser for templating languages like [ERB](https://ruby-doc.org/stdlib-2.5.1/libdoc/erb/rdoc/ERB.html) and [EJS](http://ejs.co), in which scripting code can be embedded within text content using the delimiters `<%` and `%>`. 11 | 12 | References 13 | 14 | - [ERB Documentation](https://ruby-doc.org/stdlib-2.5.1/libdoc/erb/rdoc/ERB.html) 15 | - [EJS Documentation](http://ejs.co/#docs) 16 | - [ETLua Documentation](https://github.com/leafo/etlua) 17 | - [ETA Documentation](https://eta.js.org/docs) 18 | 19 | [ci]: https://img.shields.io/github/actions/workflow/status/tree-sitter/tree-sitter-embedded-template/ci.yml?logo=github&label=CI 20 | [discord]: https://img.shields.io/discord/1063097320771698699?logo=discord&label=discord 21 | [matrix]: https://img.shields.io/matrix/tree-sitter-chat%3Amatrix.org?logo=matrix&label=matrix 22 | [npm]: https://img.shields.io/npm/v/tree-sitter-embedded-template?logo=npm 23 | [crates]: https://img.shields.io/crates/v/tree-sitter-embedded-template?logo=rust 24 | [pypi]: https://img.shields.io/pypi/v/tree-sitter-embedded-template?logo=pypi&logoColor=ffd242 25 | -------------------------------------------------------------------------------- /tree-sitter.json: -------------------------------------------------------------------------------- 1 | { 2 | "grammars": [ 3 | { 4 | "name": "embedded-template", 5 | "camelcase": "EmbeddedTemplate", 6 | "scope": "text.html.ejs", 7 | "path": ".", 8 | "file-types": [ 9 | "ejs" 10 | ], 11 | "injections": "queries/injections-ejs.scm", 12 | "injection-regex": "ejs" 13 | }, 14 | { 15 | "name": "embedded-template", 16 | "camelcase": "EmbeddedTemplate", 17 | "scope": "text.html.erb", 18 | "path": ".", 19 | "file-types": [ 20 | "erb" 21 | ], 22 | "injections": "queries/injections-erb.scm", 23 | "injection-regex": "erb" 24 | }, 25 | { 26 | "name": "embedded-template", 27 | "camelcase": "EmbeddedTemplate", 28 | "scope": "text.html.etlua", 29 | "path": ".", 30 | "file-types": [ 31 | "etlua" 32 | ], 33 | "injections": "queries/injections-etlua.scm", 34 | "injection-regex": "etlua" 35 | } 36 | ], 37 | "metadata": { 38 | "version": "0.25.0", 39 | "license": "MIT", 40 | "description": "Embedded Template (ERB, EJS) grammar for tree-sitter", 41 | "authors": [ 42 | { 43 | "name": "Max Brunsfeld", 44 | "email": "maxbrunsfeld@gmail.com" 45 | }, 46 | { 47 | "name": "Amaan Qureshi", 48 | "email": "amaanq12@gmail.com" 49 | } 50 | ], 51 | "links": { 52 | "repository": "https://github.com/tree-sitter/tree-sitter-embedded-template" 53 | } 54 | }, 55 | "bindings": { 56 | "c": true, 57 | "go": true, 58 | "node": true, 59 | "python": true, 60 | "rust": true, 61 | "swift": true 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /bindings/rust/lib.rs: -------------------------------------------------------------------------------- 1 | //! This crate provides EmbeddedTemplate language support for the [tree-sitter] parsing library. 2 | //! 3 | //! Typically, you will use the [`LANGUAGE`] constant to add this language to a 4 | //! tree-sitter [`Parser`], and then use the parser to parse some code: 5 | //! 6 | //! ``` 7 | //! let code = r#" 8 | //! "#; 9 | //! let mut parser = tree_sitter::Parser::new(); 10 | //! let language = tree_sitter_embedded_template::LANGUAGE; 11 | //! parser 12 | //! .set_language(&language.into()) 13 | //! .expect("Error loading EmbeddedTemplate parser"); 14 | //! let tree = parser.parse(code, None).unwrap(); 15 | //! assert!(!tree.root_node().has_error()); 16 | //! ``` 17 | //! 18 | //! [`Parser`]: https://docs.rs/tree-sitter/0.25.8/tree_sitter/struct.Parser.html 19 | //! [tree-sitter]: https://tree-sitter.github.io/ 20 | 21 | use tree_sitter_language::LanguageFn; 22 | 23 | extern "C" { 24 | fn tree_sitter_embedded_template() -> *const (); 25 | } 26 | 27 | /// The tree-sitter [`LanguageFn`] for this grammar. 28 | pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_embedded_template) }; 29 | 30 | /// The content of the [`node-types.json`] file for this grammar. 31 | /// 32 | /// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types 33 | pub const NODE_TYPES: &str = include_str!("../../src/node-types.json"); 34 | 35 | /// The syntax highlighting query for this grammar. 36 | pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); 37 | 38 | /// The injections query for this grammar to inject HTML/JavaScript. 39 | pub const INJECTIONS_EJS_QUERY: &str = include_str!("../../queries/injections-ejs.scm"); 40 | 41 | /// The injections query for this grammar to inject HTML/Ruby. 42 | pub const INJECTIONS_ERB_QUERY: &str = include_str!("../../queries/injections-erb.scm"); 43 | 44 | #[cfg(test)] 45 | mod tests { 46 | #[test] 47 | fn test_can_load_grammar() { 48 | let mut parser = tree_sitter::Parser::new(); 49 | parser 50 | .set_language(&super::LANGUAGE.into()) 51 | .expect("Error loading EmbeddedTemplate parser"); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from os import path 2 | from platform import system 3 | from sysconfig import get_config_var 4 | 5 | from setuptools import Extension, find_packages, setup 6 | from setuptools.command.build import build 7 | from setuptools.command.egg_info import egg_info 8 | from wheel.bdist_wheel import bdist_wheel 9 | 10 | sources = [ 11 | "bindings/python/tree_sitter_embedded_template/binding.c", 12 | "src/parser.c", 13 | ] 14 | if path.exists("src/scanner.c"): 15 | sources.append("src/scanner.c") 16 | 17 | macros: list[tuple[str, str | None]] = [ 18 | ("PY_SSIZE_T_CLEAN", None), 19 | ("TREE_SITTER_HIDE_SYMBOLS", None), 20 | ] 21 | if limited_api := not get_config_var("Py_GIL_DISABLED"): 22 | macros.append(("Py_LIMITED_API", "0x030A0000")) 23 | 24 | if system() != "Windows": 25 | cflags = ["-std=c11", "-fvisibility=hidden"] 26 | else: 27 | cflags = ["/std:c11", "/utf-8"] 28 | 29 | 30 | class Build(build): 31 | def run(self): 32 | if path.isdir("queries"): 33 | dest = path.join(self.build_lib, "tree_sitter_embedded_template", "queries") 34 | self.copy_tree("queries", dest) 35 | super().run() 36 | 37 | 38 | class BdistWheel(bdist_wheel): 39 | def get_tag(self): 40 | python, abi, platform = super().get_tag() 41 | if python.startswith("cp"): 42 | python, abi = "cp310", "abi3" 43 | return python, abi, platform 44 | 45 | 46 | class EggInfo(egg_info): 47 | def find_sources(self): 48 | super().find_sources() 49 | self.filelist.recursive_include("queries", "*.scm") 50 | self.filelist.include("src/tree_sitter/*.h") 51 | 52 | 53 | setup( 54 | packages=find_packages("bindings/python"), 55 | package_dir={"": "bindings/python"}, 56 | package_data={ 57 | "tree_sitter_embedded_template": ["*.pyi", "py.typed"], 58 | "tree_sitter_embedded_template.queries": ["*.scm"], 59 | }, 60 | ext_package="tree_sitter_embedded_template", 61 | ext_modules=[ 62 | Extension( 63 | name="_binding", 64 | sources=sources, 65 | extra_compile_args=cflags, 66 | define_macros=macros, 67 | include_dirs=["src"], 68 | py_limited_api=limited_api, 69 | ) 70 | ], 71 | cmdclass={ 72 | "build": Build, 73 | "bdist_wheel": BdistWheel, 74 | "egg_info": EggInfo, 75 | }, 76 | zip_safe=False, 77 | ) 78 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.13) 2 | 3 | project(tree-sitter-embedded-template 4 | VERSION "0.25.0" 5 | DESCRIPTION "Embedded Template (ERB, EJS) grammar for tree-sitter" 6 | HOMEPAGE_URL "https://github.com/tree-sitter/tree-sitter-embedded-template" 7 | LANGUAGES C) 8 | 9 | option(BUILD_SHARED_LIBS "Build using shared libraries" ON) 10 | option(TREE_SITTER_REUSE_ALLOCATOR "Reuse the library allocator" OFF) 11 | 12 | set(TREE_SITTER_ABI_VERSION 15 CACHE STRING "Tree-sitter ABI version") 13 | if(NOT ${TREE_SITTER_ABI_VERSION} MATCHES "^[0-9]+$") 14 | unset(TREE_SITTER_ABI_VERSION CACHE) 15 | message(FATAL_ERROR "TREE_SITTER_ABI_VERSION must be an integer") 16 | endif() 17 | 18 | include(GNUInstallDirs) 19 | 20 | find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI") 21 | 22 | add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c" 23 | DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json" 24 | COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json 25 | --abi=${TREE_SITTER_ABI_VERSION} 26 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 27 | COMMENT "Generating parser.c") 28 | 29 | add_library(tree-sitter-embedded-template src/parser.c) 30 | if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/scanner.c) 31 | target_sources(tree-sitter-embedded-template PRIVATE src/scanner.c) 32 | endif() 33 | target_include_directories(tree-sitter-embedded-template 34 | PRIVATE src 35 | INTERFACE $ 36 | $) 37 | 38 | target_compile_definitions(tree-sitter-embedded-template PRIVATE 39 | $<$:TREE_SITTER_REUSE_ALLOCATOR> 40 | $<$:TREE_SITTER_DEBUG>) 41 | 42 | set_target_properties(tree-sitter-embedded-template 43 | PROPERTIES 44 | C_STANDARD 11 45 | POSITION_INDEPENDENT_CODE ON 46 | SOVERSION "${TREE_SITTER_ABI_VERSION}.${PROJECT_VERSION_MAJOR}" 47 | DEFINE_SYMBOL "") 48 | 49 | configure_file(bindings/c/tree-sitter-embedded-template.pc.in 50 | "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-embedded-template.pc" @ONLY) 51 | 52 | install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bindings/c/tree_sitter" 53 | DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" 54 | FILES_MATCHING PATTERN "*.h") 55 | install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-embedded-template.pc" 56 | DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") 57 | install(TARGETS tree-sitter-embedded-template 58 | LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") 59 | 60 | file(GLOB QUERIES queries/*.scm) 61 | install(FILES ${QUERIES} 62 | DESTINATION "${CMAKE_INSTALL_DATADIR}/tree-sitter/queries/embedded-template") 63 | 64 | add_custom_target(ts-test "${TREE_SITTER_CLI}" test 65 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" 66 | COMMENT "tree-sitter test") 67 | -------------------------------------------------------------------------------- /test/corpus/main.txt: -------------------------------------------------------------------------------- 1 | ==================== 2 | Directives 3 | ==================== 4 | 5 |
6 | <% names.each do |name| _%> 7 |
8 | <%= name -%> 9 | <%== x %> 10 | <%|= x %> 11 | <%== x %> 12 | <%| end %> 13 | <%~ end %> 14 |
15 | 16 | <% something() -%> 17 | 18 | <%_ end %> 19 |
20 | 21 | --- 22 | 23 | (template 24 | (content) 25 | (directive (code)) 26 | (content) 27 | (output_directive (code)) 28 | (content) 29 | (output_directive (code)) 30 | (content) 31 | (output_directive (code)) 32 | (content) 33 | (output_directive (code)) 34 | (content) 35 | (directive (code)) 36 | (content) 37 | (directive (code)) 38 | (content) 39 | (directive (code)) 40 | (content) 41 | (directive (code)) 42 | (content)) 43 | 44 | =============================== 45 | Escaped directive start strings 46 | =============================== 47 | 48 | This "<%%" is not a directive 49 | 50 | --- 51 | 52 | (template (content)) 53 | 54 | =============================== 55 | Comment directives 56 | =============================== 57 | 58 | <%# a comment %> 59 | 60 | --- 61 | 62 | (template 63 | (content) 64 | (comment_directive (comment)) 65 | (content)) 66 | 67 | =============================== 68 | Underscores in code 69 | =============================== 70 | 71 |
72 | <% page_info :selected_link %> 73 |
74 | 75 | --- 76 | 77 | (template 78 | (content) 79 | (directive (code)) 80 | (content)) 81 | 82 | =============================== 83 | Empty directive 84 | =============================== 85 | 86 | <% %> 87 | <%= "hello" %> 88 | 89 | --- 90 | 91 | (template 92 | (content) 93 | (directive (code)) 94 | (content) 95 | (output_directive (code)) 96 | (content) 97 | ) 98 | 99 | =============================== 100 | Empty comment 101 | =============================== 102 | 103 | <%#%> 104 | 105 | --- 106 | 107 | (template 108 | (content) 109 | (comment_directive) 110 | (content)) 111 | 112 | =============================== 113 | Empty directives 114 | =============================== 115 | 116 | <%%> 117 | <% %> 118 | <%-%> 119 | <% -%> 120 | <%_ %> 121 | <%_%> 122 | <%_-%> 123 | <%__%> 124 | <%=%> 125 | <%=-%> 126 | <%==%> 127 | <%-%> 128 | <%--%> 129 | <%-=%> 130 | <%#%> 131 | <%graphql%> 132 | <%|%> 133 | <%|=%> 134 | <%|==%> 135 | <%~%> 136 | --- 137 | 138 | (template 139 | (content) 140 | (directive (code)) 141 | (content) 142 | (output_directive) 143 | (content) 144 | (directive (code)) 145 | (content) 146 | (directive (code)) 147 | (content) 148 | (directive) 149 | (content) 150 | (directive) 151 | (content) 152 | (directive) 153 | (content) 154 | (output_directive) 155 | (content) 156 | (output_directive) 157 | (content) 158 | (output_directive) 159 | (content) 160 | (output_directive) 161 | (content) 162 | (output_directive) 163 | (content) 164 | (output_directive) 165 | (content) 166 | (comment_directive) 167 | (content) 168 | (graphql_directive) 169 | (content) 170 | (directive) 171 | (content) 172 | (output_directive) 173 | (content) 174 | (output_directive) 175 | (content) 176 | (directive) 177 | ) 178 | -------------------------------------------------------------------------------- /src/node-types.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "type": "code", 4 | "named": true, 5 | "fields": {} 6 | }, 7 | { 8 | "type": "comment", 9 | "named": true, 10 | "fields": {} 11 | }, 12 | { 13 | "type": "comment_directive", 14 | "named": true, 15 | "fields": {}, 16 | "children": { 17 | "multiple": false, 18 | "required": false, 19 | "types": [ 20 | { 21 | "type": "comment", 22 | "named": true 23 | } 24 | ] 25 | } 26 | }, 27 | { 28 | "type": "content", 29 | "named": true, 30 | "fields": {} 31 | }, 32 | { 33 | "type": "directive", 34 | "named": true, 35 | "fields": {}, 36 | "children": { 37 | "multiple": false, 38 | "required": false, 39 | "types": [ 40 | { 41 | "type": "code", 42 | "named": true 43 | } 44 | ] 45 | } 46 | }, 47 | { 48 | "type": "graphql_directive", 49 | "named": true, 50 | "fields": {}, 51 | "children": { 52 | "multiple": false, 53 | "required": false, 54 | "types": [ 55 | { 56 | "type": "code", 57 | "named": true 58 | } 59 | ] 60 | } 61 | }, 62 | { 63 | "type": "output_directive", 64 | "named": true, 65 | "fields": {}, 66 | "children": { 67 | "multiple": false, 68 | "required": false, 69 | "types": [ 70 | { 71 | "type": "code", 72 | "named": true 73 | } 74 | ] 75 | } 76 | }, 77 | { 78 | "type": "template", 79 | "named": true, 80 | "root": true, 81 | "fields": {}, 82 | "children": { 83 | "multiple": true, 84 | "required": false, 85 | "types": [ 86 | { 87 | "type": "comment_directive", 88 | "named": true 89 | }, 90 | { 91 | "type": "content", 92 | "named": true 93 | }, 94 | { 95 | "type": "directive", 96 | "named": true 97 | }, 98 | { 99 | "type": "graphql_directive", 100 | "named": true 101 | }, 102 | { 103 | "type": "output_directive", 104 | "named": true 105 | } 106 | ] 107 | } 108 | }, 109 | { 110 | "type": "%%>", 111 | "named": false 112 | }, 113 | { 114 | "type": "%>", 115 | "named": false 116 | }, 117 | { 118 | "type": "-%>", 119 | "named": false 120 | }, 121 | { 122 | "type": "<%", 123 | "named": false 124 | }, 125 | { 126 | "type": "<%#", 127 | "named": false 128 | }, 129 | { 130 | "type": "<%%", 131 | "named": false 132 | }, 133 | { 134 | "type": "<%-", 135 | "named": false 136 | }, 137 | { 138 | "type": "<%=", 139 | "named": false 140 | }, 141 | { 142 | "type": "<%==", 143 | "named": false 144 | }, 145 | { 146 | "type": "<%_", 147 | "named": false 148 | }, 149 | { 150 | "type": "<%graphql", 151 | "named": false 152 | }, 153 | { 154 | "type": "<%|", 155 | "named": false 156 | }, 157 | { 158 | "type": "<%|=", 159 | "named": false 160 | }, 161 | { 162 | "type": "<%|==", 163 | "named": false 164 | }, 165 | { 166 | "type": "<%~", 167 | "named": false 168 | }, 169 | { 170 | "type": "=%>", 171 | "named": false 172 | }, 173 | { 174 | "type": "_%>", 175 | "named": false 176 | }, 177 | { 178 | "type": "xyz", 179 | "named": false 180 | } 181 | ] -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 2 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/mattn/go-pointer v0.0.1 h1:n+XhsuGeVO6MEAp7xyEukFINEa+Quek5psIR/ylA6o0= 4 | github.com/mattn/go-pointer v0.0.1/go.mod h1:2zXcozF6qYGgmsG+SeTZz3oAbFLdD3OWqnUbNvJZAlc= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 8 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 9 | github.com/tree-sitter/go-tree-sitter v0.24.0 h1:kRZb6aBNfcI/u0Qh8XEt3zjNVnmxTisDBN+kXK0xRYQ= 10 | github.com/tree-sitter/go-tree-sitter v0.24.0/go.mod h1:x681iFVoLMEwOSIHA1chaLkXlroXEN7WY+VHGFaoDbk= 11 | github.com/tree-sitter/tree-sitter-c v0.21.5-0.20240818205408-927da1f210eb h1:A8425heRM8mylnv4H58FPUiH+aYivyitre0PzxrfmWs= 12 | github.com/tree-sitter/tree-sitter-c v0.21.5-0.20240818205408-927da1f210eb/go.mod h1:dOF6gtQiF9UwNh995T5OphYmtIypkjsp3ap7r9AN/iA= 13 | github.com/tree-sitter/tree-sitter-cpp v0.22.4-0.20240818224355-b1a4e2b25148 h1:AfFPZwtwGN01BW1jDdqBVqscTwetvMpydqYZz57RSlc= 14 | github.com/tree-sitter/tree-sitter-cpp v0.22.4-0.20240818224355-b1a4e2b25148/go.mod h1:Bh6U3viD57rFXRYIQ+kmiYtr+1Bx0AceypDLJJSyi9s= 15 | github.com/tree-sitter/tree-sitter-go v0.21.3-0.20240818010209-8c0f0e7a6012 h1:Xvxck3tE5FW7F7bTS97iNM2ADMyCMJztVqn5HYKdJGo= 16 | github.com/tree-sitter/tree-sitter-go v0.21.3-0.20240818010209-8c0f0e7a6012/go.mod h1:T40D0O1cPvUU/+AmiXVXy1cncYQT6wem4Z0g4SfAYvY= 17 | github.com/tree-sitter/tree-sitter-html v0.20.5-0.20240818004741-d11201a263d0 h1:c46K6uh5Dz00zJeU9BfjXdb8I+E4RkUdfnWJpQADXFo= 18 | github.com/tree-sitter/tree-sitter-html v0.20.5-0.20240818004741-d11201a263d0/go.mod h1:hcNt/kOJHcIcuMvouE7LJcYdeFUFbVpBJ6d4wmOA+tU= 19 | github.com/tree-sitter/tree-sitter-java v0.21.1-0.20240824015150-576d8097e495 h1:jrt4qbJVEFs4H93/ITxygHc6u0TGqAkkate7TQ4wFSA= 20 | github.com/tree-sitter/tree-sitter-java v0.21.1-0.20240824015150-576d8097e495/go.mod h1:oyaR7fLnRV0hT9z6qwE9GkaeTom/hTDwK3H2idcOJFc= 21 | github.com/tree-sitter/tree-sitter-javascript v0.21.5-0.20240818005344-15887341e5b5 h1:om4X9AVg3asL8gxNJDcz4e/Wp+VpQj1PY3uJXKr6EOg= 22 | github.com/tree-sitter/tree-sitter-javascript v0.21.5-0.20240818005344-15887341e5b5/go.mod h1:nNqgPoV/h9uYWk6kYEFdEAhNVOacpfpRW5SFmdaP4tU= 23 | github.com/tree-sitter/tree-sitter-json v0.21.1-0.20240818005659-bdd69eb8c8a5 h1:pfV3G3k7NCKqKk8THBmyuh2zA33lgYHS3GVrzRR8ry4= 24 | github.com/tree-sitter/tree-sitter-json v0.21.1-0.20240818005659-bdd69eb8c8a5/go.mod h1:GbMKRjLfk0H+PI7nLi1Sx5lHf5wCpLz9al8tQYSxpEk= 25 | github.com/tree-sitter/tree-sitter-php v0.22.9-0.20240819002312-a552625b56c1 h1:ZXZMDwE+IhUtGug4Brv6NjJWUU3rfkZBKpemf6RY8/g= 26 | github.com/tree-sitter/tree-sitter-php v0.22.9-0.20240819002312-a552625b56c1/go.mod h1:UKCLuYnJ312Mei+3cyTmGOHzn0YAnaPRECgJmHtzrqs= 27 | github.com/tree-sitter/tree-sitter-python v0.21.1-0.20240818005537-55a9b8a4fbfb h1:EXEM82lFM7JjJb6qiKZXkpIDaCcbV2obNn82ghwj9lw= 28 | github.com/tree-sitter/tree-sitter-python v0.21.1-0.20240818005537-55a9b8a4fbfb/go.mod h1:lXCF1nGG5Dr4J3BTS0ObN4xJCCICiSu/b+Xe/VqMV7g= 29 | github.com/tree-sitter/tree-sitter-ruby v0.21.1-0.20240818211811-7dbc1e2d0e2d h1:fcYCvoXdcP1uRQYXqJHRy6Hec+uKScQdKVtMwK9JeCI= 30 | github.com/tree-sitter/tree-sitter-ruby v0.21.1-0.20240818211811-7dbc1e2d0e2d/go.mod h1:T1nShQ4v5AJtozZ8YyAS4uzUtDAJj/iv4YfwXSbUHzg= 31 | github.com/tree-sitter/tree-sitter-rust v0.21.3-0.20240818005432-2b43eafe6447 h1:o9alBu1J/WjrcTKEthYtXmdkDc5OVXD+PqlvnEZ0Lzc= 32 | github.com/tree-sitter/tree-sitter-rust v0.21.3-0.20240818005432-2b43eafe6447/go.mod h1:1Oh95COkkTn6Ezp0vcMbvfhRP5gLeqqljR0BYnBzWvc= 33 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 34 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | ifeq ($(OS),Windows_NT) 2 | $(error Windows is not supported) 3 | endif 4 | 5 | LANGUAGE_NAME := tree-sitter-embedded-template 6 | HOMEPAGE_URL := https://github.com/tree-sitter/tree-sitter-embedded-template 7 | VERSION := 0.25.0 8 | 9 | # repository 10 | SRC_DIR := src 11 | 12 | TS ?= tree-sitter 13 | 14 | # install directory layout 15 | PREFIX ?= /usr/local 16 | DATADIR ?= $(PREFIX)/share 17 | INCLUDEDIR ?= $(PREFIX)/include 18 | LIBDIR ?= $(PREFIX)/lib 19 | PCLIBDIR ?= $(LIBDIR)/pkgconfig 20 | 21 | # source/object files 22 | PARSER := $(SRC_DIR)/parser.c 23 | EXTRAS := $(filter-out $(PARSER),$(wildcard $(SRC_DIR)/*.c)) 24 | OBJS := $(patsubst %.c,%.o,$(PARSER) $(EXTRAS)) 25 | 26 | # flags 27 | ARFLAGS ?= rcs 28 | override CFLAGS += -I$(SRC_DIR) -std=c11 -fPIC 29 | 30 | # ABI versioning 31 | SONAME_MAJOR = $(shell sed -n 's/\#define LANGUAGE_VERSION //p' $(PARSER)) 32 | SONAME_MINOR = $(word 1,$(subst ., ,$(VERSION))) 33 | 34 | # OS-specific bits 35 | ifeq ($(shell uname),Darwin) 36 | SOEXT = dylib 37 | SOEXTVER_MAJOR = $(SONAME_MAJOR).$(SOEXT) 38 | SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).$(SOEXT) 39 | LINKSHARED = -dynamiclib -Wl,-install_name,$(LIBDIR)/lib$(LANGUAGE_NAME).$(SOEXTVER),-rpath,@executable_path/../Frameworks 40 | else 41 | SOEXT = so 42 | SOEXTVER_MAJOR = $(SOEXT).$(SONAME_MAJOR) 43 | SOEXTVER = $(SOEXT).$(SONAME_MAJOR).$(SONAME_MINOR) 44 | LINKSHARED = -shared -Wl,-soname,lib$(LANGUAGE_NAME).$(SOEXTVER) 45 | endif 46 | ifneq ($(filter $(shell uname),FreeBSD NetBSD DragonFly),) 47 | PCLIBDIR := $(PREFIX)/libdata/pkgconfig 48 | endif 49 | 50 | all: lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) $(LANGUAGE_NAME).pc 51 | 52 | lib$(LANGUAGE_NAME).a: $(OBJS) 53 | $(AR) $(ARFLAGS) $@ $^ 54 | 55 | lib$(LANGUAGE_NAME).$(SOEXT): $(OBJS) 56 | $(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@ 57 | ifneq ($(STRIP),) 58 | $(STRIP) $@ 59 | endif 60 | 61 | $(LANGUAGE_NAME).pc: bindings/c/$(LANGUAGE_NAME).pc.in 62 | sed -e 's|@PROJECT_VERSION@|$(VERSION)|' \ 63 | -e 's|@CMAKE_INSTALL_LIBDIR@|$(LIBDIR:$(PREFIX)/%=%)|' \ 64 | -e 's|@CMAKE_INSTALL_INCLUDEDIR@|$(INCLUDEDIR:$(PREFIX)/%=%)|' \ 65 | -e 's|@PROJECT_DESCRIPTION@|$(DESCRIPTION)|' \ 66 | -e 's|@PROJECT_HOMEPAGE_URL@|$(HOMEPAGE_URL)|' \ 67 | -e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|' $< > $@ 68 | 69 | $(PARSER): $(SRC_DIR)/grammar.json 70 | $(TS) generate $^ 71 | 72 | install: all 73 | install -d '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/embedded-template '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)' 74 | install -m644 bindings/c/tree_sitter/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h 75 | install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc 76 | install -m644 lib$(LANGUAGE_NAME).a '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a 77 | install -m755 lib$(LANGUAGE_NAME).$(SOEXT) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) 78 | ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) 79 | ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) 80 | ifneq ($(wildcard queries/*.scm),) 81 | install -m644 queries/*.scm '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/embedded-template 82 | endif 83 | 84 | uninstall: 85 | $(RM) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a \ 86 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) \ 87 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) \ 88 | '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) \ 89 | '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h \ 90 | '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc 91 | $(RM) -r '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/embedded-template 92 | 93 | clean: 94 | $(RM) $(OBJS) $(LANGUAGE_NAME).pc lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) 95 | 96 | test: 97 | $(TS) test 98 | 99 | .PHONY: all install uninstall clean test 100 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "aho-corasick" 7 | version = "1.1.3" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 10 | dependencies = [ 11 | "memchr", 12 | ] 13 | 14 | [[package]] 15 | name = "cc" 16 | version = "1.2.34" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" 19 | dependencies = [ 20 | "shlex", 21 | ] 22 | 23 | [[package]] 24 | name = "equivalent" 25 | version = "1.0.2" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 28 | 29 | [[package]] 30 | name = "hashbrown" 31 | version = "0.15.5" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 34 | 35 | [[package]] 36 | name = "indexmap" 37 | version = "2.11.0" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" 40 | dependencies = [ 41 | "equivalent", 42 | "hashbrown", 43 | ] 44 | 45 | [[package]] 46 | name = "itoa" 47 | version = "1.0.15" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 50 | 51 | [[package]] 52 | name = "memchr" 53 | version = "2.7.5" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" 56 | 57 | [[package]] 58 | name = "proc-macro2" 59 | version = "1.0.95" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" 62 | dependencies = [ 63 | "unicode-ident", 64 | ] 65 | 66 | [[package]] 67 | name = "quote" 68 | version = "1.0.40" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 71 | dependencies = [ 72 | "proc-macro2", 73 | ] 74 | 75 | [[package]] 76 | name = "regex" 77 | version = "1.11.2" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" 80 | dependencies = [ 81 | "aho-corasick", 82 | "memchr", 83 | "regex-automata", 84 | "regex-syntax", 85 | ] 86 | 87 | [[package]] 88 | name = "regex-automata" 89 | version = "0.4.9" 90 | source = "registry+https://github.com/rust-lang/crates.io-index" 91 | checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" 92 | dependencies = [ 93 | "aho-corasick", 94 | "memchr", 95 | "regex-syntax", 96 | ] 97 | 98 | [[package]] 99 | name = "regex-syntax" 100 | version = "0.8.6" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" 103 | 104 | [[package]] 105 | name = "ryu" 106 | version = "1.0.20" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 109 | 110 | [[package]] 111 | name = "serde" 112 | version = "1.0.219" 113 | source = "registry+https://github.com/rust-lang/crates.io-index" 114 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 115 | dependencies = [ 116 | "serde_derive", 117 | ] 118 | 119 | [[package]] 120 | name = "serde_derive" 121 | version = "1.0.219" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 124 | dependencies = [ 125 | "proc-macro2", 126 | "quote", 127 | "syn", 128 | ] 129 | 130 | [[package]] 131 | name = "serde_json" 132 | version = "1.0.143" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" 135 | dependencies = [ 136 | "indexmap", 137 | "itoa", 138 | "memchr", 139 | "ryu", 140 | "serde", 141 | ] 142 | 143 | [[package]] 144 | name = "shlex" 145 | version = "1.3.0" 146 | source = "registry+https://github.com/rust-lang/crates.io-index" 147 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 148 | 149 | [[package]] 150 | name = "streaming-iterator" 151 | version = "0.1.9" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "2b2231b7c3057d5e4ad0156fb3dc807d900806020c5ffa3ee6ff2c8c76fb8520" 154 | 155 | [[package]] 156 | name = "syn" 157 | version = "2.0.104" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" 160 | dependencies = [ 161 | "proc-macro2", 162 | "quote", 163 | "unicode-ident", 164 | ] 165 | 166 | [[package]] 167 | name = "tree-sitter" 168 | version = "0.25.8" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "6d7b8994f367f16e6fa14b5aebbcb350de5d7cbea82dc5b00ae997dd71680dd2" 171 | dependencies = [ 172 | "cc", 173 | "regex", 174 | "regex-syntax", 175 | "serde_json", 176 | "streaming-iterator", 177 | "tree-sitter-language", 178 | ] 179 | 180 | [[package]] 181 | name = "tree-sitter-embedded-template" 182 | version = "0.25.0" 183 | dependencies = [ 184 | "cc", 185 | "tree-sitter", 186 | "tree-sitter-language", 187 | ] 188 | 189 | [[package]] 190 | name = "tree-sitter-language" 191 | version = "0.1.5" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "c4013970217383f67b18aef68f6fb2e8d409bc5755227092d32efb0422ba24b8" 194 | 195 | [[package]] 196 | name = "unicode-ident" 197 | version = "1.0.18" 198 | source = "registry+https://github.com/rust-lang/crates.io-index" 199 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 200 | -------------------------------------------------------------------------------- /src/grammar.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://tree-sitter.github.io/tree-sitter/assets/schemas/grammar.schema.json", 3 | "name": "embedded_template", 4 | "rules": { 5 | "template": { 6 | "type": "REPEAT", 7 | "content": { 8 | "type": "CHOICE", 9 | "members": [ 10 | { 11 | "type": "SYMBOL", 12 | "name": "directive" 13 | }, 14 | { 15 | "type": "SYMBOL", 16 | "name": "output_directive" 17 | }, 18 | { 19 | "type": "SYMBOL", 20 | "name": "comment_directive" 21 | }, 22 | { 23 | "type": "SYMBOL", 24 | "name": "graphql_directive" 25 | }, 26 | { 27 | "type": "SYMBOL", 28 | "name": "content" 29 | } 30 | ] 31 | } 32 | }, 33 | "code": { 34 | "type": "REPEAT1", 35 | "content": { 36 | "type": "CHOICE", 37 | "members": [ 38 | { 39 | "type": "PATTERN", 40 | "value": "[^%=_-]+|[%=_-]" 41 | }, 42 | { 43 | "type": "STRING", 44 | "value": "%%>" 45 | } 46 | ] 47 | } 48 | }, 49 | "content": { 50 | "type": "PREC_RIGHT", 51 | "value": 0, 52 | "content": { 53 | "type": "REPEAT1", 54 | "content": { 55 | "type": "CHOICE", 56 | "members": [ 57 | { 58 | "type": "PATTERN", 59 | "value": "[^<]+|<" 60 | }, 61 | { 62 | "type": "STRING", 63 | "value": "<%%" 64 | } 65 | ] 66 | } 67 | } 68 | }, 69 | "directive": { 70 | "type": "SEQ", 71 | "members": [ 72 | { 73 | "type": "CHOICE", 74 | "members": [ 75 | { 76 | "type": "STRING", 77 | "value": "<%" 78 | }, 79 | { 80 | "type": "STRING", 81 | "value": "<%_" 82 | }, 83 | { 84 | "type": "STRING", 85 | "value": "<%|" 86 | }, 87 | { 88 | "type": "STRING", 89 | "value": "<%~" 90 | } 91 | ] 92 | }, 93 | { 94 | "type": "CHOICE", 95 | "members": [ 96 | { 97 | "type": "SYMBOL", 98 | "name": "code" 99 | }, 100 | { 101 | "type": "BLANK" 102 | } 103 | ] 104 | }, 105 | { 106 | "type": "CHOICE", 107 | "members": [ 108 | { 109 | "type": "STRING", 110 | "value": "%>" 111 | }, 112 | { 113 | "type": "STRING", 114 | "value": "-%>" 115 | }, 116 | { 117 | "type": "STRING", 118 | "value": "_%>" 119 | } 120 | ] 121 | } 122 | ] 123 | }, 124 | "output_directive": { 125 | "type": "SEQ", 126 | "members": [ 127 | { 128 | "type": "CHOICE", 129 | "members": [ 130 | { 131 | "type": "STRING", 132 | "value": "<%=" 133 | }, 134 | { 135 | "type": "STRING", 136 | "value": "<%==" 137 | }, 138 | { 139 | "type": "STRING", 140 | "value": "<%|=" 141 | }, 142 | { 143 | "type": "STRING", 144 | "value": "<%|==" 145 | }, 146 | { 147 | "type": "STRING", 148 | "value": "<%-" 149 | }, 150 | { 151 | "type": "STRING", 152 | "value": "xyz" 153 | } 154 | ] 155 | }, 156 | { 157 | "type": "CHOICE", 158 | "members": [ 159 | { 160 | "type": "SYMBOL", 161 | "name": "code" 162 | }, 163 | { 164 | "type": "BLANK" 165 | } 166 | ] 167 | }, 168 | { 169 | "type": "CHOICE", 170 | "members": [ 171 | { 172 | "type": "STRING", 173 | "value": "%>" 174 | }, 175 | { 176 | "type": "STRING", 177 | "value": "-%>" 178 | }, 179 | { 180 | "type": "STRING", 181 | "value": "=%>" 182 | } 183 | ] 184 | } 185 | ] 186 | }, 187 | "comment_directive": { 188 | "type": "SEQ", 189 | "members": [ 190 | { 191 | "type": "STRING", 192 | "value": "<%#" 193 | }, 194 | { 195 | "type": "CHOICE", 196 | "members": [ 197 | { 198 | "type": "ALIAS", 199 | "content": { 200 | "type": "SYMBOL", 201 | "name": "code" 202 | }, 203 | "named": true, 204 | "value": "comment" 205 | }, 206 | { 207 | "type": "BLANK" 208 | } 209 | ] 210 | }, 211 | { 212 | "type": "STRING", 213 | "value": "%>" 214 | } 215 | ] 216 | }, 217 | "graphql_directive": { 218 | "type": "SEQ", 219 | "members": [ 220 | { 221 | "type": "STRING", 222 | "value": "<%graphql" 223 | }, 224 | { 225 | "type": "CHOICE", 226 | "members": [ 227 | { 228 | "type": "SYMBOL", 229 | "name": "code" 230 | }, 231 | { 232 | "type": "BLANK" 233 | } 234 | ] 235 | }, 236 | { 237 | "type": "STRING", 238 | "value": "%>" 239 | } 240 | ] 241 | } 242 | }, 243 | "extras": [], 244 | "conflicts": [], 245 | "precedences": [], 246 | "externals": [], 247 | "inline": [], 248 | "supertypes": [], 249 | "reserved": {} 250 | } -------------------------------------------------------------------------------- /src/tree_sitter/parser.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_PARSER_H_ 2 | #define TREE_SITTER_PARSER_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #define ts_builtin_sym_error ((TSSymbol)-1) 13 | #define ts_builtin_sym_end 0 14 | #define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024 15 | 16 | #ifndef TREE_SITTER_API_H_ 17 | typedef uint16_t TSStateId; 18 | typedef uint16_t TSSymbol; 19 | typedef uint16_t TSFieldId; 20 | typedef struct TSLanguage TSLanguage; 21 | typedef struct TSLanguageMetadata { 22 | uint8_t major_version; 23 | uint8_t minor_version; 24 | uint8_t patch_version; 25 | } TSLanguageMetadata; 26 | #endif 27 | 28 | typedef struct { 29 | TSFieldId field_id; 30 | uint8_t child_index; 31 | bool inherited; 32 | } TSFieldMapEntry; 33 | 34 | // Used to index the field and supertype maps. 35 | typedef struct { 36 | uint16_t index; 37 | uint16_t length; 38 | } TSMapSlice; 39 | 40 | typedef struct { 41 | bool visible; 42 | bool named; 43 | bool supertype; 44 | } TSSymbolMetadata; 45 | 46 | typedef struct TSLexer TSLexer; 47 | 48 | struct TSLexer { 49 | int32_t lookahead; 50 | TSSymbol result_symbol; 51 | void (*advance)(TSLexer *, bool); 52 | void (*mark_end)(TSLexer *); 53 | uint32_t (*get_column)(TSLexer *); 54 | bool (*is_at_included_range_start)(const TSLexer *); 55 | bool (*eof)(const TSLexer *); 56 | void (*log)(const TSLexer *, const char *, ...); 57 | }; 58 | 59 | typedef enum { 60 | TSParseActionTypeShift, 61 | TSParseActionTypeReduce, 62 | TSParseActionTypeAccept, 63 | TSParseActionTypeRecover, 64 | } TSParseActionType; 65 | 66 | typedef union { 67 | struct { 68 | uint8_t type; 69 | TSStateId state; 70 | bool extra; 71 | bool repetition; 72 | } shift; 73 | struct { 74 | uint8_t type; 75 | uint8_t child_count; 76 | TSSymbol symbol; 77 | int16_t dynamic_precedence; 78 | uint16_t production_id; 79 | } reduce; 80 | uint8_t type; 81 | } TSParseAction; 82 | 83 | typedef struct { 84 | uint16_t lex_state; 85 | uint16_t external_lex_state; 86 | } TSLexMode; 87 | 88 | typedef struct { 89 | uint16_t lex_state; 90 | uint16_t external_lex_state; 91 | uint16_t reserved_word_set_id; 92 | } TSLexerMode; 93 | 94 | typedef union { 95 | TSParseAction action; 96 | struct { 97 | uint8_t count; 98 | bool reusable; 99 | } entry; 100 | } TSParseActionEntry; 101 | 102 | typedef struct { 103 | int32_t start; 104 | int32_t end; 105 | } TSCharacterRange; 106 | 107 | struct TSLanguage { 108 | uint32_t abi_version; 109 | uint32_t symbol_count; 110 | uint32_t alias_count; 111 | uint32_t token_count; 112 | uint32_t external_token_count; 113 | uint32_t state_count; 114 | uint32_t large_state_count; 115 | uint32_t production_id_count; 116 | uint32_t field_count; 117 | uint16_t max_alias_sequence_length; 118 | const uint16_t *parse_table; 119 | const uint16_t *small_parse_table; 120 | const uint32_t *small_parse_table_map; 121 | const TSParseActionEntry *parse_actions; 122 | const char * const *symbol_names; 123 | const char * const *field_names; 124 | const TSMapSlice *field_map_slices; 125 | const TSFieldMapEntry *field_map_entries; 126 | const TSSymbolMetadata *symbol_metadata; 127 | const TSSymbol *public_symbol_map; 128 | const uint16_t *alias_map; 129 | const TSSymbol *alias_sequences; 130 | const TSLexerMode *lex_modes; 131 | bool (*lex_fn)(TSLexer *, TSStateId); 132 | bool (*keyword_lex_fn)(TSLexer *, TSStateId); 133 | TSSymbol keyword_capture_token; 134 | struct { 135 | const bool *states; 136 | const TSSymbol *symbol_map; 137 | void *(*create)(void); 138 | void (*destroy)(void *); 139 | bool (*scan)(void *, TSLexer *, const bool *symbol_whitelist); 140 | unsigned (*serialize)(void *, char *); 141 | void (*deserialize)(void *, const char *, unsigned); 142 | } external_scanner; 143 | const TSStateId *primary_state_ids; 144 | const char *name; 145 | const TSSymbol *reserved_words; 146 | uint16_t max_reserved_word_set_size; 147 | uint32_t supertype_count; 148 | const TSSymbol *supertype_symbols; 149 | const TSMapSlice *supertype_map_slices; 150 | const TSSymbol *supertype_map_entries; 151 | TSLanguageMetadata metadata; 152 | }; 153 | 154 | static inline bool set_contains(const TSCharacterRange *ranges, uint32_t len, int32_t lookahead) { 155 | uint32_t index = 0; 156 | uint32_t size = len - index; 157 | while (size > 1) { 158 | uint32_t half_size = size / 2; 159 | uint32_t mid_index = index + half_size; 160 | const TSCharacterRange *range = &ranges[mid_index]; 161 | if (lookahead >= range->start && lookahead <= range->end) { 162 | return true; 163 | } else if (lookahead > range->end) { 164 | index = mid_index; 165 | } 166 | size -= half_size; 167 | } 168 | const TSCharacterRange *range = &ranges[index]; 169 | return (lookahead >= range->start && lookahead <= range->end); 170 | } 171 | 172 | /* 173 | * Lexer Macros 174 | */ 175 | 176 | #ifdef _MSC_VER 177 | #define UNUSED __pragma(warning(suppress : 4101)) 178 | #else 179 | #define UNUSED __attribute__((unused)) 180 | #endif 181 | 182 | #define START_LEXER() \ 183 | bool result = false; \ 184 | bool skip = false; \ 185 | UNUSED \ 186 | bool eof = false; \ 187 | int32_t lookahead; \ 188 | goto start; \ 189 | next_state: \ 190 | lexer->advance(lexer, skip); \ 191 | start: \ 192 | skip = false; \ 193 | lookahead = lexer->lookahead; 194 | 195 | #define ADVANCE(state_value) \ 196 | { \ 197 | state = state_value; \ 198 | goto next_state; \ 199 | } 200 | 201 | #define ADVANCE_MAP(...) \ 202 | { \ 203 | static const uint16_t map[] = { __VA_ARGS__ }; \ 204 | for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \ 205 | if (map[i] == lookahead) { \ 206 | state = map[i + 1]; \ 207 | goto next_state; \ 208 | } \ 209 | } \ 210 | } 211 | 212 | #define SKIP(state_value) \ 213 | { \ 214 | skip = true; \ 215 | state = state_value; \ 216 | goto next_state; \ 217 | } 218 | 219 | #define ACCEPT_TOKEN(symbol_value) \ 220 | result = true; \ 221 | lexer->result_symbol = symbol_value; \ 222 | lexer->mark_end(lexer); 223 | 224 | #define END_STATE() return result; 225 | 226 | /* 227 | * Parse Table Macros 228 | */ 229 | 230 | #define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT) 231 | 232 | #define STATE(id) id 233 | 234 | #define ACTIONS(id) id 235 | 236 | #define SHIFT(state_value) \ 237 | {{ \ 238 | .shift = { \ 239 | .type = TSParseActionTypeShift, \ 240 | .state = (state_value) \ 241 | } \ 242 | }} 243 | 244 | #define SHIFT_REPEAT(state_value) \ 245 | {{ \ 246 | .shift = { \ 247 | .type = TSParseActionTypeShift, \ 248 | .state = (state_value), \ 249 | .repetition = true \ 250 | } \ 251 | }} 252 | 253 | #define SHIFT_EXTRA() \ 254 | {{ \ 255 | .shift = { \ 256 | .type = TSParseActionTypeShift, \ 257 | .extra = true \ 258 | } \ 259 | }} 260 | 261 | #define REDUCE(symbol_name, children, precedence, prod_id) \ 262 | {{ \ 263 | .reduce = { \ 264 | .type = TSParseActionTypeReduce, \ 265 | .symbol = symbol_name, \ 266 | .child_count = children, \ 267 | .dynamic_precedence = precedence, \ 268 | .production_id = prod_id \ 269 | }, \ 270 | }} 271 | 272 | #define RECOVER() \ 273 | {{ \ 274 | .type = TSParseActionTypeRecover \ 275 | }} 276 | 277 | #define ACCEPT_INPUT() \ 278 | {{ \ 279 | .type = TSParseActionTypeAccept \ 280 | }} 281 | 282 | #ifdef __cplusplus 283 | } 284 | #endif 285 | 286 | #endif // TREE_SITTER_PARSER_H_ 287 | -------------------------------------------------------------------------------- /src/tree_sitter/array.h: -------------------------------------------------------------------------------- 1 | #ifndef TREE_SITTER_ARRAY_H_ 2 | #define TREE_SITTER_ARRAY_H_ 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #include "./alloc.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #ifdef _MSC_VER 17 | #pragma warning(push) 18 | #pragma warning(disable : 4101) 19 | #elif defined(__GNUC__) || defined(__clang__) 20 | #pragma GCC diagnostic push 21 | #pragma GCC diagnostic ignored "-Wunused-variable" 22 | #endif 23 | 24 | #define Array(T) \ 25 | struct { \ 26 | T *contents; \ 27 | uint32_t size; \ 28 | uint32_t capacity; \ 29 | } 30 | 31 | /// Initialize an array. 32 | #define array_init(self) \ 33 | ((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL) 34 | 35 | /// Create an empty array. 36 | #define array_new() \ 37 | { NULL, 0, 0 } 38 | 39 | /// Get a pointer to the element at a given `index` in the array. 40 | #define array_get(self, _index) \ 41 | (assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index]) 42 | 43 | /// Get a pointer to the first element in the array. 44 | #define array_front(self) array_get(self, 0) 45 | 46 | /// Get a pointer to the last element in the array. 47 | #define array_back(self) array_get(self, (self)->size - 1) 48 | 49 | /// Clear the array, setting its size to zero. Note that this does not free any 50 | /// memory allocated for the array's contents. 51 | #define array_clear(self) ((self)->size = 0) 52 | 53 | /// Reserve `new_capacity` elements of space in the array. If `new_capacity` is 54 | /// less than the array's current capacity, this function has no effect. 55 | #define array_reserve(self, new_capacity) \ 56 | _array__reserve((Array *)(self), array_elem_size(self), new_capacity) 57 | 58 | /// Free any memory allocated for this array. Note that this does not free any 59 | /// memory allocated for the array's contents. 60 | #define array_delete(self) _array__delete((Array *)(self)) 61 | 62 | /// Push a new `element` onto the end of the array. 63 | #define array_push(self, element) \ 64 | (_array__grow((Array *)(self), 1, array_elem_size(self)), \ 65 | (self)->contents[(self)->size++] = (element)) 66 | 67 | /// Increase the array's size by `count` elements. 68 | /// New elements are zero-initialized. 69 | #define array_grow_by(self, count) \ 70 | do { \ 71 | if ((count) == 0) break; \ 72 | _array__grow((Array *)(self), count, array_elem_size(self)); \ 73 | memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \ 74 | (self)->size += (count); \ 75 | } while (0) 76 | 77 | /// Append all elements from one array to the end of another. 78 | #define array_push_all(self, other) \ 79 | array_extend((self), (other)->size, (other)->contents) 80 | 81 | /// Append `count` elements to the end of the array, reading their values from the 82 | /// `contents` pointer. 83 | #define array_extend(self, count, contents) \ 84 | _array__splice( \ 85 | (Array *)(self), array_elem_size(self), (self)->size, \ 86 | 0, count, contents \ 87 | ) 88 | 89 | /// Remove `old_count` elements from the array starting at the given `index`. At 90 | /// the same index, insert `new_count` new elements, reading their values from the 91 | /// `new_contents` pointer. 92 | #define array_splice(self, _index, old_count, new_count, new_contents) \ 93 | _array__splice( \ 94 | (Array *)(self), array_elem_size(self), _index, \ 95 | old_count, new_count, new_contents \ 96 | ) 97 | 98 | /// Insert one `element` into the array at the given `index`. 99 | #define array_insert(self, _index, element) \ 100 | _array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element)) 101 | 102 | /// Remove one element from the array at the given `index`. 103 | #define array_erase(self, _index) \ 104 | _array__erase((Array *)(self), array_elem_size(self), _index) 105 | 106 | /// Pop the last element off the array, returning the element by value. 107 | #define array_pop(self) ((self)->contents[--(self)->size]) 108 | 109 | /// Assign the contents of one array to another, reallocating if necessary. 110 | #define array_assign(self, other) \ 111 | _array__assign((Array *)(self), (const Array *)(other), array_elem_size(self)) 112 | 113 | /// Swap one array with another 114 | #define array_swap(self, other) \ 115 | _array__swap((Array *)(self), (Array *)(other)) 116 | 117 | /// Get the size of the array contents 118 | #define array_elem_size(self) (sizeof *(self)->contents) 119 | 120 | /// Search a sorted array for a given `needle` value, using the given `compare` 121 | /// callback to determine the order. 122 | /// 123 | /// If an existing element is found to be equal to `needle`, then the `index` 124 | /// out-parameter is set to the existing value's index, and the `exists` 125 | /// out-parameter is set to true. Otherwise, `index` is set to an index where 126 | /// `needle` should be inserted in order to preserve the sorting, and `exists` 127 | /// is set to false. 128 | #define array_search_sorted_with(self, compare, needle, _index, _exists) \ 129 | _array__search_sorted(self, 0, compare, , needle, _index, _exists) 130 | 131 | /// Search a sorted array for a given `needle` value, using integer comparisons 132 | /// of a given struct field (specified with a leading dot) to determine the order. 133 | /// 134 | /// See also `array_search_sorted_with`. 135 | #define array_search_sorted_by(self, field, needle, _index, _exists) \ 136 | _array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists) 137 | 138 | /// Insert a given `value` into a sorted array, using the given `compare` 139 | /// callback to determine the order. 140 | #define array_insert_sorted_with(self, compare, value) \ 141 | do { \ 142 | unsigned _index, _exists; \ 143 | array_search_sorted_with(self, compare, &(value), &_index, &_exists); \ 144 | if (!_exists) array_insert(self, _index, value); \ 145 | } while (0) 146 | 147 | /// Insert a given `value` into a sorted array, using integer comparisons of 148 | /// a given struct field (specified with a leading dot) to determine the order. 149 | /// 150 | /// See also `array_search_sorted_by`. 151 | #define array_insert_sorted_by(self, field, value) \ 152 | do { \ 153 | unsigned _index, _exists; \ 154 | array_search_sorted_by(self, field, (value) field, &_index, &_exists); \ 155 | if (!_exists) array_insert(self, _index, value); \ 156 | } while (0) 157 | 158 | // Private 159 | 160 | typedef Array(void) Array; 161 | 162 | /// This is not what you're looking for, see `array_delete`. 163 | static inline void _array__delete(Array *self) { 164 | if (self->contents) { 165 | ts_free(self->contents); 166 | self->contents = NULL; 167 | self->size = 0; 168 | self->capacity = 0; 169 | } 170 | } 171 | 172 | /// This is not what you're looking for, see `array_erase`. 173 | static inline void _array__erase(Array *self, size_t element_size, 174 | uint32_t index) { 175 | assert(index < self->size); 176 | char *contents = (char *)self->contents; 177 | memmove(contents + index * element_size, contents + (index + 1) * element_size, 178 | (self->size - index - 1) * element_size); 179 | self->size--; 180 | } 181 | 182 | /// This is not what you're looking for, see `array_reserve`. 183 | static inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) { 184 | if (new_capacity > self->capacity) { 185 | if (self->contents) { 186 | self->contents = ts_realloc(self->contents, new_capacity * element_size); 187 | } else { 188 | self->contents = ts_malloc(new_capacity * element_size); 189 | } 190 | self->capacity = new_capacity; 191 | } 192 | } 193 | 194 | /// This is not what you're looking for, see `array_assign`. 195 | static inline void _array__assign(Array *self, const Array *other, size_t element_size) { 196 | _array__reserve(self, element_size, other->size); 197 | self->size = other->size; 198 | memcpy(self->contents, other->contents, self->size * element_size); 199 | } 200 | 201 | /// This is not what you're looking for, see `array_swap`. 202 | static inline void _array__swap(Array *self, Array *other) { 203 | Array swap = *other; 204 | *other = *self; 205 | *self = swap; 206 | } 207 | 208 | /// This is not what you're looking for, see `array_push` or `array_grow_by`. 209 | static inline void _array__grow(Array *self, uint32_t count, size_t element_size) { 210 | uint32_t new_size = self->size + count; 211 | if (new_size > self->capacity) { 212 | uint32_t new_capacity = self->capacity * 2; 213 | if (new_capacity < 8) new_capacity = 8; 214 | if (new_capacity < new_size) new_capacity = new_size; 215 | _array__reserve(self, element_size, new_capacity); 216 | } 217 | } 218 | 219 | /// This is not what you're looking for, see `array_splice`. 220 | static inline void _array__splice(Array *self, size_t element_size, 221 | uint32_t index, uint32_t old_count, 222 | uint32_t new_count, const void *elements) { 223 | uint32_t new_size = self->size + new_count - old_count; 224 | uint32_t old_end = index + old_count; 225 | uint32_t new_end = index + new_count; 226 | assert(old_end <= self->size); 227 | 228 | _array__reserve(self, element_size, new_size); 229 | 230 | char *contents = (char *)self->contents; 231 | if (self->size > old_end) { 232 | memmove( 233 | contents + new_end * element_size, 234 | contents + old_end * element_size, 235 | (self->size - old_end) * element_size 236 | ); 237 | } 238 | if (new_count > 0) { 239 | if (elements) { 240 | memcpy( 241 | (contents + index * element_size), 242 | elements, 243 | new_count * element_size 244 | ); 245 | } else { 246 | memset( 247 | (contents + index * element_size), 248 | 0, 249 | new_count * element_size 250 | ); 251 | } 252 | } 253 | self->size += new_count - old_count; 254 | } 255 | 256 | /// A binary search routine, based on Rust's `std::slice::binary_search_by`. 257 | /// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`. 258 | #define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \ 259 | do { \ 260 | *(_index) = start; \ 261 | *(_exists) = false; \ 262 | uint32_t size = (self)->size - *(_index); \ 263 | if (size == 0) break; \ 264 | int comparison; \ 265 | while (size > 1) { \ 266 | uint32_t half_size = size / 2; \ 267 | uint32_t mid_index = *(_index) + half_size; \ 268 | comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \ 269 | if (comparison <= 0) *(_index) = mid_index; \ 270 | size -= half_size; \ 271 | } \ 272 | comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \ 273 | if (comparison == 0) *(_exists) = true; \ 274 | else if (comparison < 0) *(_index) += 1; \ 275 | } while (0) 276 | 277 | /// Helper macro for the `_sorted_by` routines below. This takes the left (existing) 278 | /// parameter by reference in order to work with the generic sorting function above. 279 | #define _compare_int(a, b) ((int)*(a) - (int)(b)) 280 | 281 | #ifdef _MSC_VER 282 | #pragma warning(pop) 283 | #elif defined(__GNUC__) || defined(__clang__) 284 | #pragma GCC diagnostic pop 285 | #endif 286 | 287 | #ifdef __cplusplus 288 | } 289 | #endif 290 | 291 | #endif // TREE_SITTER_ARRAY_H_ 292 | -------------------------------------------------------------------------------- /src/parser.c: -------------------------------------------------------------------------------- 1 | /* Automatically @generated by tree-sitter v0.25.8 */ 2 | 3 | #include "tree_sitter/parser.h" 4 | 5 | #if defined(__GNUC__) || defined(__clang__) 6 | #pragma GCC diagnostic ignored "-Wmissing-field-initializers" 7 | #endif 8 | 9 | #define LANGUAGE_VERSION 15 10 | #define STATE_COUNT 29 11 | #define LARGE_STATE_COUNT 6 12 | #define SYMBOL_COUNT 31 13 | #define ALIAS_COUNT 1 14 | #define TOKEN_COUNT 21 15 | #define EXTERNAL_TOKEN_COUNT 0 16 | #define FIELD_COUNT 0 17 | #define MAX_ALIAS_SEQUENCE_LENGTH 3 18 | #define MAX_RESERVED_WORD_SET_SIZE 0 19 | #define PRODUCTION_ID_COUNT 2 20 | #define SUPERTYPE_COUNT 0 21 | 22 | enum ts_symbol_identifiers { 23 | aux_sym_code_token1 = 1, 24 | anon_sym_PERCENT_PERCENT_GT = 2, 25 | aux_sym_content_token1 = 3, 26 | anon_sym_LT_PERCENT_PERCENT = 4, 27 | anon_sym_LT_PERCENT = 5, 28 | anon_sym_LT_PERCENT_ = 6, 29 | anon_sym_LT_PERCENT_PIPE = 7, 30 | anon_sym_LT_PERCENT_TILDE = 8, 31 | anon_sym_PERCENT_GT = 9, 32 | anon_sym_DASH_PERCENT_GT = 10, 33 | anon_sym__PERCENT_GT = 11, 34 | anon_sym_LT_PERCENT_EQ = 12, 35 | anon_sym_LT_PERCENT_EQ_EQ = 13, 36 | anon_sym_LT_PERCENT_PIPE_EQ = 14, 37 | anon_sym_LT_PERCENT_PIPE_EQ_EQ = 15, 38 | anon_sym_LT_PERCENT_DASH = 16, 39 | anon_sym_xyz = 17, 40 | anon_sym_EQ_PERCENT_GT = 18, 41 | anon_sym_LT_PERCENT_POUND = 19, 42 | anon_sym_LT_PERCENTgraphql = 20, 43 | sym_template = 21, 44 | sym_code = 22, 45 | sym_content = 23, 46 | sym_directive = 24, 47 | sym_output_directive = 25, 48 | sym_comment_directive = 26, 49 | sym_graphql_directive = 27, 50 | aux_sym_template_repeat1 = 28, 51 | aux_sym_code_repeat1 = 29, 52 | aux_sym_content_repeat1 = 30, 53 | alias_sym_comment = 31, 54 | }; 55 | 56 | static const char * const ts_symbol_names[] = { 57 | [ts_builtin_sym_end] = "end", 58 | [aux_sym_code_token1] = "code_token1", 59 | [anon_sym_PERCENT_PERCENT_GT] = "%%>", 60 | [aux_sym_content_token1] = "content_token1", 61 | [anon_sym_LT_PERCENT_PERCENT] = "<%%", 62 | [anon_sym_LT_PERCENT] = "<%", 63 | [anon_sym_LT_PERCENT_] = "<%_", 64 | [anon_sym_LT_PERCENT_PIPE] = "<%|", 65 | [anon_sym_LT_PERCENT_TILDE] = "<%~", 66 | [anon_sym_PERCENT_GT] = "%>", 67 | [anon_sym_DASH_PERCENT_GT] = "-%>", 68 | [anon_sym__PERCENT_GT] = "_%>", 69 | [anon_sym_LT_PERCENT_EQ] = "<%=", 70 | [anon_sym_LT_PERCENT_EQ_EQ] = "<%==", 71 | [anon_sym_LT_PERCENT_PIPE_EQ] = "<%|=", 72 | [anon_sym_LT_PERCENT_PIPE_EQ_EQ] = "<%|==", 73 | [anon_sym_LT_PERCENT_DASH] = "<%-", 74 | [anon_sym_xyz] = "xyz", 75 | [anon_sym_EQ_PERCENT_GT] = "=%>", 76 | [anon_sym_LT_PERCENT_POUND] = "<%#", 77 | [anon_sym_LT_PERCENTgraphql] = "<%graphql", 78 | [sym_template] = "template", 79 | [sym_code] = "code", 80 | [sym_content] = "content", 81 | [sym_directive] = "directive", 82 | [sym_output_directive] = "output_directive", 83 | [sym_comment_directive] = "comment_directive", 84 | [sym_graphql_directive] = "graphql_directive", 85 | [aux_sym_template_repeat1] = "template_repeat1", 86 | [aux_sym_code_repeat1] = "code_repeat1", 87 | [aux_sym_content_repeat1] = "content_repeat1", 88 | [alias_sym_comment] = "comment", 89 | }; 90 | 91 | static const TSSymbol ts_symbol_map[] = { 92 | [ts_builtin_sym_end] = ts_builtin_sym_end, 93 | [aux_sym_code_token1] = aux_sym_code_token1, 94 | [anon_sym_PERCENT_PERCENT_GT] = anon_sym_PERCENT_PERCENT_GT, 95 | [aux_sym_content_token1] = aux_sym_content_token1, 96 | [anon_sym_LT_PERCENT_PERCENT] = anon_sym_LT_PERCENT_PERCENT, 97 | [anon_sym_LT_PERCENT] = anon_sym_LT_PERCENT, 98 | [anon_sym_LT_PERCENT_] = anon_sym_LT_PERCENT_, 99 | [anon_sym_LT_PERCENT_PIPE] = anon_sym_LT_PERCENT_PIPE, 100 | [anon_sym_LT_PERCENT_TILDE] = anon_sym_LT_PERCENT_TILDE, 101 | [anon_sym_PERCENT_GT] = anon_sym_PERCENT_GT, 102 | [anon_sym_DASH_PERCENT_GT] = anon_sym_DASH_PERCENT_GT, 103 | [anon_sym__PERCENT_GT] = anon_sym__PERCENT_GT, 104 | [anon_sym_LT_PERCENT_EQ] = anon_sym_LT_PERCENT_EQ, 105 | [anon_sym_LT_PERCENT_EQ_EQ] = anon_sym_LT_PERCENT_EQ_EQ, 106 | [anon_sym_LT_PERCENT_PIPE_EQ] = anon_sym_LT_PERCENT_PIPE_EQ, 107 | [anon_sym_LT_PERCENT_PIPE_EQ_EQ] = anon_sym_LT_PERCENT_PIPE_EQ_EQ, 108 | [anon_sym_LT_PERCENT_DASH] = anon_sym_LT_PERCENT_DASH, 109 | [anon_sym_xyz] = anon_sym_xyz, 110 | [anon_sym_EQ_PERCENT_GT] = anon_sym_EQ_PERCENT_GT, 111 | [anon_sym_LT_PERCENT_POUND] = anon_sym_LT_PERCENT_POUND, 112 | [anon_sym_LT_PERCENTgraphql] = anon_sym_LT_PERCENTgraphql, 113 | [sym_template] = sym_template, 114 | [sym_code] = sym_code, 115 | [sym_content] = sym_content, 116 | [sym_directive] = sym_directive, 117 | [sym_output_directive] = sym_output_directive, 118 | [sym_comment_directive] = sym_comment_directive, 119 | [sym_graphql_directive] = sym_graphql_directive, 120 | [aux_sym_template_repeat1] = aux_sym_template_repeat1, 121 | [aux_sym_code_repeat1] = aux_sym_code_repeat1, 122 | [aux_sym_content_repeat1] = aux_sym_content_repeat1, 123 | [alias_sym_comment] = alias_sym_comment, 124 | }; 125 | 126 | static const TSSymbolMetadata ts_symbol_metadata[] = { 127 | [ts_builtin_sym_end] = { 128 | .visible = false, 129 | .named = true, 130 | }, 131 | [aux_sym_code_token1] = { 132 | .visible = false, 133 | .named = false, 134 | }, 135 | [anon_sym_PERCENT_PERCENT_GT] = { 136 | .visible = true, 137 | .named = false, 138 | }, 139 | [aux_sym_content_token1] = { 140 | .visible = false, 141 | .named = false, 142 | }, 143 | [anon_sym_LT_PERCENT_PERCENT] = { 144 | .visible = true, 145 | .named = false, 146 | }, 147 | [anon_sym_LT_PERCENT] = { 148 | .visible = true, 149 | .named = false, 150 | }, 151 | [anon_sym_LT_PERCENT_] = { 152 | .visible = true, 153 | .named = false, 154 | }, 155 | [anon_sym_LT_PERCENT_PIPE] = { 156 | .visible = true, 157 | .named = false, 158 | }, 159 | [anon_sym_LT_PERCENT_TILDE] = { 160 | .visible = true, 161 | .named = false, 162 | }, 163 | [anon_sym_PERCENT_GT] = { 164 | .visible = true, 165 | .named = false, 166 | }, 167 | [anon_sym_DASH_PERCENT_GT] = { 168 | .visible = true, 169 | .named = false, 170 | }, 171 | [anon_sym__PERCENT_GT] = { 172 | .visible = true, 173 | .named = false, 174 | }, 175 | [anon_sym_LT_PERCENT_EQ] = { 176 | .visible = true, 177 | .named = false, 178 | }, 179 | [anon_sym_LT_PERCENT_EQ_EQ] = { 180 | .visible = true, 181 | .named = false, 182 | }, 183 | [anon_sym_LT_PERCENT_PIPE_EQ] = { 184 | .visible = true, 185 | .named = false, 186 | }, 187 | [anon_sym_LT_PERCENT_PIPE_EQ_EQ] = { 188 | .visible = true, 189 | .named = false, 190 | }, 191 | [anon_sym_LT_PERCENT_DASH] = { 192 | .visible = true, 193 | .named = false, 194 | }, 195 | [anon_sym_xyz] = { 196 | .visible = true, 197 | .named = false, 198 | }, 199 | [anon_sym_EQ_PERCENT_GT] = { 200 | .visible = true, 201 | .named = false, 202 | }, 203 | [anon_sym_LT_PERCENT_POUND] = { 204 | .visible = true, 205 | .named = false, 206 | }, 207 | [anon_sym_LT_PERCENTgraphql] = { 208 | .visible = true, 209 | .named = false, 210 | }, 211 | [sym_template] = { 212 | .visible = true, 213 | .named = true, 214 | }, 215 | [sym_code] = { 216 | .visible = true, 217 | .named = true, 218 | }, 219 | [sym_content] = { 220 | .visible = true, 221 | .named = true, 222 | }, 223 | [sym_directive] = { 224 | .visible = true, 225 | .named = true, 226 | }, 227 | [sym_output_directive] = { 228 | .visible = true, 229 | .named = true, 230 | }, 231 | [sym_comment_directive] = { 232 | .visible = true, 233 | .named = true, 234 | }, 235 | [sym_graphql_directive] = { 236 | .visible = true, 237 | .named = true, 238 | }, 239 | [aux_sym_template_repeat1] = { 240 | .visible = false, 241 | .named = false, 242 | }, 243 | [aux_sym_code_repeat1] = { 244 | .visible = false, 245 | .named = false, 246 | }, 247 | [aux_sym_content_repeat1] = { 248 | .visible = false, 249 | .named = false, 250 | }, 251 | [alias_sym_comment] = { 252 | .visible = true, 253 | .named = true, 254 | }, 255 | }; 256 | 257 | static const TSSymbol ts_alias_sequences[PRODUCTION_ID_COUNT][MAX_ALIAS_SEQUENCE_LENGTH] = { 258 | [0] = {0}, 259 | [1] = { 260 | [1] = alias_sym_comment, 261 | }, 262 | }; 263 | 264 | static const uint16_t ts_non_terminal_alias_map[] = { 265 | sym_code, 2, 266 | sym_code, 267 | alias_sym_comment, 268 | 0, 269 | }; 270 | 271 | static const TSStateId ts_primary_state_ids[STATE_COUNT] = { 272 | [0] = 0, 273 | [1] = 1, 274 | [2] = 2, 275 | [3] = 3, 276 | [4] = 4, 277 | [5] = 5, 278 | [6] = 6, 279 | [7] = 7, 280 | [8] = 8, 281 | [9] = 9, 282 | [10] = 10, 283 | [11] = 11, 284 | [12] = 12, 285 | [13] = 13, 286 | [14] = 14, 287 | [15] = 15, 288 | [16] = 16, 289 | [17] = 17, 290 | [18] = 17, 291 | [19] = 16, 292 | [20] = 20, 293 | [21] = 21, 294 | [22] = 16, 295 | [23] = 17, 296 | [24] = 24, 297 | [25] = 25, 298 | [26] = 26, 299 | [27] = 27, 300 | [28] = 28, 301 | }; 302 | 303 | static bool ts_lex(TSLexer *lexer, TSStateId state) { 304 | START_LEXER(); 305 | eof = lexer->eof(lexer); 306 | switch (state) { 307 | case 0: 308 | if (eof) ADVANCE(22); 309 | if (lookahead == '%') ADVANCE(1); 310 | if (lookahead == '-') ADVANCE(6); 311 | if (lookahead == '<') ADVANCE(2); 312 | if (lookahead == '=') ADVANCE(7); 313 | if (lookahead == '_') ADVANCE(8); 314 | if (lookahead == 'x') ADVANCE(19); 315 | END_STATE(); 316 | case 1: 317 | if (lookahead == '%') ADVANCE(9); 318 | if (lookahead == '>') ADVANCE(39); 319 | END_STATE(); 320 | case 2: 321 | if (lookahead == '%') ADVANCE(35); 322 | END_STATE(); 323 | case 3: 324 | if (lookahead == '%') ADVANCE(24); 325 | if (lookahead == '-') ADVANCE(25); 326 | if (lookahead == '=') ADVANCE(23); 327 | if (lookahead == '_') ADVANCE(27); 328 | if (lookahead != 0) ADVANCE(28); 329 | END_STATE(); 330 | case 4: 331 | if (lookahead == '%') ADVANCE(24); 332 | if (lookahead == '-') ADVANCE(25); 333 | if (lookahead == '=') ADVANCE(26); 334 | if (lookahead == '_') ADVANCE(23); 335 | if (lookahead != 0) ADVANCE(28); 336 | END_STATE(); 337 | case 5: 338 | if (lookahead == '%') ADVANCE(24); 339 | if (lookahead == '-' || 340 | lookahead == '=' || 341 | lookahead == '_') ADVANCE(23); 342 | if (lookahead != 0) ADVANCE(28); 343 | END_STATE(); 344 | case 6: 345 | if (lookahead == '%') ADVANCE(10); 346 | END_STATE(); 347 | case 7: 348 | if (lookahead == '%') ADVANCE(11); 349 | END_STATE(); 350 | case 8: 351 | if (lookahead == '%') ADVANCE(12); 352 | END_STATE(); 353 | case 9: 354 | if (lookahead == '>') ADVANCE(29); 355 | END_STATE(); 356 | case 10: 357 | if (lookahead == '>') ADVANCE(40); 358 | END_STATE(); 359 | case 11: 360 | if (lookahead == '>') ADVANCE(49); 361 | END_STATE(); 362 | case 12: 363 | if (lookahead == '>') ADVANCE(41); 364 | END_STATE(); 365 | case 13: 366 | if (lookahead == 'a') ADVANCE(16); 367 | END_STATE(); 368 | case 14: 369 | if (lookahead == 'h') ADVANCE(17); 370 | END_STATE(); 371 | case 15: 372 | if (lookahead == 'l') ADVANCE(51); 373 | END_STATE(); 374 | case 16: 375 | if (lookahead == 'p') ADVANCE(14); 376 | END_STATE(); 377 | case 17: 378 | if (lookahead == 'q') ADVANCE(15); 379 | END_STATE(); 380 | case 18: 381 | if (lookahead == 'r') ADVANCE(13); 382 | END_STATE(); 383 | case 19: 384 | if (lookahead == 'y') ADVANCE(20); 385 | END_STATE(); 386 | case 20: 387 | if (lookahead == 'z') ADVANCE(47); 388 | END_STATE(); 389 | case 21: 390 | if (eof) ADVANCE(22); 391 | if (lookahead == '<') ADVANCE(30); 392 | if (lookahead == 'x') ADVANCE(31); 393 | if (lookahead != 0) ADVANCE(33); 394 | END_STATE(); 395 | case 22: 396 | ACCEPT_TOKEN(ts_builtin_sym_end); 397 | END_STATE(); 398 | case 23: 399 | ACCEPT_TOKEN(aux_sym_code_token1); 400 | END_STATE(); 401 | case 24: 402 | ACCEPT_TOKEN(aux_sym_code_token1); 403 | if (lookahead == '%') ADVANCE(9); 404 | if (lookahead == '>') ADVANCE(39); 405 | END_STATE(); 406 | case 25: 407 | ACCEPT_TOKEN(aux_sym_code_token1); 408 | if (lookahead == '%') ADVANCE(10); 409 | END_STATE(); 410 | case 26: 411 | ACCEPT_TOKEN(aux_sym_code_token1); 412 | if (lookahead == '%') ADVANCE(11); 413 | END_STATE(); 414 | case 27: 415 | ACCEPT_TOKEN(aux_sym_code_token1); 416 | if (lookahead == '%') ADVANCE(12); 417 | END_STATE(); 418 | case 28: 419 | ACCEPT_TOKEN(aux_sym_code_token1); 420 | if (lookahead != 0 && 421 | lookahead != '%' && 422 | lookahead != '-' && 423 | lookahead != '=' && 424 | lookahead != '_') ADVANCE(28); 425 | END_STATE(); 426 | case 29: 427 | ACCEPT_TOKEN(anon_sym_PERCENT_PERCENT_GT); 428 | END_STATE(); 429 | case 30: 430 | ACCEPT_TOKEN(aux_sym_content_token1); 431 | if (lookahead == '%') ADVANCE(35); 432 | END_STATE(); 433 | case 31: 434 | ACCEPT_TOKEN(aux_sym_content_token1); 435 | if (lookahead == 'y') ADVANCE(32); 436 | if (lookahead != 0 && 437 | lookahead != '<') ADVANCE(33); 438 | END_STATE(); 439 | case 32: 440 | ACCEPT_TOKEN(aux_sym_content_token1); 441 | if (lookahead == 'z') ADVANCE(48); 442 | if (lookahead != 0 && 443 | lookahead != '<') ADVANCE(33); 444 | END_STATE(); 445 | case 33: 446 | ACCEPT_TOKEN(aux_sym_content_token1); 447 | if (lookahead != 0 && 448 | lookahead != '<') ADVANCE(33); 449 | END_STATE(); 450 | case 34: 451 | ACCEPT_TOKEN(anon_sym_LT_PERCENT_PERCENT); 452 | END_STATE(); 453 | case 35: 454 | ACCEPT_TOKEN(anon_sym_LT_PERCENT); 455 | ADVANCE_MAP( 456 | '#', 50, 457 | '%', 34, 458 | '-', 46, 459 | '=', 42, 460 | '_', 36, 461 | 'g', 18, 462 | '|', 37, 463 | '~', 38, 464 | ); 465 | END_STATE(); 466 | case 36: 467 | ACCEPT_TOKEN(anon_sym_LT_PERCENT_); 468 | END_STATE(); 469 | case 37: 470 | ACCEPT_TOKEN(anon_sym_LT_PERCENT_PIPE); 471 | if (lookahead == '=') ADVANCE(44); 472 | END_STATE(); 473 | case 38: 474 | ACCEPT_TOKEN(anon_sym_LT_PERCENT_TILDE); 475 | END_STATE(); 476 | case 39: 477 | ACCEPT_TOKEN(anon_sym_PERCENT_GT); 478 | END_STATE(); 479 | case 40: 480 | ACCEPT_TOKEN(anon_sym_DASH_PERCENT_GT); 481 | END_STATE(); 482 | case 41: 483 | ACCEPT_TOKEN(anon_sym__PERCENT_GT); 484 | END_STATE(); 485 | case 42: 486 | ACCEPT_TOKEN(anon_sym_LT_PERCENT_EQ); 487 | if (lookahead == '=') ADVANCE(43); 488 | END_STATE(); 489 | case 43: 490 | ACCEPT_TOKEN(anon_sym_LT_PERCENT_EQ_EQ); 491 | END_STATE(); 492 | case 44: 493 | ACCEPT_TOKEN(anon_sym_LT_PERCENT_PIPE_EQ); 494 | if (lookahead == '=') ADVANCE(45); 495 | END_STATE(); 496 | case 45: 497 | ACCEPT_TOKEN(anon_sym_LT_PERCENT_PIPE_EQ_EQ); 498 | END_STATE(); 499 | case 46: 500 | ACCEPT_TOKEN(anon_sym_LT_PERCENT_DASH); 501 | END_STATE(); 502 | case 47: 503 | ACCEPT_TOKEN(anon_sym_xyz); 504 | END_STATE(); 505 | case 48: 506 | ACCEPT_TOKEN(anon_sym_xyz); 507 | if (lookahead != 0 && 508 | lookahead != '<') ADVANCE(33); 509 | END_STATE(); 510 | case 49: 511 | ACCEPT_TOKEN(anon_sym_EQ_PERCENT_GT); 512 | END_STATE(); 513 | case 50: 514 | ACCEPT_TOKEN(anon_sym_LT_PERCENT_POUND); 515 | END_STATE(); 516 | case 51: 517 | ACCEPT_TOKEN(anon_sym_LT_PERCENTgraphql); 518 | END_STATE(); 519 | default: 520 | return false; 521 | } 522 | } 523 | 524 | static const TSLexerMode ts_lex_modes[STATE_COUNT] = { 525 | [0] = {.lex_state = 0}, 526 | [1] = {.lex_state = 21}, 527 | [2] = {.lex_state = 21}, 528 | [3] = {.lex_state = 21}, 529 | [4] = {.lex_state = 21}, 530 | [5] = {.lex_state = 21}, 531 | [6] = {.lex_state = 21}, 532 | [7] = {.lex_state = 21}, 533 | [8] = {.lex_state = 21}, 534 | [9] = {.lex_state = 21}, 535 | [10] = {.lex_state = 21}, 536 | [11] = {.lex_state = 21}, 537 | [12] = {.lex_state = 21}, 538 | [13] = {.lex_state = 21}, 539 | [14] = {.lex_state = 4}, 540 | [15] = {.lex_state = 3}, 541 | [16] = {.lex_state = 3}, 542 | [17] = {.lex_state = 3}, 543 | [18] = {.lex_state = 4}, 544 | [19] = {.lex_state = 4}, 545 | [20] = {.lex_state = 5}, 546 | [21] = {.lex_state = 5}, 547 | [22] = {.lex_state = 5}, 548 | [23] = {.lex_state = 5}, 549 | [24] = {.lex_state = 0}, 550 | [25] = {.lex_state = 0}, 551 | [26] = {.lex_state = 0}, 552 | [27] = {.lex_state = 0}, 553 | [28] = {.lex_state = 0}, 554 | }; 555 | 556 | static const uint16_t ts_parse_table[LARGE_STATE_COUNT][SYMBOL_COUNT] = { 557 | [STATE(0)] = { 558 | [ts_builtin_sym_end] = ACTIONS(1), 559 | [anon_sym_PERCENT_PERCENT_GT] = ACTIONS(1), 560 | [anon_sym_LT_PERCENT_PERCENT] = ACTIONS(1), 561 | [anon_sym_LT_PERCENT] = ACTIONS(1), 562 | [anon_sym_LT_PERCENT_] = ACTIONS(1), 563 | [anon_sym_LT_PERCENT_PIPE] = ACTIONS(1), 564 | [anon_sym_LT_PERCENT_TILDE] = ACTIONS(1), 565 | [anon_sym_PERCENT_GT] = ACTIONS(1), 566 | [anon_sym_DASH_PERCENT_GT] = ACTIONS(1), 567 | [anon_sym__PERCENT_GT] = ACTIONS(1), 568 | [anon_sym_LT_PERCENT_EQ] = ACTIONS(1), 569 | [anon_sym_LT_PERCENT_EQ_EQ] = ACTIONS(1), 570 | [anon_sym_LT_PERCENT_PIPE_EQ] = ACTIONS(1), 571 | [anon_sym_LT_PERCENT_PIPE_EQ_EQ] = ACTIONS(1), 572 | [anon_sym_LT_PERCENT_DASH] = ACTIONS(1), 573 | [anon_sym_xyz] = ACTIONS(1), 574 | [anon_sym_EQ_PERCENT_GT] = ACTIONS(1), 575 | [anon_sym_LT_PERCENT_POUND] = ACTIONS(1), 576 | [anon_sym_LT_PERCENTgraphql] = ACTIONS(1), 577 | }, 578 | [STATE(1)] = { 579 | [sym_template] = STATE(26), 580 | [sym_content] = STATE(2), 581 | [sym_directive] = STATE(2), 582 | [sym_output_directive] = STATE(2), 583 | [sym_comment_directive] = STATE(2), 584 | [sym_graphql_directive] = STATE(2), 585 | [aux_sym_template_repeat1] = STATE(2), 586 | [aux_sym_content_repeat1] = STATE(4), 587 | [ts_builtin_sym_end] = ACTIONS(3), 588 | [aux_sym_content_token1] = ACTIONS(5), 589 | [anon_sym_LT_PERCENT_PERCENT] = ACTIONS(7), 590 | [anon_sym_LT_PERCENT] = ACTIONS(9), 591 | [anon_sym_LT_PERCENT_] = ACTIONS(11), 592 | [anon_sym_LT_PERCENT_PIPE] = ACTIONS(9), 593 | [anon_sym_LT_PERCENT_TILDE] = ACTIONS(11), 594 | [anon_sym_LT_PERCENT_EQ] = ACTIONS(13), 595 | [anon_sym_LT_PERCENT_EQ_EQ] = ACTIONS(15), 596 | [anon_sym_LT_PERCENT_PIPE_EQ] = ACTIONS(13), 597 | [anon_sym_LT_PERCENT_PIPE_EQ_EQ] = ACTIONS(15), 598 | [anon_sym_LT_PERCENT_DASH] = ACTIONS(15), 599 | [anon_sym_xyz] = ACTIONS(13), 600 | [anon_sym_LT_PERCENT_POUND] = ACTIONS(17), 601 | [anon_sym_LT_PERCENTgraphql] = ACTIONS(19), 602 | }, 603 | [STATE(2)] = { 604 | [sym_content] = STATE(3), 605 | [sym_directive] = STATE(3), 606 | [sym_output_directive] = STATE(3), 607 | [sym_comment_directive] = STATE(3), 608 | [sym_graphql_directive] = STATE(3), 609 | [aux_sym_template_repeat1] = STATE(3), 610 | [aux_sym_content_repeat1] = STATE(4), 611 | [ts_builtin_sym_end] = ACTIONS(21), 612 | [aux_sym_content_token1] = ACTIONS(5), 613 | [anon_sym_LT_PERCENT_PERCENT] = ACTIONS(7), 614 | [anon_sym_LT_PERCENT] = ACTIONS(9), 615 | [anon_sym_LT_PERCENT_] = ACTIONS(11), 616 | [anon_sym_LT_PERCENT_PIPE] = ACTIONS(9), 617 | [anon_sym_LT_PERCENT_TILDE] = ACTIONS(11), 618 | [anon_sym_LT_PERCENT_EQ] = ACTIONS(13), 619 | [anon_sym_LT_PERCENT_EQ_EQ] = ACTIONS(15), 620 | [anon_sym_LT_PERCENT_PIPE_EQ] = ACTIONS(13), 621 | [anon_sym_LT_PERCENT_PIPE_EQ_EQ] = ACTIONS(15), 622 | [anon_sym_LT_PERCENT_DASH] = ACTIONS(15), 623 | [anon_sym_xyz] = ACTIONS(13), 624 | [anon_sym_LT_PERCENT_POUND] = ACTIONS(17), 625 | [anon_sym_LT_PERCENTgraphql] = ACTIONS(19), 626 | }, 627 | [STATE(3)] = { 628 | [sym_content] = STATE(3), 629 | [sym_directive] = STATE(3), 630 | [sym_output_directive] = STATE(3), 631 | [sym_comment_directive] = STATE(3), 632 | [sym_graphql_directive] = STATE(3), 633 | [aux_sym_template_repeat1] = STATE(3), 634 | [aux_sym_content_repeat1] = STATE(4), 635 | [ts_builtin_sym_end] = ACTIONS(23), 636 | [aux_sym_content_token1] = ACTIONS(25), 637 | [anon_sym_LT_PERCENT_PERCENT] = ACTIONS(28), 638 | [anon_sym_LT_PERCENT] = ACTIONS(31), 639 | [anon_sym_LT_PERCENT_] = ACTIONS(34), 640 | [anon_sym_LT_PERCENT_PIPE] = ACTIONS(31), 641 | [anon_sym_LT_PERCENT_TILDE] = ACTIONS(34), 642 | [anon_sym_LT_PERCENT_EQ] = ACTIONS(37), 643 | [anon_sym_LT_PERCENT_EQ_EQ] = ACTIONS(40), 644 | [anon_sym_LT_PERCENT_PIPE_EQ] = ACTIONS(37), 645 | [anon_sym_LT_PERCENT_PIPE_EQ_EQ] = ACTIONS(40), 646 | [anon_sym_LT_PERCENT_DASH] = ACTIONS(40), 647 | [anon_sym_xyz] = ACTIONS(37), 648 | [anon_sym_LT_PERCENT_POUND] = ACTIONS(43), 649 | [anon_sym_LT_PERCENTgraphql] = ACTIONS(46), 650 | }, 651 | [STATE(4)] = { 652 | [aux_sym_content_repeat1] = STATE(5), 653 | [ts_builtin_sym_end] = ACTIONS(49), 654 | [aux_sym_content_token1] = ACTIONS(51), 655 | [anon_sym_LT_PERCENT_PERCENT] = ACTIONS(53), 656 | [anon_sym_LT_PERCENT] = ACTIONS(55), 657 | [anon_sym_LT_PERCENT_] = ACTIONS(49), 658 | [anon_sym_LT_PERCENT_PIPE] = ACTIONS(55), 659 | [anon_sym_LT_PERCENT_TILDE] = ACTIONS(49), 660 | [anon_sym_LT_PERCENT_EQ] = ACTIONS(55), 661 | [anon_sym_LT_PERCENT_EQ_EQ] = ACTIONS(49), 662 | [anon_sym_LT_PERCENT_PIPE_EQ] = ACTIONS(55), 663 | [anon_sym_LT_PERCENT_PIPE_EQ_EQ] = ACTIONS(49), 664 | [anon_sym_LT_PERCENT_DASH] = ACTIONS(49), 665 | [anon_sym_xyz] = ACTIONS(55), 666 | [anon_sym_LT_PERCENT_POUND] = ACTIONS(49), 667 | [anon_sym_LT_PERCENTgraphql] = ACTIONS(49), 668 | }, 669 | [STATE(5)] = { 670 | [aux_sym_content_repeat1] = STATE(5), 671 | [ts_builtin_sym_end] = ACTIONS(57), 672 | [aux_sym_content_token1] = ACTIONS(59), 673 | [anon_sym_LT_PERCENT_PERCENT] = ACTIONS(62), 674 | [anon_sym_LT_PERCENT] = ACTIONS(65), 675 | [anon_sym_LT_PERCENT_] = ACTIONS(57), 676 | [anon_sym_LT_PERCENT_PIPE] = ACTIONS(65), 677 | [anon_sym_LT_PERCENT_TILDE] = ACTIONS(57), 678 | [anon_sym_LT_PERCENT_EQ] = ACTIONS(65), 679 | [anon_sym_LT_PERCENT_EQ_EQ] = ACTIONS(57), 680 | [anon_sym_LT_PERCENT_PIPE_EQ] = ACTIONS(65), 681 | [anon_sym_LT_PERCENT_PIPE_EQ_EQ] = ACTIONS(57), 682 | [anon_sym_LT_PERCENT_DASH] = ACTIONS(57), 683 | [anon_sym_xyz] = ACTIONS(65), 684 | [anon_sym_LT_PERCENT_POUND] = ACTIONS(57), 685 | [anon_sym_LT_PERCENTgraphql] = ACTIONS(57), 686 | }, 687 | }; 688 | 689 | static const uint16_t ts_small_parse_table[] = { 690 | [0] = 2, 691 | ACTIONS(69), 6, 692 | aux_sym_content_token1, 693 | anon_sym_LT_PERCENT, 694 | anon_sym_LT_PERCENT_PIPE, 695 | anon_sym_LT_PERCENT_EQ, 696 | anon_sym_LT_PERCENT_PIPE_EQ, 697 | anon_sym_xyz, 698 | ACTIONS(67), 9, 699 | ts_builtin_sym_end, 700 | anon_sym_LT_PERCENT_PERCENT, 701 | anon_sym_LT_PERCENT_, 702 | anon_sym_LT_PERCENT_TILDE, 703 | anon_sym_LT_PERCENT_EQ_EQ, 704 | anon_sym_LT_PERCENT_PIPE_EQ_EQ, 705 | anon_sym_LT_PERCENT_DASH, 706 | anon_sym_LT_PERCENT_POUND, 707 | anon_sym_LT_PERCENTgraphql, 708 | [20] = 2, 709 | ACTIONS(73), 6, 710 | aux_sym_content_token1, 711 | anon_sym_LT_PERCENT, 712 | anon_sym_LT_PERCENT_PIPE, 713 | anon_sym_LT_PERCENT_EQ, 714 | anon_sym_LT_PERCENT_PIPE_EQ, 715 | anon_sym_xyz, 716 | ACTIONS(71), 9, 717 | ts_builtin_sym_end, 718 | anon_sym_LT_PERCENT_PERCENT, 719 | anon_sym_LT_PERCENT_, 720 | anon_sym_LT_PERCENT_TILDE, 721 | anon_sym_LT_PERCENT_EQ_EQ, 722 | anon_sym_LT_PERCENT_PIPE_EQ_EQ, 723 | anon_sym_LT_PERCENT_DASH, 724 | anon_sym_LT_PERCENT_POUND, 725 | anon_sym_LT_PERCENTgraphql, 726 | [40] = 2, 727 | ACTIONS(77), 6, 728 | aux_sym_content_token1, 729 | anon_sym_LT_PERCENT, 730 | anon_sym_LT_PERCENT_PIPE, 731 | anon_sym_LT_PERCENT_EQ, 732 | anon_sym_LT_PERCENT_PIPE_EQ, 733 | anon_sym_xyz, 734 | ACTIONS(75), 9, 735 | ts_builtin_sym_end, 736 | anon_sym_LT_PERCENT_PERCENT, 737 | anon_sym_LT_PERCENT_, 738 | anon_sym_LT_PERCENT_TILDE, 739 | anon_sym_LT_PERCENT_EQ_EQ, 740 | anon_sym_LT_PERCENT_PIPE_EQ_EQ, 741 | anon_sym_LT_PERCENT_DASH, 742 | anon_sym_LT_PERCENT_POUND, 743 | anon_sym_LT_PERCENTgraphql, 744 | [60] = 2, 745 | ACTIONS(81), 6, 746 | aux_sym_content_token1, 747 | anon_sym_LT_PERCENT, 748 | anon_sym_LT_PERCENT_PIPE, 749 | anon_sym_LT_PERCENT_EQ, 750 | anon_sym_LT_PERCENT_PIPE_EQ, 751 | anon_sym_xyz, 752 | ACTIONS(79), 9, 753 | ts_builtin_sym_end, 754 | anon_sym_LT_PERCENT_PERCENT, 755 | anon_sym_LT_PERCENT_, 756 | anon_sym_LT_PERCENT_TILDE, 757 | anon_sym_LT_PERCENT_EQ_EQ, 758 | anon_sym_LT_PERCENT_PIPE_EQ_EQ, 759 | anon_sym_LT_PERCENT_DASH, 760 | anon_sym_LT_PERCENT_POUND, 761 | anon_sym_LT_PERCENTgraphql, 762 | [80] = 2, 763 | ACTIONS(85), 6, 764 | aux_sym_content_token1, 765 | anon_sym_LT_PERCENT, 766 | anon_sym_LT_PERCENT_PIPE, 767 | anon_sym_LT_PERCENT_EQ, 768 | anon_sym_LT_PERCENT_PIPE_EQ, 769 | anon_sym_xyz, 770 | ACTIONS(83), 9, 771 | ts_builtin_sym_end, 772 | anon_sym_LT_PERCENT_PERCENT, 773 | anon_sym_LT_PERCENT_, 774 | anon_sym_LT_PERCENT_TILDE, 775 | anon_sym_LT_PERCENT_EQ_EQ, 776 | anon_sym_LT_PERCENT_PIPE_EQ_EQ, 777 | anon_sym_LT_PERCENT_DASH, 778 | anon_sym_LT_PERCENT_POUND, 779 | anon_sym_LT_PERCENTgraphql, 780 | [100] = 2, 781 | ACTIONS(89), 6, 782 | aux_sym_content_token1, 783 | anon_sym_LT_PERCENT, 784 | anon_sym_LT_PERCENT_PIPE, 785 | anon_sym_LT_PERCENT_EQ, 786 | anon_sym_LT_PERCENT_PIPE_EQ, 787 | anon_sym_xyz, 788 | ACTIONS(87), 9, 789 | ts_builtin_sym_end, 790 | anon_sym_LT_PERCENT_PERCENT, 791 | anon_sym_LT_PERCENT_, 792 | anon_sym_LT_PERCENT_TILDE, 793 | anon_sym_LT_PERCENT_EQ_EQ, 794 | anon_sym_LT_PERCENT_PIPE_EQ_EQ, 795 | anon_sym_LT_PERCENT_DASH, 796 | anon_sym_LT_PERCENT_POUND, 797 | anon_sym_LT_PERCENTgraphql, 798 | [120] = 2, 799 | ACTIONS(93), 6, 800 | aux_sym_content_token1, 801 | anon_sym_LT_PERCENT, 802 | anon_sym_LT_PERCENT_PIPE, 803 | anon_sym_LT_PERCENT_EQ, 804 | anon_sym_LT_PERCENT_PIPE_EQ, 805 | anon_sym_xyz, 806 | ACTIONS(91), 9, 807 | ts_builtin_sym_end, 808 | anon_sym_LT_PERCENT_PERCENT, 809 | anon_sym_LT_PERCENT_, 810 | anon_sym_LT_PERCENT_TILDE, 811 | anon_sym_LT_PERCENT_EQ_EQ, 812 | anon_sym_LT_PERCENT_PIPE_EQ_EQ, 813 | anon_sym_LT_PERCENT_DASH, 814 | anon_sym_LT_PERCENT_POUND, 815 | anon_sym_LT_PERCENTgraphql, 816 | [140] = 2, 817 | ACTIONS(97), 6, 818 | aux_sym_content_token1, 819 | anon_sym_LT_PERCENT, 820 | anon_sym_LT_PERCENT_PIPE, 821 | anon_sym_LT_PERCENT_EQ, 822 | anon_sym_LT_PERCENT_PIPE_EQ, 823 | anon_sym_xyz, 824 | ACTIONS(95), 9, 825 | ts_builtin_sym_end, 826 | anon_sym_LT_PERCENT_PERCENT, 827 | anon_sym_LT_PERCENT_, 828 | anon_sym_LT_PERCENT_TILDE, 829 | anon_sym_LT_PERCENT_EQ_EQ, 830 | anon_sym_LT_PERCENT_PIPE_EQ_EQ, 831 | anon_sym_LT_PERCENT_DASH, 832 | anon_sym_LT_PERCENT_POUND, 833 | anon_sym_LT_PERCENTgraphql, 834 | [160] = 5, 835 | ACTIONS(99), 1, 836 | aux_sym_code_token1, 837 | ACTIONS(101), 1, 838 | anon_sym_PERCENT_PERCENT_GT, 839 | STATE(19), 1, 840 | aux_sym_code_repeat1, 841 | STATE(25), 1, 842 | sym_code, 843 | ACTIONS(103), 3, 844 | anon_sym_PERCENT_GT, 845 | anon_sym_DASH_PERCENT_GT, 846 | anon_sym_EQ_PERCENT_GT, 847 | [178] = 5, 848 | ACTIONS(105), 1, 849 | aux_sym_code_token1, 850 | ACTIONS(107), 1, 851 | anon_sym_PERCENT_PERCENT_GT, 852 | STATE(16), 1, 853 | aux_sym_code_repeat1, 854 | STATE(24), 1, 855 | sym_code, 856 | ACTIONS(109), 3, 857 | anon_sym_PERCENT_GT, 858 | anon_sym_DASH_PERCENT_GT, 859 | anon_sym__PERCENT_GT, 860 | [196] = 4, 861 | ACTIONS(111), 1, 862 | aux_sym_code_token1, 863 | ACTIONS(113), 1, 864 | anon_sym_PERCENT_PERCENT_GT, 865 | STATE(17), 1, 866 | aux_sym_code_repeat1, 867 | ACTIONS(115), 3, 868 | anon_sym_PERCENT_GT, 869 | anon_sym_DASH_PERCENT_GT, 870 | anon_sym__PERCENT_GT, 871 | [211] = 4, 872 | ACTIONS(117), 1, 873 | aux_sym_code_token1, 874 | ACTIONS(120), 1, 875 | anon_sym_PERCENT_PERCENT_GT, 876 | STATE(17), 1, 877 | aux_sym_code_repeat1, 878 | ACTIONS(123), 3, 879 | anon_sym_PERCENT_GT, 880 | anon_sym_DASH_PERCENT_GT, 881 | anon_sym__PERCENT_GT, 882 | [226] = 4, 883 | ACTIONS(125), 1, 884 | aux_sym_code_token1, 885 | ACTIONS(128), 1, 886 | anon_sym_PERCENT_PERCENT_GT, 887 | STATE(18), 1, 888 | aux_sym_code_repeat1, 889 | ACTIONS(123), 3, 890 | anon_sym_PERCENT_GT, 891 | anon_sym_DASH_PERCENT_GT, 892 | anon_sym_EQ_PERCENT_GT, 893 | [241] = 4, 894 | ACTIONS(131), 1, 895 | aux_sym_code_token1, 896 | ACTIONS(133), 1, 897 | anon_sym_PERCENT_PERCENT_GT, 898 | STATE(18), 1, 899 | aux_sym_code_repeat1, 900 | ACTIONS(115), 3, 901 | anon_sym_PERCENT_GT, 902 | anon_sym_DASH_PERCENT_GT, 903 | anon_sym_EQ_PERCENT_GT, 904 | [256] = 5, 905 | ACTIONS(135), 1, 906 | aux_sym_code_token1, 907 | ACTIONS(137), 1, 908 | anon_sym_PERCENT_PERCENT_GT, 909 | ACTIONS(139), 1, 910 | anon_sym_PERCENT_GT, 911 | STATE(22), 1, 912 | aux_sym_code_repeat1, 913 | STATE(28), 1, 914 | sym_code, 915 | [272] = 5, 916 | ACTIONS(135), 1, 917 | aux_sym_code_token1, 918 | ACTIONS(137), 1, 919 | anon_sym_PERCENT_PERCENT_GT, 920 | ACTIONS(141), 1, 921 | anon_sym_PERCENT_GT, 922 | STATE(22), 1, 923 | aux_sym_code_repeat1, 924 | STATE(27), 1, 925 | sym_code, 926 | [288] = 4, 927 | ACTIONS(115), 1, 928 | anon_sym_PERCENT_GT, 929 | ACTIONS(143), 1, 930 | aux_sym_code_token1, 931 | ACTIONS(145), 1, 932 | anon_sym_PERCENT_PERCENT_GT, 933 | STATE(23), 1, 934 | aux_sym_code_repeat1, 935 | [301] = 4, 936 | ACTIONS(123), 1, 937 | anon_sym_PERCENT_GT, 938 | ACTIONS(147), 1, 939 | aux_sym_code_token1, 940 | ACTIONS(150), 1, 941 | anon_sym_PERCENT_PERCENT_GT, 942 | STATE(23), 1, 943 | aux_sym_code_repeat1, 944 | [314] = 1, 945 | ACTIONS(153), 3, 946 | anon_sym_PERCENT_GT, 947 | anon_sym_DASH_PERCENT_GT, 948 | anon_sym__PERCENT_GT, 949 | [320] = 1, 950 | ACTIONS(155), 3, 951 | anon_sym_PERCENT_GT, 952 | anon_sym_DASH_PERCENT_GT, 953 | anon_sym_EQ_PERCENT_GT, 954 | [326] = 1, 955 | ACTIONS(157), 1, 956 | ts_builtin_sym_end, 957 | [330] = 1, 958 | ACTIONS(159), 1, 959 | anon_sym_PERCENT_GT, 960 | [334] = 1, 961 | ACTIONS(161), 1, 962 | anon_sym_PERCENT_GT, 963 | }; 964 | 965 | static const uint32_t ts_small_parse_table_map[] = { 966 | [SMALL_STATE(6)] = 0, 967 | [SMALL_STATE(7)] = 20, 968 | [SMALL_STATE(8)] = 40, 969 | [SMALL_STATE(9)] = 60, 970 | [SMALL_STATE(10)] = 80, 971 | [SMALL_STATE(11)] = 100, 972 | [SMALL_STATE(12)] = 120, 973 | [SMALL_STATE(13)] = 140, 974 | [SMALL_STATE(14)] = 160, 975 | [SMALL_STATE(15)] = 178, 976 | [SMALL_STATE(16)] = 196, 977 | [SMALL_STATE(17)] = 211, 978 | [SMALL_STATE(18)] = 226, 979 | [SMALL_STATE(19)] = 241, 980 | [SMALL_STATE(20)] = 256, 981 | [SMALL_STATE(21)] = 272, 982 | [SMALL_STATE(22)] = 288, 983 | [SMALL_STATE(23)] = 301, 984 | [SMALL_STATE(24)] = 314, 985 | [SMALL_STATE(25)] = 320, 986 | [SMALL_STATE(26)] = 326, 987 | [SMALL_STATE(27)] = 330, 988 | [SMALL_STATE(28)] = 334, 989 | }; 990 | 991 | static const TSParseActionEntry ts_parse_actions[] = { 992 | [0] = {.entry = {.count = 0, .reusable = false}}, 993 | [1] = {.entry = {.count = 1, .reusable = false}}, RECOVER(), 994 | [3] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_template, 0, 0, 0), 995 | [5] = {.entry = {.count = 1, .reusable = false}}, SHIFT(4), 996 | [7] = {.entry = {.count = 1, .reusable = true}}, SHIFT(4), 997 | [9] = {.entry = {.count = 1, .reusable = false}}, SHIFT(15), 998 | [11] = {.entry = {.count = 1, .reusable = true}}, SHIFT(15), 999 | [13] = {.entry = {.count = 1, .reusable = false}}, SHIFT(14), 1000 | [15] = {.entry = {.count = 1, .reusable = true}}, SHIFT(14), 1001 | [17] = {.entry = {.count = 1, .reusable = true}}, SHIFT(20), 1002 | [19] = {.entry = {.count = 1, .reusable = true}}, SHIFT(21), 1003 | [21] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_template, 1, 0, 0), 1004 | [23] = {.entry = {.count = 1, .reusable = true}}, REDUCE(aux_sym_template_repeat1, 2, 0, 0), 1005 | [25] = {.entry = {.count = 2, .reusable = false}}, REDUCE(aux_sym_template_repeat1, 2, 0, 0), SHIFT_REPEAT(4), 1006 | [28] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_template_repeat1, 2, 0, 0), SHIFT_REPEAT(4), 1007 | [31] = {.entry = {.count = 2, .reusable = false}}, REDUCE(aux_sym_template_repeat1, 2, 0, 0), SHIFT_REPEAT(15), 1008 | [34] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_template_repeat1, 2, 0, 0), SHIFT_REPEAT(15), 1009 | [37] = {.entry = {.count = 2, .reusable = false}}, REDUCE(aux_sym_template_repeat1, 2, 0, 0), SHIFT_REPEAT(14), 1010 | [40] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_template_repeat1, 2, 0, 0), SHIFT_REPEAT(14), 1011 | [43] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_template_repeat1, 2, 0, 0), SHIFT_REPEAT(20), 1012 | [46] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_template_repeat1, 2, 0, 0), SHIFT_REPEAT(21), 1013 | [49] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_content, 1, 0, 0), 1014 | [51] = {.entry = {.count = 1, .reusable = false}}, SHIFT(5), 1015 | [53] = {.entry = {.count = 1, .reusable = true}}, SHIFT(5), 1016 | [55] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_content, 1, 0, 0), 1017 | [57] = {.entry = {.count = 1, .reusable = true}}, REDUCE(aux_sym_content_repeat1, 2, 0, 0), 1018 | [59] = {.entry = {.count = 2, .reusable = false}}, REDUCE(aux_sym_content_repeat1, 2, 0, 0), SHIFT_REPEAT(5), 1019 | [62] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_content_repeat1, 2, 0, 0), SHIFT_REPEAT(5), 1020 | [65] = {.entry = {.count = 1, .reusable = false}}, REDUCE(aux_sym_content_repeat1, 2, 0, 0), 1021 | [67] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_directive, 2, 0, 0), 1022 | [69] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_directive, 2, 0, 0), 1023 | [71] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_output_directive, 2, 0, 0), 1024 | [73] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_output_directive, 2, 0, 0), 1025 | [75] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_graphql_directive, 3, 0, 0), 1026 | [77] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_graphql_directive, 3, 0, 0), 1027 | [79] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_directive, 3, 0, 0), 1028 | [81] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_directive, 3, 0, 0), 1029 | [83] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_comment_directive, 2, 0, 0), 1030 | [85] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_comment_directive, 2, 0, 0), 1031 | [87] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_graphql_directive, 2, 0, 0), 1032 | [89] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_graphql_directive, 2, 0, 0), 1033 | [91] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_output_directive, 3, 0, 0), 1034 | [93] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_output_directive, 3, 0, 0), 1035 | [95] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_comment_directive, 3, 0, 1), 1036 | [97] = {.entry = {.count = 1, .reusable = false}}, REDUCE(sym_comment_directive, 3, 0, 1), 1037 | [99] = {.entry = {.count = 1, .reusable = false}}, SHIFT(19), 1038 | [101] = {.entry = {.count = 1, .reusable = true}}, SHIFT(19), 1039 | [103] = {.entry = {.count = 1, .reusable = true}}, SHIFT(7), 1040 | [105] = {.entry = {.count = 1, .reusable = false}}, SHIFT(16), 1041 | [107] = {.entry = {.count = 1, .reusable = true}}, SHIFT(16), 1042 | [109] = {.entry = {.count = 1, .reusable = true}}, SHIFT(6), 1043 | [111] = {.entry = {.count = 1, .reusable = false}}, SHIFT(17), 1044 | [113] = {.entry = {.count = 1, .reusable = true}}, SHIFT(17), 1045 | [115] = {.entry = {.count = 1, .reusable = true}}, REDUCE(sym_code, 1, 0, 0), 1046 | [117] = {.entry = {.count = 2, .reusable = false}}, REDUCE(aux_sym_code_repeat1, 2, 0, 0), SHIFT_REPEAT(17), 1047 | [120] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_code_repeat1, 2, 0, 0), SHIFT_REPEAT(17), 1048 | [123] = {.entry = {.count = 1, .reusable = true}}, REDUCE(aux_sym_code_repeat1, 2, 0, 0), 1049 | [125] = {.entry = {.count = 2, .reusable = false}}, REDUCE(aux_sym_code_repeat1, 2, 0, 0), SHIFT_REPEAT(18), 1050 | [128] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_code_repeat1, 2, 0, 0), SHIFT_REPEAT(18), 1051 | [131] = {.entry = {.count = 1, .reusable = false}}, SHIFT(18), 1052 | [133] = {.entry = {.count = 1, .reusable = true}}, SHIFT(18), 1053 | [135] = {.entry = {.count = 1, .reusable = false}}, SHIFT(22), 1054 | [137] = {.entry = {.count = 1, .reusable = true}}, SHIFT(22), 1055 | [139] = {.entry = {.count = 1, .reusable = true}}, SHIFT(10), 1056 | [141] = {.entry = {.count = 1, .reusable = true}}, SHIFT(11), 1057 | [143] = {.entry = {.count = 1, .reusable = false}}, SHIFT(23), 1058 | [145] = {.entry = {.count = 1, .reusable = true}}, SHIFT(23), 1059 | [147] = {.entry = {.count = 2, .reusable = false}}, REDUCE(aux_sym_code_repeat1, 2, 0, 0), SHIFT_REPEAT(23), 1060 | [150] = {.entry = {.count = 2, .reusable = true}}, REDUCE(aux_sym_code_repeat1, 2, 0, 0), SHIFT_REPEAT(23), 1061 | [153] = {.entry = {.count = 1, .reusable = true}}, SHIFT(9), 1062 | [155] = {.entry = {.count = 1, .reusable = true}}, SHIFT(12), 1063 | [157] = {.entry = {.count = 1, .reusable = true}}, ACCEPT_INPUT(), 1064 | [159] = {.entry = {.count = 1, .reusable = true}}, SHIFT(8), 1065 | [161] = {.entry = {.count = 1, .reusable = true}}, SHIFT(13), 1066 | }; 1067 | 1068 | #ifdef __cplusplus 1069 | extern "C" { 1070 | #endif 1071 | #ifdef TREE_SITTER_HIDE_SYMBOLS 1072 | #define TS_PUBLIC 1073 | #elif defined(_WIN32) 1074 | #define TS_PUBLIC __declspec(dllexport) 1075 | #else 1076 | #define TS_PUBLIC __attribute__((visibility("default"))) 1077 | #endif 1078 | 1079 | TS_PUBLIC const TSLanguage *tree_sitter_embedded_template(void) { 1080 | static const TSLanguage language = { 1081 | .abi_version = LANGUAGE_VERSION, 1082 | .symbol_count = SYMBOL_COUNT, 1083 | .alias_count = ALIAS_COUNT, 1084 | .token_count = TOKEN_COUNT, 1085 | .external_token_count = EXTERNAL_TOKEN_COUNT, 1086 | .state_count = STATE_COUNT, 1087 | .large_state_count = LARGE_STATE_COUNT, 1088 | .production_id_count = PRODUCTION_ID_COUNT, 1089 | .supertype_count = SUPERTYPE_COUNT, 1090 | .field_count = FIELD_COUNT, 1091 | .max_alias_sequence_length = MAX_ALIAS_SEQUENCE_LENGTH, 1092 | .parse_table = &ts_parse_table[0][0], 1093 | .small_parse_table = ts_small_parse_table, 1094 | .small_parse_table_map = ts_small_parse_table_map, 1095 | .parse_actions = ts_parse_actions, 1096 | .symbol_names = ts_symbol_names, 1097 | .symbol_metadata = ts_symbol_metadata, 1098 | .public_symbol_map = ts_symbol_map, 1099 | .alias_map = ts_non_terminal_alias_map, 1100 | .alias_sequences = &ts_alias_sequences[0][0], 1101 | .lex_modes = (const void*)ts_lex_modes, 1102 | .lex_fn = ts_lex, 1103 | .primary_state_ids = ts_primary_state_ids, 1104 | .name = "embedded_template", 1105 | .max_reserved_word_set_size = 0, 1106 | .metadata = { 1107 | .major_version = 0, 1108 | .minor_version = 25, 1109 | .patch_version = 0, 1110 | }, 1111 | }; 1112 | return &language; 1113 | } 1114 | #ifdef __cplusplus 1115 | } 1116 | #endif 1117 | --------------------------------------------------------------------------------