feat: use binary tree-sitter queries created at compile time
This commit is contained in:
parent
56f33e51a6
commit
44bbf996bd
6 changed files with 645 additions and 134 deletions
123
src/ts_bin_query_gen.zig
Normal file
123
src/ts_bin_query_gen.zig
Normal file
|
@ -0,0 +1,123 @@
|
|||
const std = @import("std");
|
||||
const cbor = @import("cbor");
|
||||
const treez = @import("treez");
|
||||
|
||||
pub const tss = @import("ts_serializer.zig");
|
||||
|
||||
pub fn main() anyerror!void {
|
||||
const allocator = std.heap.c_allocator;
|
||||
const args = try std.process.argsAlloc(allocator);
|
||||
|
||||
var opt_output_file_path: ?[]const u8 = null;
|
||||
|
||||
var i: usize = 1;
|
||||
while (i < args.len) : (i += 1) {
|
||||
const arg = args[i];
|
||||
if (opt_output_file_path != null) fatal("duplicated {s} argument", .{arg});
|
||||
opt_output_file_path = args[i];
|
||||
}
|
||||
|
||||
const output_file_path = opt_output_file_path orelse fatal("missing output file", .{});
|
||||
var output_file = std.fs.cwd().createFile(output_file_path, .{}) catch |err| {
|
||||
fatal("unable to open '{s}': {s}", .{ output_file_path, @errorName(err) });
|
||||
};
|
||||
defer output_file.close();
|
||||
|
||||
var output = std.ArrayList(u8).init(allocator);
|
||||
defer output.deinit();
|
||||
const writer = output.writer();
|
||||
|
||||
try cbor.writeMapHeader(writer, file_types.len);
|
||||
|
||||
for (file_types) |file_type| {
|
||||
const lang = file_type.lang_fn() orelse std.debug.panic("tree-sitter parser function failed for language: {s}", .{file_type.name});
|
||||
|
||||
try cbor.writeValue(writer, file_type.name);
|
||||
try cbor.writeMapHeader(writer, if (file_type.injections) |_| 2 else 1);
|
||||
|
||||
const highlights_in = try treez.Query.create(lang, file_type.highlights);
|
||||
const ts_highlights_in: *tss.TSQuery = @alignCast(@ptrCast(highlights_in));
|
||||
|
||||
const highlights_cb = try tss.toCbor(ts_highlights_in, allocator);
|
||||
defer allocator.free(highlights_cb);
|
||||
|
||||
try cbor.writeValue(writer, "highlights");
|
||||
try cbor.writeValue(writer, highlights_cb);
|
||||
std.log.info("file_type {s} highlights {d} bytes", .{ file_type.name, highlights_cb.len });
|
||||
|
||||
if (file_type.injections) |injections| {
|
||||
const injections_in = try treez.Query.create(lang, injections);
|
||||
const ts_injections_in: *tss.TSQuery = @alignCast(@ptrCast(injections_in));
|
||||
|
||||
const injections_cb = try tss.toCbor(ts_injections_in, allocator);
|
||||
defer allocator.free(injections_cb);
|
||||
|
||||
try cbor.writeValue(writer, "injections");
|
||||
try cbor.writeValue(writer, injections_cb);
|
||||
std.log.info("file_type {s} injections {d} bytes", .{ file_type.name, injections_cb.len });
|
||||
}
|
||||
}
|
||||
|
||||
try output_file.writeAll(output.items);
|
||||
}
|
||||
|
||||
fn fatal(comptime format: []const u8, args: anytype) noreturn {
|
||||
std.debug.print(format, args);
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
pub const file_types = load_file_types(@import("file_types.zig"));
|
||||
|
||||
const FileType = struct {
|
||||
name: []const u8,
|
||||
lang_fn: LangFn,
|
||||
highlights: [:0]const u8,
|
||||
injections: ?[:0]const u8,
|
||||
};
|
||||
const LangFn = *const fn () callconv(.C) ?*const treez.Language;
|
||||
|
||||
fn load_file_types(comptime Namespace: type) []const FileType {
|
||||
comptime switch (@typeInfo(Namespace)) {
|
||||
.@"struct" => |info| {
|
||||
var count = 0;
|
||||
for (info.decls) |_| count += 1;
|
||||
var construct_types: [count]FileType = undefined;
|
||||
var i = 0;
|
||||
for (info.decls) |decl| {
|
||||
const lang = decl.name;
|
||||
const args = @field(Namespace, lang);
|
||||
construct_types[i] = .{
|
||||
.name = lang,
|
||||
.lang_fn = if (@hasField(@TypeOf(args), "parser")) args.parser else get_parser(lang),
|
||||
.highlights = if (@hasField(@TypeOf(args), "highlights"))
|
||||
@embedFile(args.highlights)
|
||||
else if (@hasField(@TypeOf(args), "highlights_list"))
|
||||
@embedFile(args.highlights_list[0]) ++ "\n" ++ @embedFile(args.highlights_list[1])
|
||||
else
|
||||
@embedFile("tree-sitter-" ++ lang ++ "/queries/highlights.scm"),
|
||||
.injections = if (@hasField(@TypeOf(args), "injections"))
|
||||
@embedFile(args.injections)
|
||||
else
|
||||
null,
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
const types = construct_types;
|
||||
return &types;
|
||||
},
|
||||
else => @compileError("expected tuple or struct type"),
|
||||
};
|
||||
}
|
||||
|
||||
fn get_parser(comptime lang: []const u8) LangFn {
|
||||
const language_name = ft_func_name(lang);
|
||||
return @extern(?LangFn, .{ .name = "tree_sitter_" ++ language_name }) orelse @compileError(std.fmt.comptimePrint("Cannot find extern tree_sitter_{s}", .{language_name}));
|
||||
}
|
||||
|
||||
fn ft_func_name(comptime lang: []const u8) []const u8 {
|
||||
var transform: [lang.len]u8 = undefined;
|
||||
for (lang, 0..) |c, i|
|
||||
transform[i] = if (c == '-') '_' else c;
|
||||
const func_name = transform;
|
||||
return &func_name;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue