From 1e6d8ca3d85c0031ff010759bb60804dd47b95f2 Mon Sep 17 00:00:00 2001 From: Dmitriy Pleshevskiy Date: Fri, 12 Jul 2024 20:36:24 +0300 Subject: [PATCH] update tree-sitter deps --- .editorconfig | 39 +++ .gitattributes | 11 + Makefile | 2 +- Package.swift | 47 ++++ README.md | 2 +- binding.gyp | 23 +- bindings/c/tree-sitter-d2.h | 16 ++ bindings/c/tree-sitter-d2.pc.in | 11 + bindings/go/binding.go | 13 + bindings/go/binding_test.go | 15 + bindings/go/go.mod | 5 + bindings/node/binding.cc | 36 +-- bindings/node/index.d.ts | 28 ++ bindings/node/index.js | 18 +- bindings/python/tree_sitter_d2/__init__.py | 5 + bindings/python/tree_sitter_d2/__init__.pyi | 1 + bindings/python/tree_sitter_d2/binding.c | 27 ++ bindings/python/tree_sitter_d2/py.typed | 0 bindings/rust/build.rs | 5 +- bindings/swift/TreeSitterD2/d2.h | 16 ++ flake.lock | 8 +- flake.nix | 2 +- grammar.js | 20 +- package-lock.json | 13 + package.json | 27 ++ pyproject.toml | 29 ++ queries/highlights.scm | 2 +- setup.py | 60 ++++ src/grammar.json | 31 +-- src/node-types.json | 28 ++ src/parser.c | Bin 280172 -> 274866 bytes src/scanner.c | 182 ++++++++++++ src/tree_sitter/alloc.h | 54 ++++ src/tree_sitter/array.h | 290 ++++++++++++++++++++ src/tree_sitter/parser.h | 67 ++++- test/corpus/attributes.txt | 261 +++++++++--------- test/corpus/classes.txt | 20 ++ test/corpus/connection.txt | 13 +- test/corpus/container.txt | 23 +- test/corpus/shape.txt | 22 +- tree-sitter-d2.wasm | Bin 70373 -> 66396 bytes 41 files changed, 1242 insertions(+), 230 deletions(-) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 Package.swift create mode 100644 bindings/c/tree-sitter-d2.h create mode 100644 bindings/c/tree-sitter-d2.pc.in create mode 100644 bindings/go/binding.go create mode 100644 bindings/go/binding_test.go create mode 100644 bindings/go/go.mod create mode 100644 bindings/node/index.d.ts create mode 100644 bindings/python/tree_sitter_d2/__init__.py create mode 100644 bindings/python/tree_sitter_d2/__init__.pyi create mode 100644 bindings/python/tree_sitter_d2/binding.c create mode 100644 bindings/python/tree_sitter_d2/py.typed create mode 100644 bindings/swift/TreeSitterD2/d2.h create mode 100644 package-lock.json create mode 100644 pyproject.toml create mode 100644 setup.py create mode 100644 src/scanner.c create mode 100644 src/tree_sitter/alloc.h create mode 100644 src/tree_sitter/array.h diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d3a8b5b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,39 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.{json,toml,yml,gyp}] +indent_style = space +indent_size = 2 + +[*.js] +indent_style = space +indent_size = 2 + +[*.rs] +indent_style = space +indent_size = 4 + +[*.{c,cc,h}] +indent_style = space +indent_size = 4 + +[*.{py,pyi}] +indent_style = space +indent_size = 4 + +[*.swift] +indent_style = space +indent_size = 4 + +[*.go] +indent_style = tab +indent_size = 8 + +[Makefile] +indent_style = tab +indent_size = 8 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ffb52ab --- /dev/null +++ b/.gitattributes @@ -0,0 +1,11 @@ +* text eol=lf + +src/*.json linguist-generated +src/parser.c linguist-generated +src/tree_sitter/* linguist-generated + +bindings/** linguist-generated +binding.gyp linguist-generated +setup.py linguist-generated +Makefile linguist-generated +Package.swift linguist-generated diff --git a/Makefile b/Makefile index 5829278..4001f42 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ playground: build-wasm tree-sitter playground --quiet build-wasm: build - tree-sitter build-wasm + tree-sitter build --wasm build: tree-sitter generate diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..3388ee9 --- /dev/null +++ b/Package.swift @@ -0,0 +1,47 @@ +// swift-tools-version:5.3 +import PackageDescription + +let package = Package( + name: "TreeSitterD2", + products: [ + .library(name: "TreeSitterD2", targets: ["TreeSitterD2"]), + ], + dependencies: [], + targets: [ + .target(name: "TreeSitterD2", + path: ".", + exclude: [ + "Cargo.toml", + "Makefile", + "binding.gyp", + "bindings/c", + "bindings/go", + "bindings/node", + "bindings/python", + "bindings/rust", + "prebuilds", + "grammar.js", + "package.json", + "package-lock.json", + "pyproject.toml", + "setup.py", + "test", + "examples", + ".editorconfig", + ".github", + ".gitignore", + ".gitattributes", + ".gitmodules", + ], + sources: [ + "src/parser.c", + // NOTE: if your language has an external scanner, add it here. + ], + resources: [ + .copy("queries") + ], + publicHeadersPath: "bindings/swift", + cSettings: [.headerSearchPath("src")]) + ], + cLanguageStandard: .c11 +) diff --git a/README.md b/README.md index 1614ef7..c75fd1a 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ parser_config.d2 = { install_info = { url = 'https://git.pleshevski.ru/pleshevskiy/tree-sitter-d2', revision = 'main', - files = { 'src/parser.c', 'src/scanner.cc' }, + files = { 'src/parser.c', 'src/scanner.c' }, }, filetype = 'd2', }; diff --git a/binding.gyp b/binding.gyp index 493bc06..cd55f42 100644 --- a/binding.gyp +++ b/binding.gyp @@ -2,18 +2,29 @@ "targets": [ { "target_name": "tree_sitter_d2_binding", + "dependencies": [ + " -#include "nan.h" +#include -using namespace v8; +typedef struct TSLanguage TSLanguage; -extern "C" TSLanguage * tree_sitter_d2(); +extern "C" TSLanguage *tree_sitter_d2(); -namespace { +// "tree-sitter", "language" hashed with BLAKE2 +const napi_type_tag LANGUAGE_TYPE_TAG = { + 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16 +}; -NAN_METHOD(New) {} - -void Init(Local exports, Local module) { - Local tpl = Nan::New(New); - tpl->SetClassName(Nan::New("Language").ToLocalChecked()); - tpl->InstanceTemplate()->SetInternalFieldCount(1); - - Local constructor = Nan::GetFunction(tpl).ToLocalChecked(); - Local instance = constructor->NewInstance(Nan::GetCurrentContext()).ToLocalChecked(); - Nan::SetInternalFieldPointer(instance, 0, tree_sitter_d2()); - - Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("d2").ToLocalChecked()); - Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance); +Napi::Object Init(Napi::Env env, Napi::Object exports) { + exports["name"] = Napi::String::New(env, "d2"); + auto language = Napi::External::New(env, tree_sitter_d2()); + language.TypeTag(&LANGUAGE_TYPE_TAG); + exports["language"] = language; + return exports; } -NODE_MODULE(tree_sitter_d2_binding, Init) - -} // namespace +NODE_API_MODULE(tree_sitter_d2_binding, Init) diff --git a/bindings/node/index.d.ts b/bindings/node/index.d.ts new file mode 100644 index 0000000..efe259e --- /dev/null +++ b/bindings/node/index.d.ts @@ -0,0 +1,28 @@ +type BaseNode = { + type: string; + named: boolean; +}; + +type ChildNode = { + multiple: boolean; + required: boolean; + types: BaseNode[]; +}; + +type NodeInfo = + | (BaseNode & { + subtypes: BaseNode[]; + }) + | (BaseNode & { + fields: { [name: string]: ChildNode }; + children: ChildNode[]; + }); + +type Language = { + name: string; + language: unknown; + nodeTypeInfo: NodeInfo[]; +}; + +declare const language: Language; +export = language; diff --git a/bindings/node/index.js b/bindings/node/index.js index 46e96c8..6657bcf 100644 --- a/bindings/node/index.js +++ b/bindings/node/index.js @@ -1,18 +1,6 @@ -try { - module.exports = require("../../build/Release/tree_sitter_d2_binding"); -} catch (error1) { - if (error1.code !== 'MODULE_NOT_FOUND') { - throw error1; - } - try { - module.exports = require("../../build/Debug/tree_sitter_d2_binding"); - } catch (error2) { - if (error2.code !== 'MODULE_NOT_FOUND') { - throw error2; - } - throw error1 - } -} +const root = require("path").join(__dirname, "..", ".."); + +module.exports = require("node-gyp-build")(root); try { module.exports.nodeTypeInfo = require("../../src/node-types.json"); diff --git a/bindings/python/tree_sitter_d2/__init__.py b/bindings/python/tree_sitter_d2/__init__.py new file mode 100644 index 0000000..da12613 --- /dev/null +++ b/bindings/python/tree_sitter_d2/__init__.py @@ -0,0 +1,5 @@ +"D2 grammar for tree-sitter" + +from ._binding import language + +__all__ = ["language"] diff --git a/bindings/python/tree_sitter_d2/__init__.pyi b/bindings/python/tree_sitter_d2/__init__.pyi new file mode 100644 index 0000000..5416666 --- /dev/null +++ b/bindings/python/tree_sitter_d2/__init__.pyi @@ -0,0 +1 @@ +def language() -> int: ... diff --git a/bindings/python/tree_sitter_d2/binding.c b/bindings/python/tree_sitter_d2/binding.c new file mode 100644 index 0000000..33aa69c --- /dev/null +++ b/bindings/python/tree_sitter_d2/binding.c @@ -0,0 +1,27 @@ +#include + +typedef struct TSLanguage TSLanguage; + +TSLanguage *tree_sitter_d2(void); + +static PyObject* _binding_language(PyObject *self, PyObject *args) { + return PyLong_FromVoidPtr(tree_sitter_d2()); +} + +static PyMethodDef methods[] = { + {"language", _binding_language, METH_NOARGS, + "Get the tree-sitter language for this grammar."}, + {NULL, NULL, 0, NULL} +}; + +static struct PyModuleDef module = { + .m_base = PyModuleDef_HEAD_INIT, + .m_name = "_binding", + .m_doc = NULL, + .m_size = -1, + .m_methods = methods +}; + +PyMODINIT_FUNC PyInit__binding(void) { + return PyModule_Create(&module); +} diff --git a/bindings/python/tree_sitter_d2/py.typed b/bindings/python/tree_sitter_d2/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs index 618e90a..404fd0e 100644 --- a/bindings/rust/build.rs +++ b/bindings/rust/build.rs @@ -7,6 +7,9 @@ fn main() { .flag_if_supported("-Wno-unused-parameter") .flag_if_supported("-Wno-unused-but-set-variable") .flag_if_supported("-Wno-trigraphs"); + #[cfg(target_env = "msvc")] + c_config.flag("-utf-8"); + let parser_path = src_dir.join("parser.c"); c_config.file(&parser_path); @@ -31,7 +34,7 @@ fn main() { cpp_config .flag_if_supported("-Wno-unused-parameter") .flag_if_supported("-Wno-unused-but-set-variable"); - let scanner_path = src_dir.join("scanner.cc"); + let scanner_path = src_dir.join("scanner.c"); cpp_config.file(&scanner_path); cpp_config.compile("scanner"); println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); diff --git a/bindings/swift/TreeSitterD2/d2.h b/bindings/swift/TreeSitterD2/d2.h new file mode 100644 index 0000000..2dfaf8e --- /dev/null +++ b/bindings/swift/TreeSitterD2/d2.h @@ -0,0 +1,16 @@ +#ifndef TREE_SITTER_D2_H_ +#define TREE_SITTER_D2_H_ + +typedef struct TSLanguage TSLanguage; + +#ifdef __cplusplus +extern "C" { +#endif + +const TSLanguage *tree_sitter_d2(void); + +#ifdef __cplusplus +} +#endif + +#endif // TREE_SITTER_D2_H_ diff --git a/flake.lock b/flake.lock index 77f47b2..5b00bc9 100644 --- a/flake.lock +++ b/flake.lock @@ -32,16 +32,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1686736559, - "narHash": "sha256-YyUSVoOKIDAscTx7IZhF9x3qgZ9dPNF19fKk+4c5irc=", + "lastModified": 1720687749, + "narHash": "sha256-nqJ+iK/zyqCJ/YShqCpZ2cJKE1UtjZIEUWLUFZqvxcA=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "ddf4688dc7aeb14e8a3c549cb6aa6337f187a884", + "rev": "6af55cb91ca2005516b9562f707bb99c8f79bf77", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.05", + "ref": "nixpkgs-unstable", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index 7470b53..e6d9597 100644 --- a/flake.nix +++ b/flake.nix @@ -1,6 +1,6 @@ { inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; flake-utils.url = "github:numtide/flake-utils"; tools.url = "git+https://git.pleshevski.ru/mynix/tools"; }; diff --git a/grammar.js b/grammar.js index e8cb50b..506b939 100644 --- a/grammar.js +++ b/grammar.js @@ -31,7 +31,7 @@ const attrAlias = mkAlias(($) => $.attribute); // mkAttrCont :: ($ -> Rule) -> ($ -> Rule) -> $ -> Rule const mkAttrCont = (onValue) => (onKey) => ($) => - seq(onKey($), $._colon, onValue($)); + seq(onKey($), $.colon, onValue($)); const mkAttr = (onKey) => mkAttrCont(($) => $.attr_value)(attrKeyAlias(onKey)); const mkListAttr = (onKey) => mkAttrCont( @@ -98,7 +98,7 @@ module.exports = grammar({ $._full_connection_path, alias($._referencing_full_connection_path, $.referencing) ), - optional(seq($._colon, optional($.label))), + optional(seq($.colon, optional($.label))), optional(seq(alias($._connection_block, $.block))) ), @@ -132,7 +132,7 @@ module.exports = grammar({ choice( optional(seq($.dot, $._classes_item)), seq( - optional(seq($._colon, optional($.label))), + optional(seq($.colon, optional($.label))), optional(alias($._classes_block, $.block)) ) ) @@ -147,7 +147,7 @@ module.exports = grammar({ choice( optional(seq($.dot, $._shape_attribute)), seq( - optional(seq($._colon, optional($.label))), + optional(seq($.colon, optional($.label))), optional(alias($._classes_item_block, $.class_block)) ) ) @@ -169,7 +169,7 @@ module.exports = grammar({ choice( seq($.dot, choice($.shape, $.container)), seq( - optional(seq($._colon, optional($.label))), + optional(seq($.colon, optional($.label))), optional(alias($._container_block, $.block)) ) ) @@ -192,7 +192,7 @@ module.exports = grammar({ choice( seq($.dot, $._shape_attribute), seq( - $._colon, + $.colon, choice( $.label, seq( @@ -307,7 +307,7 @@ module.exports = grammar({ $.keyword_style, choice( seq($.dot, alias($._inner_style_attribute, $.attribute)), - seq($._colon, alias($._style_attribute_block, $.block)) + seq($.colon, alias($._style_attribute_block, $.block)) ) ) ), @@ -364,7 +364,7 @@ module.exports = grammar({ choice( seq($.dot, alias($._style_attribute, $.attribute)), seq( - optional(seq($._colon, optional($.label))), + optional(seq($.colon, optional($.label))), optional(seq(alias($._container_block, $.block))) ) ) @@ -393,7 +393,7 @@ module.exports = grammar({ _dash: ($) => token.immediate("-"), - _colon: ($) => token(":"), + colon: ($) => token(":"), arrow: ($) => token(prec(PREC.ARROW, choice(/-+>/, /--+/, /<-+/, /<-+>/))), @@ -444,7 +444,7 @@ module.exports = grammar({ /[0-7]{1,3}/, /x[0-9a-fA-F]{2}/, /u[0-9a-fA-F]{4}/, - /u{[0-9a-fA-F]+}/ + /u\{[0-9a-fA-F]+\}/ ) ) ), diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..243ab5c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "tree-sitter-d2", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "tree-sitter-d2", + "version": "1.0.0", + "license": "ISC" + } + } +} diff --git a/package.json b/package.json index 2b76bf5..de9857b 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "1.0.0", "description": "", "main": "grammar.js", + "types": "bindings/node", "author": "", "license": "ISC", "tree-sitter": [ @@ -13,5 +14,31 @@ ], "injection-regex": "^d2$" } + ], + "dependencies": { + "node-gyp-build": "^4.8.0" + }, + "peerDependencies": { + "tree-sitter": "^0.21.0" + }, + "peerDependenciesMeta": { + "tree_sitter": { + "optional": true + } + }, + "devDependencies": { + "prebuildify": "^6.0.0" + }, + "scripts": { + "install": "node-gyp-build", + "prebuildify": "prebuildify --napi --strip" + }, + "files": [ + "grammar.js", + "binding.gyp", + "prebuilds/**", + "bindings/node/*", + "queries/*", + "src/**" ] } diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..84ee9eb --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,29 @@ +[build-system] +requires = ["setuptools>=42", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "tree-sitter-d2" +description = "D2 grammar for tree-sitter" +version = "0.0.1" +keywords = ["incremental", "parsing", "tree-sitter", "d2"] +classifiers = [ + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Topic :: Software Development :: Compilers", + "Topic :: Text Processing :: Linguistic", + "Typing :: Typed" +] +requires-python = ">=3.8" +license.text = "MIT" +readme = "README.md" + +[project.urls] +Homepage = "https://github.com/tree-sitter/tree-sitter-d2" + +[project.optional-dependencies] +core = ["tree-sitter~=0.21"] + +[tool.cibuildwheel] +build = "cp38-*" +build-frontend = "build" diff --git a/queries/highlights.scm b/queries/highlights.scm index 63383e3..0c13680 100644 --- a/queries/highlights.scm +++ b/queries/highlights.scm @@ -43,7 +43,7 @@ [ (dot) - ":" + (colon) ";" ] @punctuation.delimiter diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..fa81c90 --- /dev/null +++ b/setup.py @@ -0,0 +1,60 @@ +from os.path import isdir, join +from platform import system + +from setuptools import Extension, find_packages, setup +from setuptools.command.build import build +from wheel.bdist_wheel import bdist_wheel + + +class Build(build): + def run(self): + if isdir("queries"): + dest = join(self.build_lib, "tree_sitter_d2", "queries") + self.copy_tree("queries", dest) + super().run() + + +class BdistWheel(bdist_wheel): + def get_tag(self): + python, abi, platform = super().get_tag() + if python.startswith("cp"): + python, abi = "cp38", "abi3" + return python, abi, platform + + +setup( + packages=find_packages("bindings/python"), + package_dir={"": "bindings/python"}, + package_data={ + "tree_sitter_d2": ["*.pyi", "py.typed"], + "tree_sitter_d2.queries": ["*.scm"], + }, + ext_package="tree_sitter_d2", + ext_modules=[ + Extension( + name="_binding", + sources=[ + "bindings/python/tree_sitter_d2/binding.c", + "src/parser.c", + # NOTE: if your language uses an external scanner, add it here. + ], + extra_compile_args=[ + "-std=c11", + ] if system() != "Windows" else [ + "/std:c11", + "/utf-8", + ], + define_macros=[ + ("Py_LIMITED_API", "0x03080000"), + ("PY_SSIZE_T_CLEAN", None) + ], + include_dirs=["src"], + py_limited_api=True, + ) + ], + cmdclass={ + "build": Build, + "bdist_wheel": BdistWheel + }, + zip_safe=False +) diff --git a/src/grammar.json b/src/grammar.json index e6a0560..6c548c7 100644 --- a/src/grammar.json +++ b/src/grammar.json @@ -94,7 +94,7 @@ "members": [ { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "CHOICE", @@ -367,7 +367,7 @@ "members": [ { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "CHOICE", @@ -521,7 +521,7 @@ "members": [ { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "CHOICE", @@ -701,7 +701,7 @@ "members": [ { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "CHOICE", @@ -868,7 +868,7 @@ "members": [ { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "CHOICE", @@ -1194,7 +1194,7 @@ }, { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "SYMBOL", @@ -1284,7 +1284,7 @@ }, { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "CHOICE", @@ -1394,7 +1394,7 @@ }, { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "CHOICE", @@ -1425,7 +1425,7 @@ }, { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "SYMBOL", @@ -1528,7 +1528,7 @@ "members": [ { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "ALIAS", @@ -1637,7 +1637,7 @@ }, { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "SYMBOL", @@ -1778,7 +1778,7 @@ }, { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "SYMBOL", @@ -1852,7 +1852,7 @@ "members": [ { "type": "SYMBOL", - "name": "_colon" + "name": "colon" }, { "type": "CHOICE", @@ -2109,7 +2109,7 @@ "value": "-" } }, - "_colon": { + "colon": { "type": "TOKEN", "content": { "type": "STRING", @@ -2279,7 +2279,7 @@ }, { "type": "PATTERN", - "value": "u{[0-9a-fA-F]+}" + "value": "u\\{[0-9a-fA-F]+\\}" } ] } @@ -2421,4 +2421,3 @@ "inline": [], "supertypes": [] } - diff --git a/src/node-types.json b/src/node-types.json index 5193755..2ccf8a6 100644 --- a/src/node-types.json +++ b/src/node-types.json @@ -96,6 +96,10 @@ "type": "class_name", "named": true }, + { + "type": "colon", + "named": true + }, { "type": "dot", "named": true @@ -135,6 +139,10 @@ "type": "class_name", "named": true }, + { + "type": "colon", + "named": true + }, { "type": "connection", "named": true @@ -240,6 +248,10 @@ "type": "class_name", "named": true }, + { + "type": "colon", + "named": true + }, { "type": "dot", "named": true @@ -271,6 +283,10 @@ "type": "block", "named": true }, + { + "type": "colon", + "named": true + }, { "type": "container_key", "named": true @@ -306,6 +322,10 @@ "type": "block", "named": true }, + { + "type": "colon", + "named": true + }, { "type": "container", "named": true @@ -438,6 +458,10 @@ "type": "block", "named": true }, + { + "type": "colon", + "named": true + }, { "type": "dot", "named": true @@ -605,6 +629,10 @@ "type": "border-radius", "named": false }, + { + "type": "colon", + "named": true + }, { "type": "constraint", "named": false diff --git a/src/parser.c b/src/parser.c index 497b52a27f99b5aef7c51d91a9d4c03a0b26daf3..8e0da7efcd86819f2c22fff63b3744a4e5c29667 100644 GIT binary patch delta 19383 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 OySvIHr$va_F8>8tPuRu) diff --git a/src/scanner.c b/src/scanner.c new file mode 100644 index 0000000..3b09e09 --- /dev/null +++ b/src/scanner.c @@ -0,0 +1,182 @@ +#include +#include +#include +#include +#include +#include + +enum TokenType { + TEXT_BLOCK_START, + TEXT_BLOCK_END, + TEXT_BLOCK_RAW_TEXT, + BLOCK_COMMENT, +}; + +typedef struct { + int16_t *escape_char_stack; + size_t escape_char_stack_size; + size_t escape_char_stack_capacity; +} Scanner; + +static void vector_push(Scanner *scanner, int16_t value) { + if (scanner->escape_char_stack_size == scanner->escape_char_stack_capacity) { + scanner->escape_char_stack_capacity = scanner->escape_char_stack_capacity * 2 + 1; + scanner->escape_char_stack = realloc(scanner->escape_char_stack, scanner->escape_char_stack_capacity * sizeof(int16_t)); + } + scanner->escape_char_stack[scanner->escape_char_stack_size++] = value; +} + +static void vector_clear(Scanner *scanner) { + scanner->escape_char_stack_size = 0; +} + +static void advance(TSLexer *lexer) { + lexer->advance(lexer, false); +} + +static void skip(TSLexer *lexer) { + lexer->advance(lexer, true); +} + +static void skip_whitespaces(TSLexer *lexer) { + while (lexer->lookahead != 0 && iswspace(lexer->lookahead)) { + skip(lexer); + } +} + +static bool is_text_block_end(Scanner *scanner, TSLexer *lexer) { + for (int i = scanner->escape_char_stack_size - 1; i >= 0; i--) { + if (lexer->lookahead != scanner->escape_char_stack[i]) { + return false; + } + advance(lexer); + } + return true; +} + +static bool is_triple_double_quote(TSLexer *lexer) { + for (int i = 0; i < 3; ++i) { + if (lexer->lookahead != '"') { + return false; + } + advance(lexer); + } + return true; +} + +static bool scan(void *payload, TSLexer *lexer, const bool *valid_symbols) { + Scanner *scanner = (Scanner *)payload; + + if (valid_symbols[TEXT_BLOCK_START] && scanner->escape_char_stack_size == 0) { + lexer->result_symbol = TEXT_BLOCK_START; + lexer->mark_end(lexer); + + skip_whitespaces(lexer); + + if (lexer->lookahead != '|') { + return false; + } + + advance(lexer); + vector_push(scanner, '|'); + + if (iswalnum(lexer->lookahead) || iswspace(lexer->lookahead)) { + lexer->mark_end(lexer); + return true; + } + + int16_t escape_char = lexer->lookahead; + while (lexer->lookahead == escape_char) { + vector_push(scanner, escape_char); + advance(lexer); + } + + lexer->mark_end(lexer); + + return true; + } else if (valid_symbols[TEXT_BLOCK_END] && scanner->escape_char_stack_size > 0) { + lexer->result_symbol = TEXT_BLOCK_END; + lexer->mark_end(lexer); + + skip_whitespaces(lexer); + + if (is_text_block_end(scanner, lexer)) { + lexer->mark_end(lexer); + vector_clear(scanner); + return true; + } + } else if (valid_symbols[TEXT_BLOCK_RAW_TEXT] && scanner->escape_char_stack_size > 0) { + lexer->result_symbol = TEXT_BLOCK_RAW_TEXT; + lexer->mark_end(lexer); + + while (lexer->lookahead != 0 && !is_text_block_end(scanner, lexer)) { + advance(lexer); + lexer->mark_end(lexer); + } + + return true; + } else if (valid_symbols[BLOCK_COMMENT]) { + lexer->result_symbol = BLOCK_COMMENT; + lexer->mark_end(lexer); + + skip_whitespaces(lexer); + // Check start of block comment + if (!is_triple_double_quote(lexer)) { + return false; + } + + // Search end of block comment + while (!is_triple_double_quote(lexer)) { + // d2 expects closed tag for block comment + if (lexer->lookahead == 0) return false; + advance(lexer); + } + + lexer->mark_end(lexer); + + return true; + } + + return false; +} + +void *tree_sitter_d2_external_scanner_create() { + Scanner *scanner = calloc(1, sizeof(Scanner)); + scanner->escape_char_stack_capacity = 10; + scanner->escape_char_stack = malloc(scanner->escape_char_stack_capacity * sizeof(int16_t)); + return scanner; +} + +bool tree_sitter_d2_external_scanner_scan(void *payload, TSLexer *lexer, const bool *valid_symbols) { + return scan(payload, lexer, valid_symbols); +} + +unsigned tree_sitter_d2_external_scanner_serialize(void *payload, char *buffer) { + Scanner *scanner = (Scanner *)payload; + size_t i = 0; + buffer[i++] = scanner->escape_char_stack_size; + + for (size_t j = 0; j < scanner->escape_char_stack_size && i < TREE_SITTER_SERIALIZATION_BUFFER_SIZE; ++j) { + buffer[i++] = scanner->escape_char_stack[j]; + } + + return i; +} + +void tree_sitter_d2_external_scanner_deserialize(void *payload, const char *buffer, unsigned length) { + Scanner *scanner = (Scanner *)payload; + vector_clear(scanner); + if (length == 0) return; + size_t i = 0; + size_t escape_char_count = (uint8_t)buffer[i++]; + for (; i < escape_char_count + 1 && i < length; i++) { + vector_push(scanner, buffer[i]); + } +} + +void tree_sitter_d2_external_scanner_destroy(void *payload) { + Scanner *scanner = (Scanner *)payload; + free(scanner->escape_char_stack); + free(scanner); +} + diff --git a/src/tree_sitter/alloc.h b/src/tree_sitter/alloc.h new file mode 100644 index 0000000..1f4466d --- /dev/null +++ b/src/tree_sitter/alloc.h @@ -0,0 +1,54 @@ +#ifndef TREE_SITTER_ALLOC_H_ +#define TREE_SITTER_ALLOC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +// Allow clients to override allocation functions +#ifdef TREE_SITTER_REUSE_ALLOCATOR + +extern void *(*ts_current_malloc)(size_t); +extern void *(*ts_current_calloc)(size_t, size_t); +extern void *(*ts_current_realloc)(void *, size_t); +extern void (*ts_current_free)(void *); + +#ifndef ts_malloc +#define ts_malloc ts_current_malloc +#endif +#ifndef ts_calloc +#define ts_calloc ts_current_calloc +#endif +#ifndef ts_realloc +#define ts_realloc ts_current_realloc +#endif +#ifndef ts_free +#define ts_free ts_current_free +#endif + +#else + +#ifndef ts_malloc +#define ts_malloc malloc +#endif +#ifndef ts_calloc +#define ts_calloc calloc +#endif +#ifndef ts_realloc +#define ts_realloc realloc +#endif +#ifndef ts_free +#define ts_free free +#endif + +#endif + +#ifdef __cplusplus +} +#endif + +#endif // TREE_SITTER_ALLOC_H_ diff --git a/src/tree_sitter/array.h b/src/tree_sitter/array.h new file mode 100644 index 0000000..15a3b23 --- /dev/null +++ b/src/tree_sitter/array.h @@ -0,0 +1,290 @@ +#ifndef TREE_SITTER_ARRAY_H_ +#define TREE_SITTER_ARRAY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include "./alloc.h" + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(disable : 4101) +#elif defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif + +#define Array(T) \ + struct { \ + T *contents; \ + uint32_t size; \ + uint32_t capacity; \ + } + +/// Initialize an array. +#define array_init(self) \ + ((self)->size = 0, (self)->capacity = 0, (self)->contents = NULL) + +/// Create an empty array. +#define array_new() \ + { NULL, 0, 0 } + +/// Get a pointer to the element at a given `index` in the array. +#define array_get(self, _index) \ + (assert((uint32_t)(_index) < (self)->size), &(self)->contents[_index]) + +/// Get a pointer to the first element in the array. +#define array_front(self) array_get(self, 0) + +/// Get a pointer to the last element in the array. +#define array_back(self) array_get(self, (self)->size - 1) + +/// Clear the array, setting its size to zero. Note that this does not free any +/// memory allocated for the array's contents. +#define array_clear(self) ((self)->size = 0) + +/// Reserve `new_capacity` elements of space in the array. If `new_capacity` is +/// less than the array's current capacity, this function has no effect. +#define array_reserve(self, new_capacity) \ + _array__reserve((Array *)(self), array_elem_size(self), new_capacity) + +/// Free any memory allocated for this array. Note that this does not free any +/// memory allocated for the array's contents. +#define array_delete(self) _array__delete((Array *)(self)) + +/// Push a new `element` onto the end of the array. +#define array_push(self, element) \ + (_array__grow((Array *)(self), 1, array_elem_size(self)), \ + (self)->contents[(self)->size++] = (element)) + +/// Increase the array's size by `count` elements. +/// New elements are zero-initialized. +#define array_grow_by(self, count) \ + do { \ + if ((count) == 0) break; \ + _array__grow((Array *)(self), count, array_elem_size(self)); \ + memset((self)->contents + (self)->size, 0, (count) * array_elem_size(self)); \ + (self)->size += (count); \ + } while (0) + +/// Append all elements from one array to the end of another. +#define array_push_all(self, other) \ + array_extend((self), (other)->size, (other)->contents) + +/// Append `count` elements to the end of the array, reading their values from the +/// `contents` pointer. +#define array_extend(self, count, contents) \ + _array__splice( \ + (Array *)(self), array_elem_size(self), (self)->size, \ + 0, count, contents \ + ) + +/// Remove `old_count` elements from the array starting at the given `index`. At +/// the same index, insert `new_count` new elements, reading their values from the +/// `new_contents` pointer. +#define array_splice(self, _index, old_count, new_count, new_contents) \ + _array__splice( \ + (Array *)(self), array_elem_size(self), _index, \ + old_count, new_count, new_contents \ + ) + +/// Insert one `element` into the array at the given `index`. +#define array_insert(self, _index, element) \ + _array__splice((Array *)(self), array_elem_size(self), _index, 0, 1, &(element)) + +/// Remove one element from the array at the given `index`. +#define array_erase(self, _index) \ + _array__erase((Array *)(self), array_elem_size(self), _index) + +/// Pop the last element off the array, returning the element by value. +#define array_pop(self) ((self)->contents[--(self)->size]) + +/// Assign the contents of one array to another, reallocating if necessary. +#define array_assign(self, other) \ + _array__assign((Array *)(self), (const Array *)(other), array_elem_size(self)) + +/// Swap one array with another +#define array_swap(self, other) \ + _array__swap((Array *)(self), (Array *)(other)) + +/// Get the size of the array contents +#define array_elem_size(self) (sizeof *(self)->contents) + +/// Search a sorted array for a given `needle` value, using the given `compare` +/// callback to determine the order. +/// +/// If an existing element is found to be equal to `needle`, then the `index` +/// out-parameter is set to the existing value's index, and the `exists` +/// out-parameter is set to true. Otherwise, `index` is set to an index where +/// `needle` should be inserted in order to preserve the sorting, and `exists` +/// is set to false. +#define array_search_sorted_with(self, compare, needle, _index, _exists) \ + _array__search_sorted(self, 0, compare, , needle, _index, _exists) + +/// Search a sorted array for a given `needle` value, using integer comparisons +/// of a given struct field (specified with a leading dot) to determine the order. +/// +/// See also `array_search_sorted_with`. +#define array_search_sorted_by(self, field, needle, _index, _exists) \ + _array__search_sorted(self, 0, _compare_int, field, needle, _index, _exists) + +/// Insert a given `value` into a sorted array, using the given `compare` +/// callback to determine the order. +#define array_insert_sorted_with(self, compare, value) \ + do { \ + unsigned _index, _exists; \ + array_search_sorted_with(self, compare, &(value), &_index, &_exists); \ + if (!_exists) array_insert(self, _index, value); \ + } while (0) + +/// Insert a given `value` into a sorted array, using integer comparisons of +/// a given struct field (specified with a leading dot) to determine the order. +/// +/// See also `array_search_sorted_by`. +#define array_insert_sorted_by(self, field, value) \ + do { \ + unsigned _index, _exists; \ + array_search_sorted_by(self, field, (value) field, &_index, &_exists); \ + if (!_exists) array_insert(self, _index, value); \ + } while (0) + +// Private + +typedef Array(void) Array; + +/// This is not what you're looking for, see `array_delete`. +static inline void _array__delete(Array *self) { + if (self->contents) { + ts_free(self->contents); + self->contents = NULL; + self->size = 0; + self->capacity = 0; + } +} + +/// This is not what you're looking for, see `array_erase`. +static inline void _array__erase(Array *self, size_t element_size, + uint32_t index) { + assert(index < self->size); + char *contents = (char *)self->contents; + memmove(contents + index * element_size, contents + (index + 1) * element_size, + (self->size - index - 1) * element_size); + self->size--; +} + +/// This is not what you're looking for, see `array_reserve`. +static inline void _array__reserve(Array *self, size_t element_size, uint32_t new_capacity) { + if (new_capacity > self->capacity) { + if (self->contents) { + self->contents = ts_realloc(self->contents, new_capacity * element_size); + } else { + self->contents = ts_malloc(new_capacity * element_size); + } + self->capacity = new_capacity; + } +} + +/// This is not what you're looking for, see `array_assign`. +static inline void _array__assign(Array *self, const Array *other, size_t element_size) { + _array__reserve(self, element_size, other->size); + self->size = other->size; + memcpy(self->contents, other->contents, self->size * element_size); +} + +/// This is not what you're looking for, see `array_swap`. +static inline void _array__swap(Array *self, Array *other) { + Array swap = *other; + *other = *self; + *self = swap; +} + +/// This is not what you're looking for, see `array_push` or `array_grow_by`. +static inline void _array__grow(Array *self, uint32_t count, size_t element_size) { + uint32_t new_size = self->size + count; + if (new_size > self->capacity) { + uint32_t new_capacity = self->capacity * 2; + if (new_capacity < 8) new_capacity = 8; + if (new_capacity < new_size) new_capacity = new_size; + _array__reserve(self, element_size, new_capacity); + } +} + +/// This is not what you're looking for, see `array_splice`. +static inline void _array__splice(Array *self, size_t element_size, + uint32_t index, uint32_t old_count, + uint32_t new_count, const void *elements) { + uint32_t new_size = self->size + new_count - old_count; + uint32_t old_end = index + old_count; + uint32_t new_end = index + new_count; + assert(old_end <= self->size); + + _array__reserve(self, element_size, new_size); + + char *contents = (char *)self->contents; + if (self->size > old_end) { + memmove( + contents + new_end * element_size, + contents + old_end * element_size, + (self->size - old_end) * element_size + ); + } + if (new_count > 0) { + if (elements) { + memcpy( + (contents + index * element_size), + elements, + new_count * element_size + ); + } else { + memset( + (contents + index * element_size), + 0, + new_count * element_size + ); + } + } + self->size += new_count - old_count; +} + +/// A binary search routine, based on Rust's `std::slice::binary_search_by`. +/// This is not what you're looking for, see `array_search_sorted_with` or `array_search_sorted_by`. +#define _array__search_sorted(self, start, compare, suffix, needle, _index, _exists) \ + do { \ + *(_index) = start; \ + *(_exists) = false; \ + uint32_t size = (self)->size - *(_index); \ + if (size == 0) break; \ + int comparison; \ + while (size > 1) { \ + uint32_t half_size = size / 2; \ + uint32_t mid_index = *(_index) + half_size; \ + comparison = compare(&((self)->contents[mid_index] suffix), (needle)); \ + if (comparison <= 0) *(_index) = mid_index; \ + size -= half_size; \ + } \ + comparison = compare(&((self)->contents[*(_index)] suffix), (needle)); \ + if (comparison == 0) *(_exists) = true; \ + else if (comparison < 0) *(_index) += 1; \ + } while (0) + +/// Helper macro for the `_sorted_by` routines below. This takes the left (existing) +/// parameter by reference in order to work with the generic sorting function above. +#define _compare_int(a, b) ((int)*(a) - (int)(b)) + +#ifdef _MSC_VER +#pragma warning(default : 4101) +#elif defined(__GNUC__) || defined(__clang__) +#pragma GCC diagnostic pop +#endif + +#ifdef __cplusplus +} +#endif + +#endif // TREE_SITTER_ARRAY_H_ diff --git a/src/tree_sitter/parser.h b/src/tree_sitter/parser.h index 2b14ac1..17f0e94 100644 --- a/src/tree_sitter/parser.h +++ b/src/tree_sitter/parser.h @@ -13,9 +13,8 @@ extern "C" { #define ts_builtin_sym_end 0 #define TREE_SITTER_SERIALIZATION_BUFFER_SIZE 1024 -typedef uint16_t TSStateId; - #ifndef TREE_SITTER_API_H_ +typedef uint16_t TSStateId; typedef uint16_t TSSymbol; typedef uint16_t TSFieldId; typedef struct TSLanguage TSLanguage; @@ -87,6 +86,11 @@ typedef union { } entry; } TSParseActionEntry; +typedef struct { + int32_t start; + int32_t end; +} TSCharacterRange; + struct TSLanguage { uint32_t version; uint32_t symbol_count; @@ -126,13 +130,38 @@ struct TSLanguage { const TSStateId *primary_state_ids; }; +static inline bool set_contains(TSCharacterRange *ranges, uint32_t len, int32_t lookahead) { + uint32_t index = 0; + uint32_t size = len - index; + while (size > 1) { + uint32_t half_size = size / 2; + uint32_t mid_index = index + half_size; + TSCharacterRange *range = &ranges[mid_index]; + if (lookahead >= range->start && lookahead <= range->end) { + return true; + } else if (lookahead > range->end) { + index = mid_index; + } + size -= half_size; + } + TSCharacterRange *range = &ranges[index]; + return (lookahead >= range->start && lookahead <= range->end); +} + /* * Lexer Macros */ +#ifdef _MSC_VER +#define UNUSED __pragma(warning(suppress : 4101)) +#else +#define UNUSED __attribute__((unused)) +#endif + #define START_LEXER() \ bool result = false; \ bool skip = false; \ + UNUSED \ bool eof = false; \ int32_t lookahead; \ goto start; \ @@ -148,6 +177,17 @@ struct TSLanguage { goto next_state; \ } +#define ADVANCE_MAP(...) \ + { \ + static const uint16_t map[] = { __VA_ARGS__ }; \ + for (uint32_t i = 0; i < sizeof(map) / sizeof(map[0]); i += 2) { \ + if (map[i] == lookahead) { \ + state = map[i + 1]; \ + goto next_state; \ + } \ + } \ + } + #define SKIP(state_value) \ { \ skip = true; \ @@ -166,7 +206,7 @@ struct TSLanguage { * Parse Table Macros */ -#define SMALL_STATE(id) id - LARGE_STATE_COUNT +#define SMALL_STATE(id) ((id) - LARGE_STATE_COUNT) #define STATE(id) id @@ -176,7 +216,7 @@ struct TSLanguage { {{ \ .shift = { \ .type = TSParseActionTypeShift, \ - .state = state_value \ + .state = (state_value) \ } \ }} @@ -184,7 +224,7 @@ struct TSLanguage { {{ \ .shift = { \ .type = TSParseActionTypeShift, \ - .state = state_value, \ + .state = (state_value), \ .repetition = true \ } \ }} @@ -197,14 +237,15 @@ struct TSLanguage { } \ }} -#define REDUCE(symbol_val, child_count_val, ...) \ - {{ \ - .reduce = { \ - .type = TSParseActionTypeReduce, \ - .symbol = symbol_val, \ - .child_count = child_count_val, \ - __VA_ARGS__ \ - }, \ +#define REDUCE(symbol_name, children, precedence, prod_id) \ + {{ \ + .reduce = { \ + .type = TSParseActionTypeReduce, \ + .symbol = symbol_name, \ + .child_count = children, \ + .dynamic_precedence = precedence, \ + .production_id = prod_id \ + }, \ }} #define RECOVER() \ diff --git a/test/corpus/attributes.txt b/test/corpus/attributes.txt index 0915414..9a034dd 100644 --- a/test/corpus/attributes.txt +++ b/test/corpus/attributes.txt @@ -25,26 +25,26 @@ near: abc -------------------------------------------------------------------------------- (source_file - (attribute (attr_key) (attr_value)) + (attribute (attr_key) (colon) (attr_value)) - (attribute (attr_key (reserved)) (attr_value)) - (attribute (attr_key (reserved)) (attr_value (string (string_fragment)))) - (attribute (attr_key (reserved)) (attr_value)) - (attribute (attr_key (reserved)) (attr_value)) - (attribute (attr_key (reserved)) (attr_value (float))) - (attribute (attr_key (reserved)) (attr_value)) - (attribute (attr_key (reserved)) (attr_value)) - (attribute (attr_key (reserved)) (attr_value (integer))) - (attribute (attr_key (reserved)) (attr_value (integer))) - (attribute (attr_key (reserved)) (attr_value (integer))) - (attribute (attr_key (reserved)) (attr_value)) - (attribute (attr_key (reserved)) (attr_value (integer))) - (attribute (attr_key (reserved)) (attr_value)) - (attribute (attr_key (reserved)) (attr_value (boolean))) - (attribute (attr_key (reserved)) (attr_value (boolean))) - (attribute (attr_key (reserved)) (attr_value (boolean))) - (attribute (attr_key (reserved)) (attr_value)) - (attribute (attr_key (reserved)) (attr_value)) + (attribute (attr_key (reserved)) (colon) (attr_value)) + (attribute (attr_key (reserved)) (colon) (attr_value (string (string_fragment)))) + (attribute (attr_key (reserved)) (colon) (attr_value)) + (attribute (attr_key (reserved)) (colon) (attr_value)) + (attribute (attr_key (reserved)) (colon) (attr_value (float))) + (attribute (attr_key (reserved)) (colon) (attr_value)) + (attribute (attr_key (reserved)) (colon) (attr_value)) + (attribute (attr_key (reserved)) (colon) (attr_value (integer))) + (attribute (attr_key (reserved)) (colon) (attr_value (integer))) + (attribute (attr_key (reserved)) (colon) (attr_value (integer))) + (attribute (attr_key (reserved)) (colon) (attr_value)) + (attribute (attr_key (reserved)) (colon) (attr_value (integer))) + (attribute (attr_key (reserved)) (colon) (attr_value)) + (attribute (attr_key (reserved)) (colon) (attr_value (boolean))) + (attribute (attr_key (reserved)) (colon) (attr_value (boolean))) + (attribute (attr_key (reserved)) (colon) (attr_value (boolean))) + (attribute (attr_key (reserved)) (colon) (attr_value)) + (attribute (attr_key (reserved)) (colon) (attr_value)) ) ================================================================================ @@ -66,18 +66,18 @@ foo.style.text-transform: uppercase -------------------------------------------------------------------------------- (source_file - (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (float))))) - (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value)))) - (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value)))) - (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (integer))))) - (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (integer))))) - (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (integer))))) - (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value)))) - (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (boolean))))) - (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (boolean))))) - (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (boolean))))) - (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value)))) - (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value)))) + (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (float))))) + (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value)))) + (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value)))) + (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (integer))))) + (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (integer))))) + (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (integer))))) + (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value)))) + (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (boolean))))) + (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (boolean))))) + (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (boolean))))) + (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value)))) + (shape (shape_key) (dot) (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value)))) ) ================================================================================ @@ -105,19 +105,20 @@ foo.style: { (shape_key) (dot) (attribute (keyword_style) + (colon) (block - (attribute (attr_key) (attr_value (float))) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (boolean))) - (attribute (attr_key) (attr_value (boolean))) - (attribute (attr_key) (attr_value (boolean))) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value)) + (attribute (attr_key) (colon) (attr_value (float))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (boolean))) + (attribute (attr_key) (colon) (attr_value (boolean))) + (attribute (attr_key) (colon) (attr_value (boolean))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value)) ) ) ) @@ -142,15 +143,16 @@ foo: { (source_file (container (container_key) + (colon) (block - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (string (string_fragment)))) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (escape_sequence))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (string (string_fragment)))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (escape_sequence))) ) ) ) @@ -177,18 +179,19 @@ foo: { (source_file (container (container_key) + (colon) (block - (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (float)))) - (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value))) - (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value))) - (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (integer)))) - (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (integer)))) - (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (integer)))) - (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value))) - (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (boolean)))) - (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (boolean)))) - (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value (boolean)))) - (attribute (keyword_style) (dot) (attribute (attr_key) (attr_value))) + (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (float)))) + (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value))) + (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value))) + (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (integer)))) + (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (integer)))) + (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (integer)))) + (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value))) + (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (boolean)))) + (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (boolean)))) + (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value (boolean)))) + (attribute (keyword_style) (dot) (attribute (attr_key) (colon) (attr_value))) ) ) ) @@ -217,21 +220,23 @@ foo: { (source_file (container (container_key) + (colon) (block (attribute (keyword_style) + (colon) (block - (attribute (attr_key) (attr_value (float))) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (boolean))) - (attribute (attr_key) (attr_value (boolean))) - (attribute (attr_key) (attr_value (boolean))) - (attribute (attr_key) (attr_value)) + (attribute (attr_key) (colon) (attr_value (float))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (boolean))) + (attribute (attr_key) (colon) (attr_value (boolean))) + (attribute (attr_key) (colon) (attr_value (boolean))) + (attribute (attr_key) (colon) (attr_value)) ) ) ) @@ -264,21 +269,23 @@ foo -> bar: { (shape_key) (arrow) (shape_key) + (colon) (block (attribute (keyword_style) + (colon) (block - (attribute (attr_key) (attr_value (float))) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (boolean))) - (attribute (attr_key) (attr_value (boolean))) - (attribute (attr_key) (attr_value (boolean))) - (attribute (attr_key) (attr_value)) + (attribute (attr_key) (colon) (attr_value (float))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (boolean))) + (attribute (attr_key) (colon) (attr_value (boolean))) + (attribute (attr_key) (colon) (attr_value (boolean))) + (attribute (attr_key) (colon) (attr_value)) ) ) ) @@ -300,15 +307,10 @@ foo -> bar: { (shape_key) (arrow) (shape_key) + (colon) (block - (attribute - (attr_key) - (label) - ) - (attribute - (attr_key) - (label) - ) + (attribute (attr_key) (colon) (label)) + (attribute (attr_key) (colon) (label)) ) ) ) @@ -325,15 +327,10 @@ foo -> bar: {source-arrowhead: 0; target-arrowhead: 1} (shape_key) (arrow) (shape_key) + (colon) (block - (attribute - (attr_key) - (label) - ) - (attribute - (attr_key) - (label) - ) + (attribute (attr_key) (colon) (label)) + (attribute (attr_key) (colon) (label)) ) ) ) @@ -366,24 +363,27 @@ foo -> bar: { (shape_key) (arrow) (shape_key) + (colon) (block (attribute (attr_key) + (colon) (block (attribute (keyword_style) + (colon) (block - (attribute (attr_key) (attr_value (float))) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (boolean))) - (attribute (attr_key) (attr_value (boolean))) - (attribute (attr_key) (attr_value (boolean))) - (attribute (attr_key) (attr_value)) + (attribute (attr_key) (colon) (attr_value (float))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (boolean))) + (attribute (attr_key) (colon) (attr_value (boolean))) + (attribute (attr_key) (colon) (attr_value (boolean))) + (attribute (attr_key) (colon) (attr_value)) ) ) ) @@ -413,16 +413,18 @@ foo -> bar: { (shape_key) (arrow) (shape_key) + (colon) (block (attribute (attr_key) + (colon) (block - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (string (string_fragment)))) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (string (string_fragment)))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) ) ) ) @@ -441,9 +443,10 @@ foo.style: {opacity: 0.5; fill: red} (shape_key) (dot) (attribute (keyword_style) + (colon) (block - (attribute (attr_key) (attr_value (float))) - (attribute (attr_key) (attr_value)) + (attribute (attr_key) (colon) (attr_value (float))) + (attribute (attr_key) (colon) (attr_value)) ) ) ) @@ -471,16 +474,17 @@ footer -------------------------------------------------------------------------------- (source_file - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) (shape (shape_key)) (container (container_key) + (colon) (label (string)) (block - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) - (attribute (attr_key) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) + (attribute (attr_key) (colon) (attr_value (integer))) (shape (shape_key)) (shape (shape_key)) ) @@ -506,11 +510,12 @@ block: { (source_file (container (container_key) + (colon) (block - (attribute (attr_key) (attr_value)) - (attribute (attr_key) (attr_value_list (attr_value))) - (attribute (attr_key) (attr_value_list (attr_value) (attr_value))) - (attribute (attr_key) (attr_value_list (attr_value) (attr_value))) + (attribute (attr_key) (colon) (attr_value)) + (attribute (attr_key) (colon) (attr_value_list (attr_value))) + (attribute (attr_key) (colon) (attr_value_list (attr_value) (attr_value))) + (attribute (attr_key) (colon) (attr_value_list (attr_value) (attr_value))) ) ) ) diff --git a/test/corpus/classes.txt b/test/corpus/classes.txt index c29122c..a996f48 100644 --- a/test/corpus/classes.txt +++ b/test/corpus/classes.txt @@ -25,14 +25,18 @@ classes: { (source_file (classes (keyword_classes) + (colon) (block (class_name) + (colon) (class_block (attribute (keyword_style) + (colon) (block (attribute (attr_key) + (colon) (attr_value (string (string_fragment)) ) @@ -58,14 +62,17 @@ classes: { (source_file (classes (keyword_classes) + (colon) (block (class_name) (dot) (attribute (keyword_style) + (colon) (block (attribute (attr_key) + (colon) (attr_value (string (string_fragment)) ) @@ -93,9 +100,11 @@ classes.foo.style: { (dot) (attribute (keyword_style) + (colon) (block (attribute (attr_key) + (colon) (attr_value (string (string_fragment)) ) @@ -121,12 +130,15 @@ classes.foo: { (keyword_classes) (dot) (class_name) + (colon) (class_block (attribute (keyword_style) + (colon) (block (attribute (attr_key) + (colon) (attr_value (string (string_fragment)) ) @@ -150,6 +162,7 @@ foo.class: biz (dot) (attribute (keyword_class) + (colon) (class_name) ) ) @@ -169,6 +182,7 @@ foo.class: [biz; baz] (dot) (attribute (keyword_class) + (colon) (class_list (class_name) ) @@ -179,6 +193,7 @@ foo.class: [biz; baz] (dot) (attribute (keyword_class) + (colon) (class_list (class_name) (class_name) @@ -205,19 +220,23 @@ foo: { (source_file (container (container_key) + (colon) (block (attribute (keyword_class) + (colon) (class_name) ) (attribute (keyword_class) + (colon) (class_list (class_name) ) ) (attribute (keyword_class) + (colon) (class_list (class_name) (class_name) @@ -225,6 +244,7 @@ foo: { ) (attribute (keyword_class) + (colon) (class_list (class_name) (class_name) diff --git a/test/corpus/connection.txt b/test/corpus/connection.txt index 4c68529..3d1790a 100644 --- a/test/corpus/connection.txt +++ b/test/corpus/connection.txt @@ -175,12 +175,14 @@ bar -> baz: Yes (shape_key) (arrow) (shape_key) + (colon) (label) ) (connection (shape_key) (arrow) (shape_key) + (colon) (label) ) ) @@ -197,6 +199,7 @@ foo.biz.baz -> bar.baz.biz: Label (container_key) (dot) (container_key) (dot) (shape_key) (arrow) (container_key) (dot) (container_key) (dot) (shape_key) + (colon) (label) ) ) @@ -215,11 +218,13 @@ foo.baz: { (container_key) (dot) (container (container_key) + (colon) (block (connection (shape_key) (arrow) (shape_key) + (colon) (label) ) ) @@ -270,7 +275,7 @@ Diclare a connection with espaced key fragments ) ================================================================================ -Declare a referencing connection +Declare a referencing connection ================================================================================ (x() -> y()) (x() -> y())[0] @@ -310,6 +315,7 @@ Declare a referencing connection with label (arrow) (shape_key) ) + (colon) (label) ) (connection @@ -319,6 +325,7 @@ Declare a referencing connection with label (shape_key) (index (integer)) ) + (colon) (label) ) ) @@ -342,12 +349,14 @@ Declare a referencing connection with block (arrow) (shape_key) ) + (colon) (block (attribute (keyword_style) (dot) (attribute (attr_key) + (colon) (attr_value (escape_sequence) ) @@ -362,12 +371,14 @@ Declare a referencing connection with block (shape_key) (index (integer)) ) + (colon) (block (attribute (keyword_style) (dot) (attribute (attr_key) + (colon) (attr_value (escape_sequence) ) diff --git a/test/corpus/container.txt b/test/corpus/container.txt index 5742d7a..11add4a 100644 --- a/test/corpus/container.txt +++ b/test/corpus/container.txt @@ -51,12 +51,15 @@ foo: { (source_file (container (container_key) + (colon) (block (container (container_key) + (colon) (block (container (container_key) + (colon) (block (shape (shape_key)) ) @@ -84,17 +87,20 @@ foo: Foo { (source_file (container (container_key) + (colon) (label) (block (container (container_key) + (colon) (label) (block (container (container_key) + (colon) (label) (block - (shape (shape_key) (label)) + (shape (shape_key) (colon) (label)) ) ) ) @@ -118,6 +124,7 @@ foo: { (source_file (container (container_key) + (colon) (block (shape (shape_key)) (shape (shape_key)) @@ -144,12 +151,15 @@ Foo biz bar: { (source_file (container (container_key) + (colon) (block (container (container_key) + (colon) (block (container (container_key) + (colon) (block (shape (shape_key)) ) @@ -177,14 +187,17 @@ Foo biz bar: Biz biz Bar { (source_file (container (container_key) + (colon) (label) (block (container (container_key) + (colon) (label) (block (container (container_key) + (colon) (label) (block (shape (shape_key)) @@ -216,6 +229,7 @@ Foo: Baz { (source_file (container (container_key) + (colon) (label) (block (shape (shape_key)) @@ -241,10 +255,12 @@ primty: Primitive types { (source_file (container (container_key) + (colon) (label) (block (container (container_key) + (colon) (block (shape (shape_key (string (string_fragment))) @@ -253,12 +269,14 @@ primty: Primitive types { ) (container (container_key) + (colon) (block (shape (shape_key)) ) ) (container (container_key) + (colon) (block (shape (shape_key)) (shape (shape_key)) @@ -280,11 +298,12 @@ container: { (source_file (container (container_key) + (colon) (block (container (container_key (keyword_underscore)) (dot) - (shape (shape_key) (label)) + (shape (shape_key) (colon) (label)) ) ) ) diff --git a/test/corpus/shape.txt b/test/corpus/shape.txt index 6ef4ba0..b8dc65e 100644 --- a/test/corpus/shape.txt +++ b/test/corpus/shape.txt @@ -55,7 +55,7 @@ bar ================================================================================ Complex shape key ================================================================================ - Foo bar + Foo bar -Biz-baz- imAShape im_a$_shape @@ -129,9 +129,9 @@ a: Foo Bar; b: Biz Baz -------------------------------------------------------------------------------- (source_file - (shape (shape_key) (label)) - (shape (shape_key) (label)) - (shape (shape_key) (label)) + (shape (shape_key) (colon) (label)) + (shape (shape_key) (colon) (label)) + (shape (shape_key) (colon) (label)) ) ================================================================================ @@ -143,9 +143,9 @@ a: Foo\nB\@r; b: Biz\nBaz -------------------------------------------------------------------------------- (source_file - (shape (shape_key) (label (escape_sequence) (escape_sequence))) - (shape (shape_key) (label (escape_sequence) (escape_sequence))) - (shape (shape_key) (label (escape_sequence))) + (shape (shape_key) (colon) (label (escape_sequence) (escape_sequence))) + (shape (shape_key) (colon) (label (escape_sequence) (escape_sequence))) + (shape (shape_key) (colon) (label (escape_sequence))) ) @@ -161,7 +161,7 @@ bar : Foo Bar; baz (source_file (shape (shape_key)) - (shape (shape_key) (label)) + (shape (shape_key) (colon) (label)) (shape (shape_key)) ) @@ -175,6 +175,7 @@ Use quoted string as shape key and label (source_file (shape (shape_key (string (string_fragment))) + (colon) (label (string (string_fragment)))) ) @@ -190,6 +191,7 @@ foo: | (source_file (shape (shape_key) + (colon) (text_block (raw_text) ) @@ -216,6 +218,7 @@ foo: |go (source_file (shape (shape_key) + (colon) (text_block (language) (raw_text) @@ -243,6 +246,7 @@ $$$| (source_file (shape (shape_key) + (colon) (text_block (language) (raw_text) @@ -262,12 +266,14 @@ bar: |##md ## hello world ##| (source_file (shape (shape_key) + (colon) (text_block (raw_text) ) ) (shape (shape_key) + (colon) (text_block (language) (raw_text) diff --git a/tree-sitter-d2.wasm b/tree-sitter-d2.wasm index 3efa1ad5475b486378e5375dbb74fba4582a2fd4..a135dca7d748cda52dfa4aacdd77418dd1c07536 100755 GIT binary patch literal 66396 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 SWIIS(@Oz+MJ@nm(-~R)7KLWA<