commit ccd44c8172e9afc648b89d360659aa1d090945ec Author: Matthias Unterrainer Date: Sat Jan 17 15:37:53 2026 +0100 Initial commit diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..65330c4 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,46 @@ +root = true + +[*] +charset = utf-8 + +[*.{json,toml,yml,gyp}] +indent_style = space +indent_size = 2 + +[*.js] +indent_style = space +indent_size = 2 + +[*.scm] +indent_style = space +indent_size = 2 + +[*.{c,cc,h}] +indent_style = space +indent_size = 4 + +[*.rs] +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 + +[parser.c] +indent_size = 2 + +[{alloc,array,parser}.h] +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..7772c94 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,42 @@ +* text=auto eol=lf + +# Generated source files +src/*.json linguist-generated +src/parser.c linguist-generated +src/tree_sitter/* linguist-generated + +# C bindings +bindings/c/** linguist-generated +CMakeLists.txt linguist-generated +Makefile linguist-generated + +# Rust bindings +bindings/rust/* linguist-generated +Cargo.toml linguist-generated +Cargo.lock linguist-generated + +# Node.js bindings +bindings/node/* linguist-generated +binding.gyp linguist-generated +package.json linguist-generated +package-lock.json linguist-generated + +# Python bindings +bindings/python/** linguist-generated +setup.py linguist-generated +pyproject.toml linguist-generated + +# Go bindings +bindings/go/* linguist-generated +go.mod linguist-generated +go.sum linguist-generated + +# Swift bindings +bindings/swift/** linguist-generated +Package.swift linguist-generated +Package.resolved linguist-generated + +# Zig bindings +bindings/zig/* linguist-generated +build.zig linguist-generated +build.zig.zon linguist-generated diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..87a0c80 --- /dev/null +++ b/.gitignore @@ -0,0 +1,50 @@ +# Rust artifacts +target/ +Cargo.lock + +# Node artifacts +build/ +prebuilds/ +node_modules/ +package-lock.json + +# Swift artifacts +.build/ +Package.resolved + +# Go artifacts +_obj/ + +# Python artifacts +.venv/ +dist/ +*.egg-info +*.whl + +# C artifacts +*.a +*.so +*.so.* +*.dylib +*.dll +*.pc +*.exp +*.lib + +# Zig artifacts +.zig-cache/ +zig-cache/ +zig-out/ + +# Example dirs +/examples/*/ + +# Grammar volatiles +*.wasm +*.obj +*.o + +# Archives +*.tar.gz +*.tgz +*.zip diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d0ef279 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,66 @@ +cmake_minimum_required(VERSION 3.13) + +project(tree-sitter-mc + VERSION "0.1.0" + DESCRIPTION "A parser for the MC programming language" + HOMEPAGE_URL "https://git.matthunter.de/matth0930/tree-sitter-mc.git" + LANGUAGES C) + +option(BUILD_SHARED_LIBS "Build using shared libraries" ON) +option(TREE_SITTER_REUSE_ALLOCATOR "Reuse the library allocator" OFF) + +set(TREE_SITTER_ABI_VERSION 15 CACHE STRING "Tree-sitter ABI version") +if(NOT ${TREE_SITTER_ABI_VERSION} MATCHES "^[0-9]+$") + unset(TREE_SITTER_ABI_VERSION CACHE) + message(FATAL_ERROR "TREE_SITTER_ABI_VERSION must be an integer") +endif() + +include(GNUInstallDirs) + +find_program(TREE_SITTER_CLI tree-sitter DOC "Tree-sitter CLI") + +add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/src/parser.c" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/grammar.json" + COMMAND "${TREE_SITTER_CLI}" generate src/grammar.json + --abi=${TREE_SITTER_ABI_VERSION} + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "Generating parser.c") + +add_library(tree-sitter-mc src/parser.c) +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/scanner.c) + target_sources(tree-sitter-mc PRIVATE src/scanner.c) +endif() +target_include_directories(tree-sitter-mc + PRIVATE src + INTERFACE $ + $) + +target_compile_definitions(tree-sitter-mc PRIVATE + $<$:TREE_SITTER_REUSE_ALLOCATOR> + $<$:TREE_SITTER_DEBUG>) + +set_target_properties(tree-sitter-mc + PROPERTIES + C_STANDARD 11 + POSITION_INDEPENDENT_CODE ON + SOVERSION "${TREE_SITTER_ABI_VERSION}.${PROJECT_VERSION_MAJOR}" + DEFINE_SYMBOL "") + +configure_file(bindings/c/tree-sitter-mc.pc.in + "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-mc.pc" @ONLY) + +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bindings/c/tree_sitter" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + FILES_MATCHING PATTERN "*.h") +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/tree-sitter-mc.pc" + DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") +install(TARGETS tree-sitter-mc + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}") + +file(GLOB QUERIES queries/*.scm) +install(FILES ${QUERIES} + DESTINATION "${CMAKE_INSTALL_DATADIR}/tree-sitter/queries/mc") + +add_custom_target(ts-test "${TREE_SITTER_CLI}" test + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" + COMMENT "tree-sitter test") diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..c42c9ba --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "tree-sitter-mc" +description = "A parser for the MC programming language" +version = "0.1.0" +authors = ["Matthias Unterrainer"] +license = "Apache-2.0" +readme = "README.md" +keywords = ["incremental", "parsing", "tree-sitter", "mc"] +categories = ["parser-implementations", "parsing", "text-editors"] +repository = "https://git.matthunter.de/matth0930/tree-sitter-mc.git" +edition = "2021" +autoexamples = false + +build = "bindings/rust/build.rs" +include = [ + "bindings/rust/*", + "grammar.js", + "queries/*", + "src/*", + "tree-sitter.json", + "/LICENSE", +] + +[lib] +path = "bindings/rust/lib.rs" + +[dependencies] +tree-sitter-language = "0.1" + +[build-dependencies] +cc = "1.2" + +[dev-dependencies] +tree-sitter = "0.25.10" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d715e4d --- /dev/null +++ b/Makefile @@ -0,0 +1,99 @@ +ifeq ($(OS),Windows_NT) +$(error Windows is not supported) +endif + +LANGUAGE_NAME := tree-sitter-mc +HOMEPAGE_URL := https://git.matthunter.de/matth0930/tree-sitter-mc.git +VERSION := 0.1.0 + +# repository +SRC_DIR := src + +TS ?= tree-sitter + +# install directory layout +PREFIX ?= /usr/local +DATADIR ?= $(PREFIX)/share +INCLUDEDIR ?= $(PREFIX)/include +LIBDIR ?= $(PREFIX)/lib +PCLIBDIR ?= $(LIBDIR)/pkgconfig + +# source/object files +PARSER := $(SRC_DIR)/parser.c +EXTRAS := $(filter-out $(PARSER),$(wildcard $(SRC_DIR)/*.c)) +OBJS := $(patsubst %.c,%.o,$(PARSER) $(EXTRAS)) + +# flags +ARFLAGS ?= rcs +override CFLAGS += -I$(SRC_DIR) -std=c11 -fPIC + +# ABI versioning +SONAME_MAJOR = $(shell sed -n 's/\#define LANGUAGE_VERSION //p' $(PARSER)) +SONAME_MINOR = $(word 1,$(subst ., ,$(VERSION))) + +# OS-specific bits +ifeq ($(shell uname),Darwin) + 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 + 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 + +all: lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) $(LANGUAGE_NAME).pc + +lib$(LANGUAGE_NAME).a: $(OBJS) + $(AR) $(ARFLAGS) $@ $^ + +lib$(LANGUAGE_NAME).$(SOEXT): $(OBJS) + $(CC) $(LDFLAGS) $(LINKSHARED) $^ $(LDLIBS) -o $@ +ifneq ($(STRIP),) + $(STRIP) $@ +endif + +$(LANGUAGE_NAME).pc: bindings/c/$(LANGUAGE_NAME).pc.in + sed -e 's|@PROJECT_VERSION@|$(VERSION)|' \ + -e 's|@CMAKE_INSTALL_LIBDIR@|$(LIBDIR:$(PREFIX)/%=%)|' \ + -e 's|@CMAKE_INSTALL_INCLUDEDIR@|$(INCLUDEDIR:$(PREFIX)/%=%)|' \ + -e 's|@PROJECT_DESCRIPTION@|$(DESCRIPTION)|' \ + -e 's|@PROJECT_HOMEPAGE_URL@|$(HOMEPAGE_URL)|' \ + -e 's|@CMAKE_INSTALL_PREFIX@|$(PREFIX)|' $< > $@ + +$(PARSER): $(SRC_DIR)/grammar.json + $(TS) generate $^ + +install: all + install -d '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/mc '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter '$(DESTDIR)$(PCLIBDIR)' '$(DESTDIR)$(LIBDIR)' + install -m644 bindings/c/tree_sitter/$(LANGUAGE_NAME).h '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h + 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 ($(wildcard queries/*.scm),) + install -m644 queries/*.scm '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/mc +endif + +uninstall: + $(RM) '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).a \ + '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER) \ + '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXTVER_MAJOR) \ + '$(DESTDIR)$(LIBDIR)'/lib$(LANGUAGE_NAME).$(SOEXT) \ + '$(DESTDIR)$(INCLUDEDIR)'/tree_sitter/$(LANGUAGE_NAME).h \ + '$(DESTDIR)$(PCLIBDIR)'/$(LANGUAGE_NAME).pc + $(RM) -r '$(DESTDIR)$(DATADIR)'/tree-sitter/queries/mc + +clean: + $(RM) $(OBJS) $(LANGUAGE_NAME).pc lib$(LANGUAGE_NAME).a lib$(LANGUAGE_NAME).$(SOEXT) + +test: + $(TS) test + +.PHONY: all install uninstall clean test diff --git a/Package.swift b/Package.swift new file mode 100644 index 0000000..5078e4c --- /dev/null +++ b/Package.swift @@ -0,0 +1,41 @@ +// swift-tools-version:5.3 + +import Foundation +import PackageDescription + +var sources = ["src/parser.c"] +if FileManager.default.fileExists(atPath: "src/scanner.c") { + sources.append("src/scanner.c") +} + +let package = Package( + name: "TreeSitterMc", + products: [ + .library(name: "TreeSitterMc", targets: ["TreeSitterMc"]), + ], + dependencies: [ + .package(name: "SwiftTreeSitter", url: "https://github.com/tree-sitter/swift-tree-sitter", from: "0.9.0"), + ], + targets: [ + .target( + name: "TreeSitterMc", + dependencies: [], + path: ".", + sources: sources, + resources: [ + .copy("queries") + ], + publicHeadersPath: "bindings/swift", + cSettings: [.headerSearchPath("src")] + ), + .testTarget( + name: "TreeSitterMcTests", + dependencies: [ + "SwiftTreeSitter", + "TreeSitterMc", + ], + path: "bindings/swift/TreeSitterMcTests" + ) + ], + cLanguageStandard: .c11 +) diff --git a/binding.gyp b/binding.gyp new file mode 100644 index 0000000..f6c6f14 --- /dev/null +++ b/binding.gyp @@ -0,0 +1,35 @@ +{ + "targets": [ + { + "target_name": "tree_sitter_mc_binding", + "dependencies": [ + " + +typedef struct TSLanguage TSLanguage; + +extern "C" TSLanguage *tree_sitter_mc(); + +// "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::New(env, tree_sitter_mc()); + language.TypeTag(&LANGUAGE_TYPE_TAG); + exports["language"] = language; + return exports; +} + +NODE_API_MODULE(tree_sitter_mc_binding, Init) diff --git a/bindings/node/binding_test.js b/bindings/node/binding_test.js new file mode 100644 index 0000000..55becac --- /dev/null +++ b/bindings/node/binding_test.js @@ -0,0 +1,9 @@ +const assert = require("node:assert"); +const { test } = require("node:test"); + +const Parser = require("tree-sitter"); + +test("can load grammar", () => { + const parser = new Parser(); + assert.doesNotThrow(() => parser.setLanguage(require("."))); +}); diff --git a/bindings/node/index.d.ts b/bindings/node/index.d.ts new file mode 100644 index 0000000..528e060 --- /dev/null +++ b/bindings/node/index.d.ts @@ -0,0 +1,27 @@ +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 = { + language: unknown; + nodeTypeInfo: NodeInfo[]; +}; + +declare const language: Language; +export = language; diff --git a/bindings/node/index.js b/bindings/node/index.js new file mode 100644 index 0000000..39e098d --- /dev/null +++ b/bindings/node/index.js @@ -0,0 +1,11 @@ +const root = require("path").join(__dirname, "..", ".."); + +module.exports = + typeof process.versions.bun === "string" + // Support `bun build --compile` by being statically analyzable enough to find the .node file at build-time + ? require(`../../prebuilds/${process.platform}-${process.arch}/tree-sitter-mc.node`) + : require("node-gyp-build")(root); + +try { + module.exports.nodeTypeInfo = require("../../src/node-types.json"); +} catch (_) {} diff --git a/bindings/python/tests/test_binding.py b/bindings/python/tests/test_binding.py new file mode 100644 index 0000000..f99be81 --- /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_mc + + +class TestLanguage(TestCase): + def test_can_load_grammar(self): + try: + Parser(Language(tree_sitter_mc.language())) + except Exception: + self.fail("Error loading MC grammar") diff --git a/bindings/python/tree_sitter_mc/__init__.py b/bindings/python/tree_sitter_mc/__init__.py new file mode 100644 index 0000000..071d522 --- /dev/null +++ b/bindings/python/tree_sitter_mc/__init__.py @@ -0,0 +1,42 @@ +"""A parser for the MC programming language""" + +from importlib.resources import files as _files + +from ._binding import language + + +def _get_query(name, file): + query = _files(f"{__package__}.queries") / file + globals()[name] = query.read_text() + 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") + + 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_mc/__init__.pyi b/bindings/python/tree_sitter_mc/__init__.pyi new file mode 100644 index 0000000..abf6633 --- /dev/null +++ b/bindings/python/tree_sitter_mc/__init__.pyi @@ -0,0 +1,10 @@ +from typing import Final + +# NOTE: uncomment these to include any queries that this grammar contains: + +# HIGHLIGHTS_QUERY: Final[str] +# INJECTIONS_QUERY: Final[str] +# LOCALS_QUERY: Final[str] +# TAGS_QUERY: Final[str] + +def language() -> object: ... diff --git a/bindings/python/tree_sitter_mc/binding.c b/bindings/python/tree_sitter_mc/binding.c new file mode 100644 index 0000000..e7369e6 --- /dev/null +++ b/bindings/python/tree_sitter_mc/binding.c @@ -0,0 +1,35 @@ +#include + +typedef struct TSLanguage TSLanguage; + +TSLanguage *tree_sitter_mc(void); + +static PyObject* _binding_language(PyObject *Py_UNUSED(self), PyObject *Py_UNUSED(args)) { + return PyCapsule_New(tree_sitter_mc(), "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_mc/py.typed b/bindings/python/tree_sitter_mc/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs new file mode 100644 index 0000000..d8e32ef --- /dev/null +++ b/bindings/rust/build.rs @@ -0,0 +1,21 @@ +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"); + + 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-mc"); +} diff --git a/bindings/rust/lib.rs b/bindings/rust/lib.rs new file mode 100644 index 0000000..2a2d8db --- /dev/null +++ b/bindings/rust/lib.rs @@ -0,0 +1,51 @@ +//! This crate provides MC 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_mc::LANGUAGE; +//! parser +//! .set_language(&language.into()) +//! .expect("Error loading MC parser"); +//! let tree = parser.parse(code, None).unwrap(); +//! assert!(!tree.root_node().has_error()); +//! ``` +//! +//! [`Parser`]: https://docs.rs/tree-sitter/0.25.10/tree_sitter/struct.Parser.html +//! [tree-sitter]: https://tree-sitter.github.io/ + +use tree_sitter_language::LanguageFn; + +extern "C" { + fn tree_sitter_mc() -> *const (); +} + +/// The tree-sitter [`LanguageFn`] for this grammar. +pub const LANGUAGE: LanguageFn = unsafe { LanguageFn::from_raw(tree_sitter_mc) }; + +/// 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"); + +// NOTE: uncomment these to include any queries that this grammar contains: + +// pub const HIGHLIGHTS_QUERY: &str = include_str!("../../queries/highlights.scm"); +// pub const INJECTIONS_QUERY: &str = include_str!("../../queries/injections.scm"); +// pub const LOCALS_QUERY: &str = include_str!("../../queries/locals.scm"); +// 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 MC parser"); + } +} diff --git a/bindings/swift/TreeSitterMc/mc.h b/bindings/swift/TreeSitterMc/mc.h new file mode 100644 index 0000000..83bf9f7 --- /dev/null +++ b/bindings/swift/TreeSitterMc/mc.h @@ -0,0 +1,16 @@ +#ifndef TREE_SITTER_MC_H_ +#define TREE_SITTER_MC_H_ + +typedef struct TSLanguage TSLanguage; + +#ifdef __cplusplus +extern "C" { +#endif + +const TSLanguage *tree_sitter_mc(void); + +#ifdef __cplusplus +} +#endif + +#endif // TREE_SITTER_MC_H_ diff --git a/bindings/swift/TreeSitterMcTests/TreeSitterMcTests.swift b/bindings/swift/TreeSitterMcTests/TreeSitterMcTests.swift new file mode 100644 index 0000000..31b15be --- /dev/null +++ b/bindings/swift/TreeSitterMcTests/TreeSitterMcTests.swift @@ -0,0 +1,12 @@ +import XCTest +import SwiftTreeSitter +import TreeSitterMc + +final class TreeSitterMcTests: XCTestCase { + func testCanLoadGrammar() throws { + let parser = Parser() + let language = Language(language: tree_sitter_mc()) + XCTAssertNoThrow(try parser.setLanguage(language), + "Error loading MC grammar") + } +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..bb6fced --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module git.matthunter.de/matth0930/tree-sitter-mc.git + +go 1.22 + +require github.com/tree-sitter/go-tree-sitter v0.24.0 diff --git a/grammar.js b/grammar.js new file mode 100644 index 0000000..1c7d2b0 --- /dev/null +++ b/grammar.js @@ -0,0 +1,17 @@ +/** + * @file A parser for the MC programming language + * @author Matthias Unterrainer + * @license Apache-2.0 + */ + +/// +// @ts-check + +module.exports = grammar({ + name: "mc", + + rules: { + // TODO: add the actual grammar rules + source_file: $ => "hello" + } +}); diff --git a/package.json b/package.json new file mode 100644 index 0000000..5cd77ef --- /dev/null +++ b/package.json @@ -0,0 +1,51 @@ +{ + "name": "tree-sitter-mc", + "version": "0.1.0", + "description": "A parser for the MC programming language", + "repository": "https://git.matthunter.de/matth0930/tree-sitter-mc.git", + "license": "Apache-2.0", + "author": { + "name": "Matthias Unterrainer" + }, + "main": "bindings/node", + "types": "bindings/node", + "keywords": [ + "incremental", + "parsing", + "tree-sitter", + "mc" + ], + "files": [ + "grammar.js", + "tree-sitter.json", + "binding.gyp", + "prebuilds/**", + "bindings/node/*", + "queries/*", + "src/**", + "*.wasm" + ], + "dependencies": { + "node-addon-api": "^8.5.0", + "node-gyp-build": "^4.8.4" + }, + "devDependencies": { + "prebuildify": "^6.0.1", + "tree-sitter": "^0.22.4", + "tree-sitter-cli": "^0.25.10" + }, + "peerDependencies": { + "tree-sitter": "^0.22.4" + }, + "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" + } +} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..29b7fb1 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,29 @@ +[build-system] +requires = ["setuptools>=62.4.0", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "tree-sitter-mc" +description = "A parser for the MC programming language" +version = "0.1.0" +keywords = ["incremental", "parsing", "tree-sitter", "mc"] +classifiers = [ + "Intended Audience :: Developers", + "Topic :: Software Development :: Compilers", + "Topic :: Text Processing :: Linguistic", + "Typing :: Typed", +] +authors = [{ name = "Matthias Unterrainer" }] +requires-python = ">=3.10" +license.text = "Apache-2.0" +readme = "README.md" + +[project.urls] +Homepage = "https://git.matthunter.de/matth0930/tree-sitter-mc.git" + +[project.optional-dependencies] +core = ["tree-sitter~=0.24"] + +[tool.cibuildwheel] +build = "cp310-*" +build-frontend = "build" diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..74f1150 --- /dev/null +++ b/setup.py @@ -0,0 +1,77 @@ +from os import path +from sysconfig import get_config_var + +from setuptools import Extension, find_packages, setup +from setuptools.command.build import build +from setuptools.command.build_ext import build_ext +from setuptools.command.egg_info import egg_info +from wheel.bdist_wheel import bdist_wheel + + +class Build(build): + def run(self): + if path.isdir("queries"): + dest = path.join(self.build_lib, "tree_sitter_mc", "queries") + self.copy_tree("queries", dest) + super().run() + + +class BuildExt(build_ext): + def build_extension(self, ext: Extension): + if self.compiler.compiler_type != "msvc": + ext.extra_compile_args = ["-std=c11", "-fvisibility=hidden"] + else: + ext.extra_compile_args = ["/std:c11", "/utf-8"] + if path.exists("src/scanner.c"): + ext.sources.append("src/scanner.c") + if ext.py_limited_api: + ext.define_macros.append(("Py_LIMITED_API", "0x030A0000")) + super().build_extension(ext) + + +class BdistWheel(bdist_wheel): + def get_tag(self): + python, abi, platform = super().get_tag() + if python.startswith("cp"): + python, abi = "cp310", "abi3" + return python, abi, platform + + +class EggInfo(egg_info): + def find_sources(self): + super().find_sources() + self.filelist.recursive_include("queries", "*.scm") + self.filelist.include("src/tree_sitter/*.h") + + +setup( + packages=find_packages("bindings/python"), + package_dir={"": "bindings/python"}, + package_data={ + "tree_sitter_mc": ["*.pyi", "py.typed"], + "tree_sitter_mc.queries": ["*.scm"], + }, + ext_package="tree_sitter_mc", + ext_modules=[ + Extension( + name="_binding", + sources=[ + "bindings/python/tree_sitter_mc/binding.c", + "src/parser.c", + ], + define_macros=[ + ("PY_SSIZE_T_CLEAN", None), + ("TREE_SITTER_HIDE_SYMBOLS", None), + ], + include_dirs=["src"], + py_limited_api=not get_config_var("Py_GIL_DISABLED"), + ) + ], + cmdclass={ + "build": Build, + "build_ext": BuildExt, + "bdist_wheel": BdistWheel, + "egg_info": EggInfo, + }, + zip_safe=False +) diff --git a/tree-sitter.json b/tree-sitter.json new file mode 100644 index 0000000..a2ebf83 --- /dev/null +++ b/tree-sitter.json @@ -0,0 +1,39 @@ +{ + "$schema": "https://tree-sitter.github.io/tree-sitter/assets/schemas/config.schema.json", + "grammars": [ + { + "name": "mc", + "camelcase": "Mc", + "title": "MC", + "scope": "source.mc", + "file-types": [ + "mc", + "c" + ], + "injection-regex": "^mc$", + "class-name": "TreeSitterMc" + } + ], + "metadata": { + "version": "0.1.0", + "license": "Apache-2.0", + "description": "A parser for the MC programming language", + "authors": [ + { + "name": "Matthias Unterrainer" + } + ], + "links": { + "repository": "https://git.matthunter.de/matth0930/tree-sitter-mc.git" + } + }, + "bindings": { + "c": true, + "go": true, + "node": true, + "python": true, + "rust": true, + "swift": true, + "zig": false + } +} \ No newline at end of file