diff options
Diffstat (limited to 'bindings')
| -rw-r--r-- | bindings/c/tree-sitter-wmap.pc.in | 10 | ||||
| -rw-r--r-- | bindings/c/tree_sitter/tree-sitter-wmap.h | 16 | ||||
| -rw-r--r-- | bindings/go/binding.go | 15 | ||||
| -rw-r--r-- | bindings/go/binding_test.go | 15 | ||||
| -rw-r--r-- | bindings/node/binding.cc | 19 | ||||
| -rw-r--r-- | bindings/node/binding_test.js | 11 | ||||
| -rw-r--r-- | bindings/node/index.d.ts | 60 | ||||
| -rw-r--r-- | bindings/node/index.js | 37 | ||||
| -rw-r--r-- | bindings/python/tests/test_binding.py | 12 | ||||
| -rw-r--r-- | bindings/python/tree_sitter_wmap/__init__.py | 43 | ||||
| -rw-r--r-- | bindings/python/tree_sitter_wmap/__init__.pyi | 17 | ||||
| -rw-r--r-- | bindings/python/tree_sitter_wmap/binding.c | 35 | ||||
| -rw-r--r-- | bindings/python/tree_sitter_wmap/py.typed | 0 | ||||
| -rw-r--r-- | bindings/rust/build.rs | 56 | ||||
| -rw-r--r-- | bindings/rust/lib.rs | 60 | ||||
| -rw-r--r-- | bindings/swift/TreeSitterWmap/wmap.h | 16 | ||||
| -rw-r--r-- | bindings/swift/TreeSitterWmapTests/TreeSitterWmapTests.swift | 12 |
17 files changed, 434 insertions, 0 deletions
diff --git a/bindings/c/tree-sitter-wmap.pc.in b/bindings/c/tree-sitter-wmap.pc.in new file mode 100644 index 0000000..028c4a1 --- /dev/null +++ b/bindings/c/tree-sitter-wmap.pc.in @@ -0,0 +1,10 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +libdir=${prefix}/@CMAKE_INSTALL_LIBDIR@ +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: tree-sitter-wmap +Description: @PROJECT_DESCRIPTION@ +URL: @PROJECT_HOMEPAGE_URL@ +Version: @PROJECT_VERSION@ +Libs: -L${libdir} -ltree-sitter-wmap +Cflags: -I${includedir} diff --git a/bindings/c/tree_sitter/tree-sitter-wmap.h b/bindings/c/tree_sitter/tree-sitter-wmap.h new file mode 100644 index 0000000..b477b35 --- /dev/null +++ b/bindings/c/tree_sitter/tree-sitter-wmap.h @@ -0,0 +1,16 @@ +#ifndef TREE_SITTER_WMAP_H_ +#define TREE_SITTER_WMAP_H_ + +typedef struct TSLanguage TSLanguage; + +#ifdef __cplusplus +extern "C" { +#endif + +const TSLanguage *tree_sitter_wmap(void); + +#ifdef __cplusplus +} +#endif + +#endif // TREE_SITTER_WMAP_H_ diff --git a/bindings/go/binding.go b/bindings/go/binding.go new file mode 100644 index 0000000..80fe78d --- /dev/null +++ b/bindings/go/binding.go @@ -0,0 +1,15 @@ +package tree_sitter_wmap + +// #cgo CFLAGS: -std=c11 -fPIC +// #include "../../src/parser.c" +// #if __has_include("../../src/scanner.c") +// #include "../../src/scanner.c" +// #endif +import "C" + +import "unsafe" + +// Get the tree-sitter Language for this grammar. +func Language() unsafe.Pointer { + return unsafe.Pointer(C.tree_sitter_wmap()) +} diff --git a/bindings/go/binding_test.go b/bindings/go/binding_test.go new file mode 100644 index 0000000..911fd9b --- /dev/null +++ b/bindings/go/binding_test.go @@ -0,0 +1,15 @@ +package tree_sitter_wmap_test + +import ( + "testing" + + tree_sitter "github.com/tree-sitter/go-tree-sitter" + tree_sitter_wmap "git.sr.ht/~rbdr/tree-sitter-wmap/bindings/go" +) + +func TestCanLoadGrammar(t *testing.T) { + language := tree_sitter.NewLanguage(tree_sitter_wmap.Language()) + if language == nil { + t.Errorf("Error loading Wmap grammar") + } +} diff --git a/bindings/node/binding.cc b/bindings/node/binding.cc new file mode 100644 index 0000000..03bd34c --- /dev/null +++ b/bindings/node/binding.cc @@ -0,0 +1,19 @@ +#include <napi.h> + +typedef struct TSLanguage TSLanguage; + +extern "C" TSLanguage *tree_sitter_wmap(); + +// "tree-sitter", "language" hashed with BLAKE2 +const napi_type_tag LANGUAGE_TYPE_TAG = { + 0x8AF2E5212AD58ABF, 0xD5006CAD83ABBA16 +}; + +Napi::Object Init(Napi::Env env, Napi::Object exports) { + auto language = Napi::External<TSLanguage>::New(env, tree_sitter_wmap()); + language.TypeTag(&LANGUAGE_TYPE_TAG); + exports["language"] = language; + return exports; +} + +NODE_API_MODULE(tree_sitter_wmap_binding, Init) diff --git a/bindings/node/binding_test.js b/bindings/node/binding_test.js new file mode 100644 index 0000000..7a91a84 --- /dev/null +++ b/bindings/node/binding_test.js @@ -0,0 +1,11 @@ +import assert from "node:assert"; +import { test } from "node:test"; +import Parser from "tree-sitter"; + +test("can load grammar", () => { + const parser = new Parser(); + assert.doesNotReject(async () => { + const { default: language } = await import("./index.js"); + parser.setLanguage(language); + }); +}); diff --git a/bindings/node/index.d.ts b/bindings/node/index.d.ts new file mode 100644 index 0000000..876252a --- /dev/null +++ b/bindings/node/index.d.ts @@ -0,0 +1,60 @@ +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[]; + }); + +/** + * The tree-sitter language object for this grammar. + * + * @see {@linkcode https://tree-sitter.github.io/node-tree-sitter/interfaces/Parser.Language.html Parser.Language} + * + * @example + * import Parser from "tree-sitter"; + * import Wmap from "tree-sitter-wmap"; + * + * const parser = new Parser(); + * parser.setLanguage(Wmap); + */ +declare const binding: { + /** + * The inner language object. + * @private + */ + language: unknown; + + /** + * The content of the `node-types.json` file for this grammar. + * + * @see {@linkplain https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types Static Node Types} + */ + nodeTypeInfo: NodeInfo[]; + + /** The syntax highlighting query for this grammar. */ + HIGHLIGHTS_QUERY?: string; + + /** The language injection query for this grammar. */ + INJECTIONS_QUERY?: string; + + /** The local variable query for this grammar. */ + LOCALS_QUERY?: string; + + /** The symbol tagging query for this grammar. */ + TAGS_QUERY?: string; +}; + +export default binding; diff --git a/bindings/node/index.js b/bindings/node/index.js new file mode 100644 index 0000000..efa6bea --- /dev/null +++ b/bindings/node/index.js @@ -0,0 +1,37 @@ +import { readFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; + +const root = fileURLToPath(new URL("../..", import.meta.url)); + +const binding = typeof process.versions.bun === "string" + // Support `bun build --compile` by being statically analyzable enough to find the .node file at build-time + ? await import(`${root}/prebuilds/${process.platform}-${process.arch}/tree-sitter-wmap.node`) + : (await import("node-gyp-build")).default(root); + +try { + const nodeTypes = await import(`${root}/src/node-types.json`, { with: { type: "json" } }); + binding.nodeTypeInfo = nodeTypes.default; +} catch { } + +const queries = [ + ["HIGHLIGHTS_QUERY", `${root}/queries/highlights.scm`], + ["INJECTIONS_QUERY", `${root}/queries/injections.scm`], + ["LOCALS_QUERY", `${root}/queries/locals.scm`], + ["TAGS_QUERY", `${root}/queries/tags.scm`], +]; + +for (const [prop, path] of queries) { + Object.defineProperty(binding, prop, { + configurable: true, + enumerable: true, + get() { + delete binding[prop]; + try { + binding[prop] = readFileSync(path, "utf8"); + } catch { } + return binding[prop]; + } + }); +} + +export default binding; diff --git a/bindings/python/tests/test_binding.py b/bindings/python/tests/test_binding.py new file mode 100644 index 0000000..35b3845 --- /dev/null +++ b/bindings/python/tests/test_binding.py @@ -0,0 +1,12 @@ +from unittest import TestCase + +from tree_sitter import Language, Parser +import tree_sitter_wmap + + +class TestLanguage(TestCase): + def test_can_load_grammar(self): + try: + Parser(Language(tree_sitter_wmap.language())) + except Exception: + self.fail("Error loading Wmap grammar") diff --git a/bindings/python/tree_sitter_wmap/__init__.py b/bindings/python/tree_sitter_wmap/__init__.py new file mode 100644 index 0000000..fa35926 --- /dev/null +++ b/bindings/python/tree_sitter_wmap/__init__.py @@ -0,0 +1,43 @@ +"""Parser for wmap Formatted Wardley Maps""" + +from importlib.resources import files as _files + +from ._binding import language + + +def _get_query(name, file): + try: + query = _files(f"{__package__}") / file + globals()[name] = query.read_text() + except FileNotFoundError: + globals()[name] = None + return globals()[name] + + +def __getattr__(name): + if name == "HIGHLIGHTS_QUERY": + return _get_query("HIGHLIGHTS_QUERY", "queries/highlights.scm") + if name == "INJECTIONS_QUERY": + return _get_query("INJECTIONS_QUERY", "queries/injections.scm") + if name == "LOCALS_QUERY": + return _get_query("LOCALS_QUERY", "queries/locals.scm") + if name == "TAGS_QUERY": + return _get_query("TAGS_QUERY", "queries/tags.scm") + + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + +__all__ = [ + "language", + "HIGHLIGHTS_QUERY", + "INJECTIONS_QUERY", + "LOCALS_QUERY", + "TAGS_QUERY", +] + + +def __dir__(): + return sorted(__all__ + [ + "__all__", "__builtins__", "__cached__", "__doc__", "__file__", + "__loader__", "__name__", "__package__", "__path__", "__spec__", + ]) diff --git a/bindings/python/tree_sitter_wmap/__init__.pyi b/bindings/python/tree_sitter_wmap/__init__.pyi new file mode 100644 index 0000000..5c88ff6 --- /dev/null +++ b/bindings/python/tree_sitter_wmap/__init__.pyi @@ -0,0 +1,17 @@ +from typing import Final +from typing_extensions import CapsuleType + +HIGHLIGHTS_QUERY: Final[str] | None +"""The syntax highlighting query for this grammar.""" + +INJECTIONS_QUERY: Final[str] | None +"""The language injection query for this grammar.""" + +LOCALS_QUERY: Final[str] | None +"""The local variable query for this grammar.""" + +TAGS_QUERY: Final[str] | None +"""The symbol tagging query for this grammar.""" + +def language() -> CapsuleType: + """The tree-sitter language function for this grammar.""" diff --git a/bindings/python/tree_sitter_wmap/binding.c b/bindings/python/tree_sitter_wmap/binding.c new file mode 100644 index 0000000..bbc4012 --- /dev/null +++ b/bindings/python/tree_sitter_wmap/binding.c @@ -0,0 +1,35 @@ +#include <Python.h> + +typedef struct TSLanguage TSLanguage; + +TSLanguage *tree_sitter_wmap(void); + +static PyObject* _binding_language(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { + return PyCapsule_New(tree_sitter_wmap(), "tree_sitter.Language", NULL); +} + +static struct PyModuleDef_Slot slots[] = { +#ifdef Py_GIL_DISABLED + {Py_mod_gil, Py_MOD_GIL_NOT_USED}, +#endif + {0, NULL} +}; + +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 = 0, + .m_methods = methods, + .m_slots = slots, +}; + +PyMODINIT_FUNC PyInit__binding(void) { + return PyModuleDef_Init(&module); +} diff --git a/bindings/python/tree_sitter_wmap/py.typed b/bindings/python/tree_sitter_wmap/py.typed new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/bindings/python/tree_sitter_wmap/py.typed diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs new file mode 100644 index 0000000..545b483 --- /dev/null +++ b/bindings/rust/build.rs @@ -0,0 +1,56 @@ +fn main() { + let src_dir = std::path::Path::new("src"); + + let mut c_config = cc::Build::new(); + c_config.std("c11").include(src_dir); + + #[cfg(target_env = "msvc")] + c_config.flag("-utf-8"); + + if std::env::var("TARGET").unwrap() == "wasm32-unknown-unknown" { + let Ok(wasm_headers) = std::env::var("DEP_TREE_SITTER_LANGUAGE_WASM_HEADERS") else { + panic!("Environment variable DEP_TREE_SITTER_LANGUAGE_WASM_HEADERS must be set by the language crate"); + }; + let Ok(wasm_src) = + std::env::var("DEP_TREE_SITTER_LANGUAGE_WASM_SRC").map(std::path::PathBuf::from) + else { + panic!("Environment variable DEP_TREE_SITTER_LANGUAGE_WASM_SRC must be set by the language crate"); + }; + + c_config.include(&wasm_headers); + c_config.files([ + wasm_src.join("stdio.c"), + wasm_src.join("stdlib.c"), + wasm_src.join("string.c"), + ]); + } + + let parser_path = src_dir.join("parser.c"); + c_config.file(&parser_path); + println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); + + let scanner_path = src_dir.join("scanner.c"); + if scanner_path.exists() { + c_config.file(&scanner_path); + println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); + } + + c_config.compile("tree-sitter-wmap"); + + println!("cargo:rustc-check-cfg=cfg(with_highlights_query)"); + if !"queries/highlights.scm".is_empty() && std::path::Path::new("queries/highlights.scm").exists() { + println!("cargo:rustc-cfg=with_highlights_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_injections_query)"); + if !"queries/injections.scm".is_empty() && std::path::Path::new("queries/injections.scm").exists() { + println!("cargo:rustc-cfg=with_injections_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_locals_query)"); + if !"queries/locals.scm".is_empty() && std::path::Path::new("queries/locals.scm").exists() { + println!("cargo:rustc-cfg=with_locals_query"); + } + println!("cargo:rustc-check-cfg=cfg(with_tags_query)"); + if !"queries/tags.scm".is_empty() && std::path::Path::new("queries/tags.scm").exists() { + println!("cargo:rustc-cfg=with_tags_query"); + } +} diff --git a/bindings/rust/lib.rs b/bindings/rust/lib.rs new file mode 100644 index 0000000..3517b5f --- /dev/null +++ b/bindings/rust/lib.rs @@ -0,0 +1,60 @@ +//! This crate provides Wmap language support for the [tree-sitter] parsing library. +//! +//! Typically, you will use the [`LANGUAGE`] constant to add this language to a +//! tree-sitter [`Parser`], and then use the parser to parse some code: +//! +//! ``` +//! let code = r#" +//! "#; +//! let mut parser = tree_sitter::Parser::new(); +//! let language = tree_sitter_wmap::LANGUAGE; +//! parser +//! .set_language(&language.into()) +//! .expect("Error loading Wmap parser"); +//! let tree = parser.parse(code, None).unwrap(); +//! assert!(!tree.root_node().has_error()); +//! ``` +//! +//! [`Parser`]: https://docs.rs/tree-sitter/0.26.3/tree_sitter/struct.Parser.html +//! [tree-sitter]: https://tree-sitter.github.io/ + +use tree_sitter_language::LanguageFn; + +extern "C" { + fn tree_sitter_wmap() -> *const (); +} + +/// The tree-sitter [`LanguageFn`] for this grammar. +pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_wmap) }; + +/// The content of the [`node-types.json`] file for this grammar. +/// +/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types +pub const NODE_TYPES: &str = include_str!("../../src/node-types.json"); + +#[cfg(with_highlights_query)] +/// The syntax highlighting query for this grammar. +pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); + +#[cfg(with_injections_query)] +/// The language injection query for this grammar. +pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); + +#[cfg(with_locals_query)] +/// The local variable query for this grammar. +pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); + +#[cfg(with_tags_query)] +/// The symbol tagging query for this grammar. +pub const TAGS_QUERY: &str = include_str!("../../queries/tags.scm"); + +#[cfg(test)] +mod tests { + #[test] + fn test_can_load_grammar() { + let mut parser = tree_sitter::Parser::new(); + parser + .set_language(&super::LANGUAGE.into()) + .expect("Error loading Wmap parser"); + } +} diff --git a/bindings/swift/TreeSitterWmap/wmap.h b/bindings/swift/TreeSitterWmap/wmap.h new file mode 100644 index 0000000..b477b35 --- /dev/null +++ b/bindings/swift/TreeSitterWmap/wmap.h @@ -0,0 +1,16 @@ +#ifndef TREE_SITTER_WMAP_H_ +#define TREE_SITTER_WMAP_H_ + +typedef struct TSLanguage TSLanguage; + +#ifdef __cplusplus +extern "C" { +#endif + +const TSLanguage *tree_sitter_wmap(void); + +#ifdef __cplusplus +} +#endif + +#endif // TREE_SITTER_WMAP_H_ diff --git a/bindings/swift/TreeSitterWmapTests/TreeSitterWmapTests.swift b/bindings/swift/TreeSitterWmapTests/TreeSitterWmapTests.swift new file mode 100644 index 0000000..d596362 --- /dev/null +++ b/bindings/swift/TreeSitterWmapTests/TreeSitterWmapTests.swift @@ -0,0 +1,12 @@ +import XCTest +import SwiftTreeSitter +import TreeSitterWmap + +final class TreeSitterWmapTests: XCTestCase { + func testCanLoadGrammar() throws { + let parser = Parser() + let language = Language(language: tree_sitter_wmap()) + XCTAssertNoThrow(try parser.setLanguage(language), + "Error loading Wmap grammar") + } +} |