From 5cfeba9c0d3af1879c4c1e9f682acbb0cfe2d895 Mon Sep 17 00:00:00 2001 From: ObserverOfTime Date: Fri, 24 Jan 2025 16:55:24 +0200 Subject: [PATCH] feat(bindings): add opt-in zig bindings --- cli/loader/src/lib.rs | 2 + cli/src/init.rs | 43 +++++++++++++-- cli/src/templates/build.zig | 61 ++++++++++++++++++++++ cli/src/templates/build.zig.zon | 14 +++++ cli/src/templates/gitattributes | 4 ++ cli/src/templates/gitignore | 5 ++ docs/src/assets/schemas/config.schema.json | 4 ++ 7 files changed, 128 insertions(+), 5 deletions(-) create mode 100644 cli/src/templates/build.zig create mode 100644 cli/src/templates/build.zig.zon diff --git a/cli/loader/src/lib.rs b/cli/loader/src/lib.rs index e34c671b..7d309265 100644 --- a/cli/loader/src/lib.rs +++ b/cli/loader/src/lib.rs @@ -239,6 +239,7 @@ pub struct Bindings { pub python: bool, pub rust: bool, pub swift: bool, + pub zig: bool, } impl Default for Bindings { @@ -252,6 +253,7 @@ impl Default for Bindings { python: true, rust: true, swift: true, + zig: false, } } } diff --git a/cli/src/init.rs b/cli/src/init.rs index a2b9edbb..72ad9cad 100644 --- a/cli/src/init.rs +++ b/cli/src/init.rs @@ -95,6 +95,9 @@ const TEST_BINDING_PY_TEMPLATE: &str = include_str!("./templates/test_binding.py const PACKAGE_SWIFT_TEMPLATE: &str = include_str!("./templates/package.swift"); const TESTS_SWIFT_TEMPLATE: &str = include_str!("./templates/tests.swift"); +const BUILD_ZIG_TEMPLATE: &str = include_str!("./templates/build.zig"); +const BUILD_ZIG_ZON_TEMPLATE: &str = include_str!("./templates/build.zig.zon"); + const TREE_SITTER_JSON_SCHEMA: &str = "https://tree-sitter.github.io/tree-sitter/assets/schemas/config.schema.json"; @@ -314,9 +317,19 @@ pub fn generate_grammar_files( } // Write .gitignore file - missing_path(repo_path.join(".gitignore"), |path| { - generate_file(path, GITIGNORE_TEMPLATE, language_name, &generate_opts) - })?; + missing_path_else( + repo_path.join(".gitignore"), + allow_update, + |path| generate_file(path, GITIGNORE_TEMPLATE, language_name, &generate_opts), + |path| { + let contents = fs::read_to_string(path)?; + if !contents.contains("Zig artifacts") { + eprintln!("Replacing .gitignore"); + generate_file(path, GITIGNORE_TEMPLATE, language_name, &generate_opts)?; + } + Ok(()) + }, + )?; // Write .gitattributes file missing_path_else( @@ -324,8 +337,17 @@ pub fn generate_grammar_files( allow_update, |path| generate_file(path, GITATTRIBUTES_TEMPLATE, language_name, &generate_opts), |path| { - let contents = fs::read_to_string(path)?; - write_file(path, contents.replace("bindings/c/* ", "bindings/c/** "))?; + let mut contents = fs::read_to_string(path)?; + contents = contents.replace("bindings/c/* ", "bindings/c/** "); + if !contents.contains("Zig bindings") { + contents.push('\n'); + contents.push_str(indoc! {" + # Zig bindings + build.zig linguist-generated + build.zig.zon linguist-generated + "}); + } + write_file(path, contents)?; Ok(()) }, )?; @@ -658,6 +680,17 @@ pub fn generate_grammar_files( })?; } + // Generate Zig bindings + if tree_sitter_config.bindings.zig { + missing_path(repo_path.join("build.zig"), |path| { + generate_file(path, BUILD_ZIG_TEMPLATE, language_name, &generate_opts) + })?; + + missing_path(repo_path.join("build.zig.zon"), |path| { + generate_file(path, BUILD_ZIG_ZON_TEMPLATE, language_name, &generate_opts) + })?; + } + Ok(()) } diff --git a/cli/src/templates/build.zig b/cli/src/templates/build.zig new file mode 100644 index 00000000..9d237f4e --- /dev/null +++ b/cli/src/templates/build.zig @@ -0,0 +1,61 @@ +const std = @import("std"); + +pub fn build(b: *std.Build) !void { + const target = b.standardTargetOptions(.{}); + const optimize = b.standardOptimizeOption(.{}); + + const shared = b.option(bool, "build-shared", "Build a shared library") orelse true; + const reuse_alloc = b.option(bool, "reuse-allocator", "Reuse the library allocator") orelse false; + + const lib: *std.Build.Step.Compile = if (shared) b.addSharedLibrary(.{ + .name = "tree-sitter-PARSER_NAME", + .pic = true, + .target = target, + .optimize = optimize, + .link_libc = true, + }) else b.addStaticLibrary(.{ + .name = "tree-sitter-PARSER_NAME", + .target = target, + .optimize = optimize, + .link_libc = true, + }); + + lib.addCSourceFile(.{ + .file = b.path("src/parser.c"), + .flags = &.{"-std=c11"}, + }); + if (hasScanner(b.build_root.handle)) { + lib.addCSourceFile(.{ + .file = b.path("src/scanner.c"), + .flags = &.{"-std=c11"}, + }); + } + + if (reuse_alloc) { + lib.root_module.addCMacro("TREE_SITTER_REUSE_ALLOCATOR", ""); + } + if (optimize == .Debug) { + lib.root_module.addCMacro("TREE_SITTER_DEBUG", ""); + } + + lib.addIncludePath(b.path("src")); + lib.installHeadersDirectory(b.path("bindings/c"), ".", .{}); + + b.installArtifact(lib); + b.installFile("src/node-types.json", "node-types.json"); + b.installDirectory(.{ + .source_dir = b.path("queries"), + .install_dir = .prefix, + .install_subdir = "queries", + .include_extensions = &.{"scm"} + }); + + const test_cmd = b.addSystemCommand(&.{"tree-sitter", "test"}); + const test_step = b.step("test", "Run parser tests"); + test_step.dependOn(&test_cmd.step); +} + +inline fn hasScanner(dir: std.fs.Dir) bool { + dir.access("src/scanner.c", .{}) catch return false; + return true; +} diff --git a/cli/src/templates/build.zig.zon b/cli/src/templates/build.zig.zon new file mode 100644 index 00000000..eff723d7 --- /dev/null +++ b/cli/src/templates/build.zig.zon @@ -0,0 +1,14 @@ +.{ + .name = "tree_sitter_PARSER_NAME", + .version = "PARSER_VERSION", + .dependencies = .{}, + .paths = .{ + "build.zig", + "build.zig.zon", + "bindings/c", + "src", + "queries", + "LICENSE", + "README.md", + }, +} diff --git a/cli/src/templates/gitattributes b/cli/src/templates/gitattributes index 4d7e4402..79475a5e 100644 --- a/cli/src/templates/gitattributes +++ b/cli/src/templates/gitattributes @@ -35,3 +35,7 @@ go.sum linguist-generated bindings/swift/** linguist-generated Package.swift linguist-generated Package.resolved linguist-generated + +# Zig bindings +build.zig linguist-generated +build.zig.zon linguist-generated diff --git a/cli/src/templates/gitignore b/cli/src/templates/gitignore index 4e880d55..bc9e191a 100644 --- a/cli/src/templates/gitignore +++ b/cli/src/templates/gitignore @@ -28,6 +28,11 @@ dist/ *.exp *.lib +# Zig artifacts +.zig-cache/ +zig-cache/ +zig-out/ + # Example dirs /examples/*/ diff --git a/docs/src/assets/schemas/config.schema.json b/docs/src/assets/schemas/config.schema.json index 481acc58..3968af5a 100644 --- a/docs/src/assets/schemas/config.schema.json +++ b/docs/src/assets/schemas/config.schema.json @@ -272,6 +272,10 @@ "swift": { "type": "boolean", "default": true + }, + "zig": { + "type": "boolean", + "default": false } }, "additionalProperties": false