140 lines
5.3 KiB
Zig
140 lines
5.3 KiB
Zig
const std = @import("std");
|
|
const cbor = @import("cbor");
|
|
const treez = @import("treez");
|
|
|
|
pub const tss = @import("ts_serializer.zig");
|
|
|
|
const verbose = false;
|
|
|
|
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) |_| 3 else 2);
|
|
|
|
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);
|
|
if (verbose)
|
|
std.log.info("file_type {s} highlights {d} bytes", .{ file_type.name, highlights_cb.len });
|
|
|
|
const errors_in = try treez.Query.create(lang, "(ERROR) @error");
|
|
const ts_errors_in: *tss.TSQuery = @alignCast(@ptrCast(errors_in));
|
|
|
|
const errors_cb = try tss.toCbor(ts_errors_in, allocator);
|
|
defer allocator.free(errors_cb);
|
|
|
|
try cbor.writeValue(writer, "errors");
|
|
try cbor.writeValue(writer, errors_cb);
|
|
if (verbose)
|
|
std.log.info("file_type {s} errors {d} bytes", .{ file_type.name, errors_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);
|
|
if (verbose)
|
|
std.log.info("file_type {s} injections {d} bytes", .{ file_type.name, injections_cb.len });
|
|
}
|
|
}
|
|
|
|
try output_file.writeAll(output.items);
|
|
if (verbose)
|
|
std.log.info("file_types total {d} bytes", .{output.items.len});
|
|
}
|
|
|
|
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;
|
|
}
|