diff --git a/.editorconfig b/.editorconfig index 12962a5..cf3b4e5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,7 +1,7 @@ root = true [*] -charset = utf-2 +charset = utf-8 [*.{json,toml,yml,gyp}] indent_style = space diff --git a/.gitignore b/.gitignore index 435e374..c22386a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,34 @@ +.DS_Store +*.log + +# C / shared libraries +*.a *.dll *.dylib -*.log +*.o *.so -.DS_Store +*.pc bin build + +# Rust +target/ +Cargo.lock + +# Node node_modules +prebuilds/ + +# Python +__pycache__/ +*.egg-info/ +dist/ +*.whl + +# Swift +.build/ +.swiftpm/ + +# tree-sitter +*.wasm +log.html diff --git a/CMakeLists.txt b/CMakeLists.txt index 276998a..3409812 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,7 +19,17 @@ include(GNUInstallDirs) find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI") +add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json" + "${CMAKE_CURRENT_SOURCE_DIR}/src/node-types.json" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/grammar.js" + COMMAND "${TREE_SITTER_CLI}" generate grammar.js --no-parser + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Generating grammar.json") + add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c" + BYPRODUCTS "${CMAKE_CURRENT_SOURCE_DIR}/src/tree_sitter/parser.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/tree_sitter/alloc.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/tree_sitter/array.h" DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json" COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json --abi=${TREE_SITTER_ABI_VERSION} diff --git a/Cargo.toml b/Cargo.toml index c24cdc4..1557b59 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,12 +1,15 @@ [package] name = "tree-sitter-applescript" -description = "applescript grammar for the tree-sitter parsing library" -version = "1.1.0" -keywords = ["incremental", "parsing", "applescript"] -categories = ["parsing", "text-editors"] -repository = "https://github.com/tree-sitter/tree-sitter-applescript" -edition = "2018" +description = "AppleScript grammar for tree-sitter" +version = "2.0.0" +authors = ["Tom Waddington "] license = "MIT" +readme = "README.md" +keywords = ["incremental", "parsing", "tree-sitter", "applescript"] +categories = ["parser-implementations", "parsing", "text-editors"] +repository = "https://github.com/waddie/tree-sitter-applescript" +edition = "2021" +autoexamples = false build = "bindings/rust/build.rs" include = [ @@ -14,13 +17,18 @@ include = [ "grammar.js", "queries/*", "src/*", + "tree-sitter.json", + "/LICENSE", ] [lib] path = "bindings/rust/lib.rs" [dependencies] -tree-sitter = "~0.20.10" +tree-sitter-language = "0.1" [build-dependencies] -cc = "1.0" +cc = "1.2" + +[dev-dependencies] +tree-sitter = "0.26.12" diff --git a/Makefile b/Makefile index dd82f3a..29a826b 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,7 @@ -ifeq ($(OS),Windows_NT) -$(error Windows is not supported) -endif - LANGUAGE_NAME := tree-sitter-applescript HOMEPAGE_URL := https://github.com/waddie/tree-sitter-applescript -VERSION := 1.1.0 +VERSION := 2.0.0 +DESCRIPTION := AppleScript grammar for tree-sitter # repository SRC_DIR := src @@ -16,6 +13,7 @@ PREFIX ?= /usr/local DATADIR ?= $(PREFIX)/share INCLUDEDIR ?= $(PREFIX)/include LIBDIR ?= $(PREFIX)/lib +BINDIR ?= $(PREFIX)/bin PCLIBDIR ?= $(LIBDIR)/pkgconfig # source/object files @@ -32,20 +30,25 @@ SONAME_MAJOR = $(shell sed -n 's/\#define LANGUAGE_VERSION //p' $(PARSER)) SONAME_MINOR = $(word 1,$(subst ., ,$(VERSION))) # OS-specific bits -ifeq ($(shell uname),Darwin) +MACHINE := $(shell $(CC) -dumpmachine) + +ifneq ($(findstring darwin,$(MACHINE)),) SOEXT = dylib SOEXTVER_MAJOR = $(SONAME_MAJOR).$(SOEXT) SOEXTVER = $(SONAME_MAJOR).$(SONAME_MINOR).$(SOEXT) LINKSHARED = -dynamiclib -Wl,-install_name,$(LIBDIR)/lib$(LANGUAGE_NAME).$(SOEXTVER),-rpath,@executable_path/../Frameworks +else ifneq ($(findstring mingw32,$(MACHINE)),) + SOEXT = dll + LINKSHARED += -s -shared -Wl,--out-implib,lib$(LANGUAGE_NAME).dll.a else SOEXT = so SOEXTVER_MAJOR = $(SOEXT).$(SONAME_MAJOR) SOEXTVER = $(SOEXT).$(SONAME_MAJOR).$(SONAME_MINOR) LINKSHARED = -shared -Wl,-soname,lib$(LANGUAGE_NAME).$(SOEXTVER) -endif ifneq ($(filter $(shell uname),FreeBSD NetBSD DragonFly),) PCLIBDIR := $(PREFIX)/libdata/pkgconfig endif +endif all: lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) $(LANGUAGE_NAME).pc @@ -58,6 +61,10 @@ ifneq ($(STRIP),) $(STRIP) $@ endif +ifneq ($(findstring mingw32,$(MACHINE)),) +lib$(LANGUAGE_NAME).dll.a: lib$(LANGUAGE_NAME).$(SOEXT) +endif + $(LANGUAGE_NAME).pc: bindings/c/$(LANGUAGE_NAME).pc.in sed -e 's|@PROJECT_VERSION@|$(VERSION)|' \ -e 's|@CMAKE_INSTALL_LIBDIR@|$(LIBDIR:$(PREFIX)/%=%)|' \ @@ -66,6 +73,9 @@ $(LANGUAGE_NAME).pc: bindings/c/$(LANGUAGE_NAME).pc.in -e 's|@PROJECT_HOMEPAGE_URL@|$(HOMEPAGE_URL)|' \ -e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|' $< > $@ +$(SRC_DIR)/grammar.json: grammar.js + $(TS) generate --no-parser $^ + $(PARSER): $(SRC_DIR)/grammar.json $(TS) generate $^ @@ -75,8 +85,15 @@ install: all install -m644 $(LANGUAGE_NAME).pc '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc install -m644 lib$(LANGUAGE_NAME).a '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a install -m755 lib$(LANGUAGE_NAME).$(SOEXT) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) - ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) - ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) +ifneq ($(findstring mingw32,$(MACHINE)),) + install -d '$(DESTDIR)$(BINDIR)' + install -m755 lib$(LANGUAGE_NAME).dll '$(DESTDIR)$(BINDIR)'/lib$(LANGUAGE_NAME).dll + install -m755 lib$(LANGUAGE_NAME).dll.a '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).dll.a +else + install -m755 lib$(LANGUAGE_NAME).$(SOEXT) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) + cd '$(DESTDIR)$(LIBDIR)' && ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER) lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) + cd '$(DESTDIR)$(LIBDIR)' && ln -sf lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) lib$(LANGUAGE_NAME).$(SOEXT) +endif ifneq ($(wildcard queries/*.scm),) install -m644 queries/*.scm '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/applescript endif @@ -91,7 +108,7 @@ uninstall: $(RM) -r '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/applescript clean: - $(RM) $(OBJS) $(LANGUAGE_NAME).pc lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) + $(RM) $(OBJS) $(LANGUAGE_NAME).pc lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) lib$(LANGUAGE_NAME).dll.a test: $(TS) test diff --git a/Package.swift b/Package.swift index 96a4261..b2eaffd 100644 --- a/Package.swift +++ b/Package.swift @@ -14,7 +14,7 @@ let package = Package( .library(name: "TreeSitterApplescript", targets: ["TreeSitterApplescript"]), ], dependencies: [ - .package(name: "SwiftTreeSitter", url: "https://github.com/tree-sitter/swift-tree-sitter", from: "0.9.0"), + .package(url: "https://github.com/tree-sitter/swift-tree-sitter", from: "0.9.0"), ], targets: [ .target( @@ -31,7 +31,7 @@ let package = Package( .testTarget( name: "TreeSitterApplescriptTests", dependencies: [ - "SwiftTreeSitter", + .product(name: "SwiftTreeSitter", package: "swift-tree-sitter"), "TreeSitterApplescript", ], path: "bindings/swift/TreeSitterApplescriptTests" diff --git a/binding.gyp b/binding.gyp index 011358e..3e86b54 100644 --- a/binding.gyp +++ b/binding.gyp @@ -2,18 +2,34 @@ "targets": [ { "target_name": "tree_sitter_applescript_binding", + "dependencies": [ + " -#include "nan.h" +#include -using namespace v8; +typedef struct TSLanguage TSLanguage; -extern "C" TSLanguage * tree_sitter_applescript(); +extern "C" TSLanguage *tree_sitter_applescript(); -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_applescript()); - - Nan::Set(instance, Nan::New("name").ToLocalChecked(), Nan::New("applescript").ToLocalChecked()); - Nan::Set(module, Nan::New("exports").ToLocalChecked(), instance); +Napi::Object Init(Napi::Env env, Napi::Object exports) { + auto language = Napi::External::New(env, tree_sitter_applescript()); + language.TypeTag(&LANGUAGE_TYPE_TAG); + exports["language"] = language; + return exports; } -NODE_MODULE(tree_sitter_applescript_binding, Init) - -} // namespace +NODE_API_MODULE(tree_sitter_applescript_binding, Init) diff --git a/bindings/node/binding_test.js b/bindings/node/binding_test.js index 55becac..7a91a84 100644 --- a/bindings/node/binding_test.js +++ b/bindings/node/binding_test.js @@ -1,9 +1,11 @@ -const assert = require("node:assert"); -const { test } = require("node:test"); - -const Parser = require("tree-sitter"); +import assert from "node:assert"; +import { test } from "node:test"; +import Parser from "tree-sitter"; test("can load grammar", () => { const parser = new Parser(); - assert.doesNotThrow(() => parser.setLanguage(require("."))); + 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 index 528e060..a2f8ce3 100644 --- a/bindings/node/index.d.ts +++ b/bindings/node/index.d.ts @@ -18,10 +18,43 @@ type NodeInfo = children: ChildNode[]; }); -type Language = { +/** + * 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 AppleScript from "tree-sitter-applescript"; + * + * const parser = new Parser(); + * parser.setLanguage(AppleScript); + */ +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; }; -declare const language: Language; -export = language; +export default binding; diff --git a/bindings/node/index.js b/bindings/node/index.js index fc3d273..97a34e1 100644 --- a/bindings/node/index.js +++ b/bindings/node/index.js @@ -2,22 +2,40 @@ // Copyright (c) 2025 Tom Waddington // See LICENSE file for full license text +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-applescript.node`) + : (await import("node-gyp-build")).default(root); + try { - module.exports = require("../../build/Release/tree_sitter_applescript_binding"); -} catch (error1) { - if (error1.code !== 'MODULE_NOT_FOUND') { - throw error1; - } - try { - module.exports = require("../../build/Debug/tree_sitter_applescript_binding"); - } catch (error2) { - if (error2.code !== 'MODULE_NOT_FOUND') { - throw error2; + 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]; } - throw error1 - } + }); } -try { - module.exports.nodeTypeInfo = require("../../src/node-types.json"); -} catch (_) {} +export default binding; diff --git a/bindings/python/tree_sitter_applescript/__init__.py b/bindings/python/tree_sitter_applescript/__init__.py index 78b7e86..c58ce64 100644 --- a/bindings/python/tree_sitter_applescript/__init__.py +++ b/bindings/python/tree_sitter_applescript/__init__.py @@ -6,32 +6,33 @@ from ._binding import language def _get_query(name, file): - query = _files(f"{__package__}.queries") / file - globals()[name] = query.read_text() + try: + query = _files(f"{__package__}") / file + globals()[name] = query.read_text() + except FileNotFoundError: + globals()[name] = None return globals()[name] def __getattr__(name): - # NOTE: uncomment these to include any queries that this grammar contains: - - # if name == "HIGHLIGHTS_QUERY": - # return _get_query("HIGHLIGHTS_QUERY", "highlights.scm") - # if name == "INJECTIONS_QUERY": - # return _get_query("INJECTIONS_QUERY", "injections.scm") - # if name == "LOCALS_QUERY": - # return _get_query("LOCALS_QUERY", "locals.scm") - # if name == "TAGS_QUERY": - # return _get_query("TAGS_QUERY", "tags.scm") + 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", + "HIGHLIGHTS_QUERY", + "INJECTIONS_QUERY", + "LOCALS_QUERY", + "TAGS_QUERY", ] diff --git a/bindings/python/tree_sitter_applescript/__init__.pyi b/bindings/python/tree_sitter_applescript/__init__.pyi index abf6633..5c88ff6 100644 --- a/bindings/python/tree_sitter_applescript/__init__.pyi +++ b/bindings/python/tree_sitter_applescript/__init__.pyi @@ -1,10 +1,17 @@ from typing import Final +from typing_extensions import CapsuleType -# NOTE: uncomment these to include any queries that this grammar contains: +HIGHLIGHTS_QUERY: Final[str] | None +"""The syntax highlighting query for this grammar.""" -# HIGHLIGHTS_QUERY: Final[str] -# INJECTIONS_QUERY: Final[str] -# LOCALS_QUERY: Final[str] -# TAGS_QUERY: Final[str] +INJECTIONS_QUERY: Final[str] | None +"""The language injection query for this grammar.""" -def language() -> object: ... +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/rust/build.rs b/bindings/rust/build.rs index ec73692..ae7c9b7 100644 --- a/bindings/rust/build.rs +++ b/bindings/rust/build.rs @@ -6,39 +6,55 @@ fn main() { let src_dir = std::path::Path::new("src"); let mut c_config = cc::Build::new(); - c_config.include(&src_dir); - c_config - .flag_if_supported("-Wno-unused-parameter") - .flag_if_supported("-Wno-unused-but-set-variable") - .flag_if_supported("-Wno-trigraphs"); + 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()); - // If your language uses an external scanner written in C, - // then include this block of code: - - /* let scanner_path = src_dir.join("scanner.c"); - c_config.file(&scanner_path); - println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); - */ + if scanner_path.exists() { + c_config.file(&scanner_path); + println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); + } - c_config.compile("parser"); - println!("cargo:rerun-if-changed={}", parser_path.to_str().unwrap()); + c_config.compile("tree-sitter-applescript"); - // If your language uses an external scanner written in C++, - // then include this block of code: - - /* - let mut cpp_config = cc::Build::new(); - cpp_config.cpp(true); - cpp_config.include(&src_dir); - cpp_config - .flag_if_supported("-Wno-unused-parameter") - .flag_if_supported("-Wno-unused-but-set-variable"); - let scanner_path = src_dir.join("scanner.cc"); - cpp_config.file(&scanner_path); - cpp_config.compile("scanner"); - println!("cargo:rerun-if-changed={}", scanner_path.to_str().unwrap()); - */ + 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 index d674eff..7c90fd1 100644 --- a/bindings/rust/lib.rs +++ b/bindings/rust/lib.rs @@ -2,47 +2,55 @@ // Copyright (c) 2025 Tom Waddington // See LICENSE file for full license text -//! This crate provides applescript language support for the [tree-sitter][] parsing library. +//! This crate provides AppleScript language support for the [tree-sitter] parsing library. //! -//! Typically, you will use the [language][language func] function to add this language to a -//! tree-sitter [Parser][], and then use the parser to parse some code: +//! 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 = ""; +//! let code = r#" +//! "#; //! let mut parser = tree_sitter::Parser::new(); -//! parser.set_language(tree_sitter_applescript::language()).expect("Error loading applescript grammar"); +//! let language = tree_sitter_applescript::LANGUAGE; +//! parser +//! .set_language(&language.into()) +//! .expect("Error loading AppleScript parser"); //! let tree = parser.parse(code, None).unwrap(); +//! assert!(!tree.root_node().has_error()); //! ``` //! -//! [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html -//! [language func]: fn.language.html -//! [Parser]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Parser.html +//! [`Parser`]: https://docs.rs/tree-sitter/0.26.12/tree_sitter/struct.Parser.html //! [tree-sitter]: https://tree-sitter.github.io/ -use tree_sitter::Language; +use tree_sitter_language::LanguageFn; extern "C" { - fn tree_sitter_applescript() -> Language; + fn tree_sitter_applescript() -> *const (); } -/// Get the tree-sitter [Language][] for this grammar. -/// -/// [Language]: https://docs.rs/tree-sitter/*/tree_sitter/struct.Language.html -pub fn language() -> Language { - unsafe { tree_sitter_applescript() } -} +/// The tree-sitter [`LanguageFn`] for this grammar. +pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_applescript) }; -/// The content of the [`node-types.json`][] file for this grammar. +/// The content of the [`node-types.json`] file for this grammar. /// -/// [`node-types.json`]: https://tree-sitter.github.io/tree-sitter/using-parsers#static-node-types -pub const NODE_TYPES: &'static str = include_str!("../../src/node-types.json"); +/// [`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"); -// Uncomment these to include any queries that this grammar contains +#[cfg(with_locals_query)] +/// The local variable query for this grammar. +pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); -// pub const HIGHLIGHTS_QUERY: &'static str = include_str!("../../queries/highlights.scm"); -// pub const INJECTIONS_QUERY: &'static str = include_str!("../../queries/injections.scm"); -// pub const LOCALS_QUERY: &'static str = include_str!("../../queries/locals.scm"); -// pub const TAGS_QUERY: &'static str = include_str!("../../queries/tags.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 { @@ -50,7 +58,7 @@ mod tests { fn test_can_load_grammar() { let mut parser = tree_sitter::Parser::new(); parser - .set_language(super::language()) - .expect("Error loading applescript language"); + .set_language(&super::LANGUAGE.into()) + .expect("Error loading AppleScript parser"); } } diff --git a/grammar.js b/grammar.js index a445edc..b988ec5 100644 --- a/grammar.js +++ b/grammar.js @@ -2,7 +2,7 @@ // Copyright (c) 2025 Tom Waddington // See LICENSE file for full license text -module.exports = grammar({ +export default grammar({ name: 'applescript', externals: $ => [ diff --git a/package.json b/package.json index b3131e9..fd85aac 100644 --- a/package.json +++ b/package.json @@ -1,34 +1,62 @@ { "name": "tree-sitter-applescript", - "version": "1.1.0", + "version": "2.0.0", "description": "AppleScript grammar for tree-sitter", + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/waddie/tree-sitter-applescript.git" + }, + "license": "MIT", + "author": { + "name": "Tom Waddington", + "email": "tom@waddington.dev" + }, "main": "bindings/node", + "types": "bindings/node", "keywords": [ - "parser", + "incremental", + "parsing", "tree-sitter", "applescript" ], - "author": "Tree-sitter Contributors", - "license": "MIT", + "files": [ + "grammar.js", + "tree-sitter.json", + "binding.gyp", + "prebuilds/**", + "bindings/node/*", + "queries/*", + "src/**", + "*.wasm" + ], "dependencies": { - "nan": "^2.17.0" + "node-addon-api": "^8.5.0", + "node-gyp-build": "^4.8.4" }, "devDependencies": { + "prebuildify": "^6.0.1", + "tree-sitter": "^0.25.0", "tree-sitter-cli": "^0.26.12" }, + "peerDependencies": { + "tree-sitter": "^0.25.0" + }, + "peerDependenciesMeta": { + "tree-sitter": { + "optional": true + } + }, + "scripts": { + "install": "node-gyp-build", + "prestart": "tree-sitter build --wasm", + "start": "tree-sitter playground", + "test": "node --test bindings/node/*_test.js" + }, "pnpm": { "onlyBuiltDependencies": [ + "tree-sitter", "tree-sitter-cli" ] - }, - "tree-sitter": [ - { - "scope": "source.applescript", - "file-types": [ - "applescript", - "scpt" - ], - "highlights": "queries/highlights.scm" - } - ] + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 308543f..bd90f22 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,26 +8,220 @@ importers: .: dependencies: - nan: - specifier: ^2.17.0 - version: 2.23.0 + node-addon-api: + specifier: ^8.5.0 + version: 8.9.1 + node-gyp-build: + specifier: ^4.8.4 + version: 4.8.4 devDependencies: + prebuildify: + specifier: ^6.0.1 + version: 6.0.1 + tree-sitter: + specifier: ^0.25.0 + version: 0.25.1 tree-sitter-cli: specifier: ^0.26.12 version: 0.26.12 packages: - nan@2.23.0: - resolution: {integrity: sha512-1UxuyYGdoQHcGg87Lkqm3FzefucTa0NAiOcuRsDmysep3c1LVCRK2krrUDafMWtjSG04htvAmvg96+SDknOmgQ==} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + + node-abi@3.94.0: + resolution: {integrity: sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==} + engines: {node: '>=10'} + + node-addon-api@8.9.1: + resolution: {integrity: sha512-4eUQWVPCUUUiBjLnHS3cXWeC6ryoPUc0U3rP7IuzapoGbzMqd/r6KKO0clr0b+snQhsrueFEhCZDdK+LK7hxKg==} + engines: {node: ^18 || ^20 || >= 21} + + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + + npm-run-path@3.1.0: + resolution: {integrity: sha512-Dbl4A/VfiVGLgQv29URL9xshU8XDY1GeLy+fsaZ1AA8JDSfjvr5P5+pzRbWqRSBxk6/DW7MIh8lTM/PaGnP2kg==} + engines: {node: '>=8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + prebuildify@6.0.1: + resolution: {integrity: sha512-8Y2oOOateom/s8dNBsGIcnm6AxPmLH4/nanQzL5lQMU+sC0CMhzARZHizwr36pUPLdvBnOkCNQzxg4djuFSgIw==} + hasBin: true + + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + + tar-fs@2.1.5: + resolution: {integrity: sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==} + + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} tree-sitter-cli@0.26.12: resolution: {integrity: sha512-rIdMAm6nv75MVFoZ7UTaLVB1OG5h3ZSlCZEp5pne4gOUTalJIkL0A1NlYBg0oEl/d7gvIyc2Y5Jz8m5Xj+NOEw==} engines: {node: '>=12.0.0'} hasBin: true + tree-sitter@0.25.1: + resolution: {integrity: sha512-mrcEdkYtHfrK1A6fs3O6FxkBo0Qig5XUXqHhxUOQu0bmPo00QF4XaSx4edpazdHwxnSCjlGKGgIqWdaN4dvTLA==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + snapshots: - nan@2.23.0: {} + base64-js@1.5.1: {} + + bl@4.1.0: + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + chownr@1.1.4: {} + + end-of-stream@1.4.5: + dependencies: + once: 1.4.0 + + fs-constants@1.0.0: {} + + ieee754@1.2.1: {} + + inherits@2.0.4: {} + + minimist@1.2.8: {} + + mkdirp-classic@0.5.3: {} + + node-abi@3.94.0: + dependencies: + semver: 7.8.5 + + node-addon-api@8.9.1: {} + + node-gyp-build@4.8.4: {} + + npm-run-path@3.1.0: + dependencies: + path-key: 3.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + path-key@3.1.1: {} + + prebuildify@6.0.1: + dependencies: + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + node-abi: 3.94.0 + npm-run-path: 3.1.0 + pump: 3.0.4 + tar-fs: 2.1.5 + + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + + readable-stream@3.6.2: + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + + safe-buffer@5.2.1: {} + + semver@7.8.5: {} + + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + + tar-fs@2.1.5: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.4 + tar-stream: 2.2.0 + + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.5 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 tree-sitter-cli@0.26.12: {} + + tree-sitter@0.25.1: + dependencies: + node-addon-api: 8.9.1 + node-gyp-build: 4.8.4 + + util-deprecate@1.0.2: {} + + wrappy@1.0.2: {} diff --git a/pyproject.toml b/pyproject.toml index 8324f7b..a4fafa9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta" [project] name = "tree-sitter-applescript" description = "AppleScript grammar for tree-sitter" -version = "1.1.0" +version = "2.0.0" keywords = ["incremental", "parsing", "tree-sitter", "applescript"] classifiers = [ "Intended Audience :: Developers", diff --git a/setup.py b/setup.py index 2a10e58..3f11a77 100644 --- a/setup.py +++ b/setup.py @@ -32,7 +32,7 @@ class BuildExt(build_ext): class BdistWheel(bdist_wheel): def get_tag(self): python, abi, platform = super().get_tag() - if python.startswith("cp"): + if python.startswith("cp") and not get_config_var("Py_GIL_DISABLED"): python, abi = "cp310", "abi3" return python, abi, platform @@ -42,6 +42,7 @@ class EggInfo(egg_info): super().find_sources() self.filelist.recursive_include("queries", "*.scm") self.filelist.include("src/tree_sitter/*.h") + self.filelist.include("src/*.c") setup( diff --git a/src/parser.c b/src/parser.c index 0d809ef..229e56d 100644 --- a/src/parser.c +++ b/src/parser.c @@ -611613,8 +611613,8 @@ TS_PUBLIC const TSLanguage *tree_sitter_applescript(void) { .name = "applescript", .max_reserved_word_set_size = 0, .metadata = { - .major_version = 1, - .minor_version = 1, + .major_version = 2, + .minor_version = 0, .patch_version = 0, }, }; diff --git a/src/scanner.c b/src/scanner.c index c674f91..e78463b 100644 --- a/src/scanner.c +++ b/src/scanner.c @@ -2,7 +2,8 @@ // Copyright (c) 2025 Tom Waddington // See LICENSE file for full license text -#include +// Quoted, not angled: cgo compiles this without src/ on the include path. +#include "tree_sitter/parser.h" #include // External token types - must match order in grammar.js externals array diff --git a/tree-sitter.json b/tree-sitter.json index e76afc5..496fb98 100644 --- a/tree-sitter.json +++ b/tree-sitter.json @@ -1,18 +1,11 @@ { "$schema": "https://tree-sitter.github.io/tree-sitter/assets/schemas/config.schema.json", - "bindings": { - "c": true, - "go": true, - "node": true, - "python": true, - "rust": true, - "swift": true, - "zig": false - }, "grammars": [ { + "name": "applescript", "camelcase": "AppleScript", - "class-name": "TreeSitterApplescript", + "title": "AppleScript", + "scope": "source.applescript", "file-types": [ "applescript", "scpt" @@ -20,27 +13,35 @@ "highlights": [ "queries/highlights.scm" ], - "injection-regex": "^applescript$", - "name": "applescript", - "scope": "source.applescript", "tags": [ "queries/tags.scm" ], - "title": "AppleScript" + "injection-regex": "^applescript$", + "class-name": "TreeSitterApplescript" } ], "metadata": { + "version": "2.0.0", + "license": "MIT", + "description": "AppleScript grammar for tree-sitter", "authors": [ { - "email": "tom@waddington.dev", - "name": "Tom Waddington" + "name": "Tom Waddington", + "email": "tom@waddington.dev" } ], - "description": "AppleScript grammar for tree-sitter", - "license": "MIT", "links": { "repository": "https://github.com/waddie/tree-sitter-applescript" - }, - "version": "1.1.0" + } + }, + "bindings": { + "c": true, + "go": true, + "java": false, + "node": true, + "python": true, + "rust": true, + "swift": true, + "zig": false } -} +} \ No newline at end of file