179 lines
6.6 KiB
Zig
179 lines
6.6 KiB
Zig
const std = @import("std");
|
|
const patterns = @import("patterns.zig");
|
|
const codegen = @import("codegen.zig");
|
|
|
|
pub fn main() !void {
|
|
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
defer {
|
|
const leaked = gpa.deinit();
|
|
if (leaked == .leak) {
|
|
std.debug.print("Memory leaked!\n", .{});
|
|
}
|
|
}
|
|
const allocator = gpa.allocator();
|
|
|
|
const args = try std.process.argsAlloc(allocator);
|
|
defer std.process.argsFree(allocator, args);
|
|
|
|
if (args.len < 2) {
|
|
std.debug.print("Usage: {s} <header-file> [--output=<output-file>] [--mocks=<mock-file>]\n", .{args[0]});
|
|
std.debug.print("Example: {s} ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig\n", .{args[0]});
|
|
std.debug.print(" {s} ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig --mocks=gpu_mock.c\n", .{args[0]});
|
|
std.debug.print(" {s} ../SDL/include/SDL3/SDL_gpu.h > gpu.zig\n", .{args[0]});
|
|
return error.MissingArgument;
|
|
}
|
|
|
|
const header_path = args[1];
|
|
|
|
var output_file: ?[]const u8 = null;
|
|
var mock_output_file: ?[]const u8 = null;
|
|
|
|
// Parse additional flags
|
|
for (args[2..]) |arg| {
|
|
const output_prefix = "--output=";
|
|
const mocks_prefix = "--mocks=";
|
|
if (std.mem.startsWith(u8, arg, output_prefix)) {
|
|
output_file = arg[output_prefix.len..];
|
|
} else if (std.mem.startsWith(u8, arg, mocks_prefix)) {
|
|
mock_output_file = arg[mocks_prefix.len..];
|
|
} else {
|
|
std.debug.print("Error: Unknown argument '{s}'\n", .{arg});
|
|
std.debug.print("Usage: {s} <header-file> [--output=<output-file>] [--mocks=<mock-file>]\n", .{args[0]});
|
|
return error.InvalidArgument;
|
|
}
|
|
}
|
|
|
|
std.debug.print("SDL3 Header Parser\n", .{});
|
|
std.debug.print("==================\n\n", .{});
|
|
std.debug.print("Parsing: {s}\n\n", .{header_path});
|
|
|
|
// Read the header file
|
|
const source = try std.fs.cwd().readFileAlloc(allocator, header_path, 10 * 1024 * 1024); // 10MB max
|
|
defer allocator.free(source);
|
|
|
|
// Parse declarations
|
|
var scanner = patterns.Scanner.init(allocator, source);
|
|
const decls = try scanner.scan();
|
|
defer {
|
|
for (decls) |decl| {
|
|
switch (decl) {
|
|
.opaque_type => |opaque_decl| {
|
|
allocator.free(opaque_decl.name);
|
|
if (opaque_decl.doc_comment) |doc| allocator.free(doc);
|
|
},
|
|
.enum_decl => |enum_decl| {
|
|
allocator.free(enum_decl.name);
|
|
if (enum_decl.doc_comment) |doc| allocator.free(doc);
|
|
for (enum_decl.values) |val| {
|
|
allocator.free(val.name);
|
|
if (val.value) |v| allocator.free(v);
|
|
if (val.comment) |c| allocator.free(c);
|
|
}
|
|
allocator.free(enum_decl.values);
|
|
},
|
|
.struct_decl => |struct_decl| {
|
|
allocator.free(struct_decl.name);
|
|
if (struct_decl.doc_comment) |doc| allocator.free(doc);
|
|
for (struct_decl.fields) |field| {
|
|
allocator.free(field.name);
|
|
allocator.free(field.type_name);
|
|
if (field.comment) |c| allocator.free(c);
|
|
}
|
|
allocator.free(struct_decl.fields);
|
|
},
|
|
.flag_decl => |flag_decl| {
|
|
allocator.free(flag_decl.name);
|
|
allocator.free(flag_decl.underlying_type);
|
|
if (flag_decl.doc_comment) |doc| allocator.free(doc);
|
|
for (flag_decl.flags) |flag| {
|
|
allocator.free(flag.name);
|
|
allocator.free(flag.value);
|
|
if (flag.comment) |c| allocator.free(c);
|
|
}
|
|
allocator.free(flag_decl.flags);
|
|
},
|
|
.function_decl => |func| {
|
|
allocator.free(func.name);
|
|
allocator.free(func.return_type);
|
|
if (func.doc_comment) |doc| allocator.free(doc);
|
|
for (func.params) |param| {
|
|
allocator.free(param.name);
|
|
allocator.free(param.type_name);
|
|
}
|
|
allocator.free(func.params);
|
|
},
|
|
}
|
|
}
|
|
allocator.free(decls);
|
|
}
|
|
|
|
std.debug.print("Found {d} declarations\n", .{decls.len});
|
|
|
|
// Count each type
|
|
var opaque_count: usize = 0;
|
|
var enum_count: usize = 0;
|
|
var struct_count: usize = 0;
|
|
var flag_count: usize = 0;
|
|
var func_count: usize = 0;
|
|
|
|
for (decls) |decl| {
|
|
switch (decl) {
|
|
.opaque_type => opaque_count += 1,
|
|
.enum_decl => enum_count += 1,
|
|
.struct_decl => struct_count += 1,
|
|
.flag_decl => flag_count += 1,
|
|
.function_decl => func_count += 1,
|
|
}
|
|
}
|
|
|
|
std.debug.print(" - Opaque types: {d}\n", .{opaque_count});
|
|
std.debug.print(" - Enums: {d}\n", .{enum_count});
|
|
std.debug.print(" - Structs: {d}\n", .{struct_count});
|
|
std.debug.print(" - Flags: {d}\n", .{flag_count});
|
|
std.debug.print(" - Functions: {d}\n\n", .{func_count});
|
|
|
|
// Generate Zig code
|
|
const output = try codegen.CodeGen.generate(allocator, decls);
|
|
defer allocator.free(output);
|
|
|
|
// Write to file or stdout
|
|
if (output_file) |file_path| {
|
|
try std.fs.cwd().writeFile(.{
|
|
.sub_path = file_path,
|
|
.data = output,
|
|
});
|
|
std.debug.print("Generated: {s}\n", .{file_path});
|
|
} else {
|
|
_ = try std.posix.write(std.posix.STDOUT_FILENO, output);
|
|
}
|
|
|
|
// Parse and format the AST for validation
|
|
const output_z = try allocator.dupeZ(u8, output);
|
|
defer allocator.free(output_z);
|
|
|
|
var ast = try std.zig.Ast.parse(allocator, output_z, .zig);
|
|
defer ast.deinit(allocator);
|
|
|
|
// Check for parse errors
|
|
if (ast.errors.len > 0) {
|
|
std.debug.print("\nWarning: {d} syntax errors detected in generated code\n", .{ast.errors.len});
|
|
}
|
|
|
|
// Generate C mocks if requested
|
|
if (mock_output_file) |mock_path| {
|
|
const mock_codegen = @import("mock_codegen.zig");
|
|
const mock_output = try mock_codegen.MockCodeGen.generate(allocator, decls);
|
|
defer allocator.free(mock_output);
|
|
|
|
try std.fs.cwd().writeFile(.{
|
|
.sub_path = mock_path,
|
|
.data = mock_output,
|
|
});
|
|
std.debug.print("Generated C mocks: {s}\n", .{mock_path});
|
|
}
|
|
}
|
|
|
|
test "basic test" {
|
|
try std.testing.expect(true);
|
|
}
|