feat(bindings): add opt-in zig bindings

This commit is contained in:
ObserverOfTime 2025-01-24 16:55:24 +02:00 committed by Amaan Qureshi
parent 3074c0adf2
commit 5cfeba9c0d
7 changed files with 128 additions and 5 deletions

View file

@ -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,
}
}
}

View file

@ -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(())
}

View file

@ -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;
}

View file

@ -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",
},
}

View file

@ -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

View file

@ -28,6 +28,11 @@ dist/
*.exp
*.lib
# Zig artifacts
.zig-cache/
zig-cache/
zig-out/
# Example dirs
/examples/*/

View file

@ -272,6 +272,10 @@
"swift": {
"type": "boolean",
"default": true
},
"zig": {
"type": "boolean",
"default": false
}
},
"additionalProperties": false