diff --git a/lib/sdl3/parser/src/codegen.zig b/lib/sdl3/parser/src/codegen.zig index ca758d8..a1df115 100644 --- a/lib/sdl3/parser/src/codegen.zig +++ b/lib/sdl3/parser/src/codegen.zig @@ -82,6 +82,7 @@ pub const CodeGen = struct { fn writeHeader(self: *CodeGen) !void { const header = + \\const std = @import("std"); \\pub const c = @import("c.zig").c; \\ \\ @@ -617,6 +618,7 @@ test "generate opaque type" { defer std.testing.allocator.free(output); const expected = + \\const std = @import("std"); \\pub const c = @import("c.zig").c; \\ \\pub const GPUDevice = opaque {}; diff --git a/lib/sdl3/parser/src/patterns.zig b/lib/sdl3/parser/src/patterns.zig index 237e288..5429074 100644 --- a/lib/sdl3/parser/src/patterns.zig +++ b/lib/sdl3/parser/src/patterns.zig @@ -871,7 +871,57 @@ pub const Scanner = struct { // Parse: ReturnType SDLCALL FunctionName(params); const doc = self.consumePendingDocComment(); - const text = func_text.items; + var text = func_text.items; + + // Strip format string attribute macros + const macros_to_strip = [_][]const u8{ + "SDL_PRINTF_FORMAT_STRING ", + "SDL_WPRINTF_FORMAT_STRING ", + "SDL_SCANF_FORMAT_STRING ", + }; + for (macros_to_strip) |macro| { + while (std.mem.indexOf(u8, text, macro)) |pos| { + // Create new string without the macro + const before = text[0..pos]; + const after = text[pos + macro.len ..]; + const new_text = try std.fmt.allocPrint(self.allocator, "{s}{s}", .{ before, after }); + defer self.allocator.free(new_text); + + // Replace func_text content + func_text.clearRetainingCapacity(); + try func_text.appendSlice(self.allocator, new_text); + text = func_text.items; + } + } + + // Strip vararg function macros from end (e.g., SDL_PRINTF_VARARG_FUNC(1)) + const vararg_macros = [_][]const u8{ + "SDL_PRINTF_VARARG_FUNC", + "SDL_PRINTF_VARARG_FUNCV", + "SDL_WPRINTF_VARARG_FUNC", + "SDL_SCANF_VARARG_FUNC", + }; + for (vararg_macros) |macro| { + if (std.mem.indexOf(u8, text, macro)) |pos| { + // Find semicolon after this position + if (std.mem.indexOfScalarPos(u8, text, pos, ';')) |semi_pos| { + // Find the closing ) before semicolon + var paren_pos = semi_pos; + while (paren_pos > pos and text[paren_pos] != ')') : (paren_pos -= 1) {} + if (text[paren_pos] == ')') { + // Remove from macro to ) + const before = text[0..pos]; + const after = text[paren_pos + 1 ..]; + const new_text = try std.fmt.allocPrint(self.allocator, "{s}{s}", .{ before, after }); + defer self.allocator.free(new_text); + + func_text.clearRetainingCapacity(); + try func_text.appendSlice(self.allocator, new_text); + text = func_text.items; + } + } + } + } // Find SDLCALL to split return type and function name const sdlcall_pos = std.mem.indexOf(u8, text, "SDLCALL ") orelse return null; diff --git a/lib/sdl3/parser/src/types.zig b/lib/sdl3/parser/src/types.zig index d4fe376..66ada93 100644 --- a/lib/sdl3/parser/src/types.zig +++ b/lib/sdl3/parser/src/types.zig @@ -27,6 +27,7 @@ pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 { if (std.mem.eql(u8, trimmed, "double")) return try allocator.dupe(u8, "f64"); if (std.mem.eql(u8, trimmed, "char")) return try allocator.dupe(u8, "u8"); if (std.mem.eql(u8, trimmed, "int")) return try allocator.dupe(u8, "c_int"); + if (std.mem.eql(u8, trimmed, "va_list")) return try allocator.dupe(u8, "std.builtin.VaList"); // SDL integer types if (std.mem.eql(u8, trimmed, "Uint8")) return try allocator.dupe(u8, "u8"); @@ -45,6 +46,7 @@ pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 { if (std.mem.eql(u8, trimmed, "char *")) return try allocator.dupe(u8, "[*c]u8"); if (std.mem.eql(u8, trimmed, "void *")) return try allocator.dupe(u8, "?*anyopaque"); if (std.mem.eql(u8, trimmed, "const void *")) return try allocator.dupe(u8, "?*const anyopaque"); + if (std.mem.eql(u8, trimmed, "void **")) return try allocator.dupe(u8, "[*c]?*anyopaque"); if (std.mem.eql(u8, trimmed, "const Uint8 *")) return try allocator.dupe(u8, "[*c]const u8"); if (std.mem.eql(u8, trimmed, "Uint8 *")) return try allocator.dupe(u8, "[*c]u8");