diff --git a/lib/sdl3/parser/src/patterns.zig b/lib/sdl3/parser/src/patterns.zig index 98d485f..d141d34 100644 --- a/lib/sdl3/parser/src/patterns.zig +++ b/lib/sdl3/parser/src/patterns.zig @@ -655,6 +655,7 @@ pub const Scanner = struct { fn parseStructField(self: *Scanner, line: []const u8) !?FieldDecl { const trimmed = std.mem.trim(u8, line, " \t\r"); + std.debug.print("DEBUG parseStructField: trimmed='{s}'\n", .{trimmed}); if (trimmed.len == 0) return null; if (std.mem.startsWith(u8, trimmed, "//")) return null; if (std.mem.startsWith(u8, trimmed, "/*")) return null; @@ -677,6 +678,40 @@ pub const Scanner = struct { } } + std.debug.print("DEBUG parseStructField: field_part='{s}'\n", .{field_part}); + + // Check for function pointer field: RetType (SDLCALL *field_name)(params) + if (std.mem.indexOf(u8, field_part, "(SDLCALL *")) |sdlcall_pos| { + std.debug.print("DEBUG: Found SDLCALL function pointer in: {s}\n", .{field_part}); + // Find the * after SDLCALL + const after_sdlcall = field_part[sdlcall_pos + 10..]; // Skip "(SDLCALL *" + std.debug.print("DEBUG: after_sdlcall: {s}\n", .{after_sdlcall}); + if (std.mem.indexOf(u8, after_sdlcall, ")")) |close_paren| { + const field_name = std.mem.trim(u8, after_sdlcall[0..close_paren], " \t"); + std.debug.print("DEBUG: field_name extracted: {s}\n", .{field_name}); + + // The entire thing is the type (we'll convert to Zig function pointer syntax later) + return FieldDecl{ + .name = try self.allocator.dupe(u8, field_name), + .type_name = try self.allocator.dupe(u8, std.mem.trim(u8, field_part, " \t")), + .comment = comment, + }; + } + } else if (std.mem.indexOf(u8, field_part, "(*")) |star_pos| { + // Handle non-SDLCALL function pointers: RetType (*field_name)(params) + const after_star = field_part[star_pos + 2..]; // Skip "(*" + if (std.mem.indexOf(u8, after_star, ")")) |close_paren| { + const field_name = std.mem.trim(u8, after_star[0..close_paren], " \t"); + + // The entire thing is the type (we'll convert to Zig function pointer syntax later) + return FieldDecl{ + .name = try self.allocator.dupe(u8, field_name), + .type_name = try self.allocator.dupe(u8, std.mem.trim(u8, field_part, " \t")), + .comment = comment, + }; + } + } + // Check if this line contains multiple comma-separated fields (e.g., "int x, y;") // Only split on commas that are not inside nested structures (ignore for now) const field_trimmed = std.mem.trim(u8, field_part, " \t"); diff --git a/lib/sdl3/parser/src/types.zig b/lib/sdl3/parser/src/types.zig index 4278c21..f76bef3 100644 --- a/lib/sdl3/parser/src/types.zig +++ b/lib/sdl3/parser/src/types.zig @@ -6,6 +6,11 @@ const Allocator = std.mem.Allocator; pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 { const trimmed = std.mem.trim(u8, c_type, " \t"); + // Handle function pointers: RetType (SDLCALL *name)(params) -> *const fn(params) callconv(.C) RetType + if (std.mem.indexOf(u8, trimmed, "(SDLCALL *") orelse std.mem.indexOf(u8, trimmed, "(*")) |star_pos| { + return try convertFunctionPointerType(trimmed, allocator); + } + // Handle array types: "Uint8[2]" -> "[2]u8" if (std.mem.indexOf(u8, trimmed, "[")) |bracket_pos| { const base_type = std.mem.trim(u8, trimmed[0..bracket_pos], " \t"); @@ -141,6 +146,77 @@ pub fn getCastType(zig_type: []const u8) CastType { return .none; } +/// Convert C function pointer type to Zig function pointer syntax +/// Example: Sint64 (SDLCALL *size)(void *userdata) -> *const fn (?*anyopaque) callconv(.C) i64 +fn convertFunctionPointerType(c_type: []const u8, allocator: Allocator) ![]const u8 { + // Pattern: ReturnType (SDLCALL *name)(params) or ReturnType (*name)(params) + + // Find the return type (everything before the opening paren) + const open_paren = std.mem.indexOf(u8, c_type, "(") orelse return try allocator.dupe(u8, c_type); + const return_type_str = std.mem.trim(u8, c_type[0..open_paren], " \t"); + + // Find the parameters (between the last ( and the last )) + const last_open_paren = std.mem.lastIndexOf(u8, c_type, "(") orelse return try allocator.dupe(u8, c_type); + const last_close_paren = std.mem.lastIndexOf(u8, c_type, ")") orelse return try allocator.dupe(u8, c_type); + + if (last_close_paren <= last_open_paren) return try allocator.dupe(u8, c_type); + + const params_str = std.mem.trim(u8, c_type[last_open_paren + 1 .. last_close_paren], " \t"); + + // Convert return type + const zig_return = try convertType(return_type_str, allocator); + defer allocator.free(zig_return); + + // Convert parameters + var params_list = std.ArrayList([]const u8).init(allocator); + defer { + for (params_list.items) |param| { + allocator.free(param); + } + params_list.deinit(); + } + + // Parse comma-separated parameters + var param_iter = std.mem.splitScalar(u8, params_str, ','); + while (param_iter.next()) |param| { + const trimmed_param = std.mem.trim(u8, param, " \t"); + if (trimmed_param.len == 0) continue; + + // Extract just the type (remove parameter name if present) + // Pattern: "void *userdata" -> "void *" + // Pattern: "Sint64 offset" -> "Sint64" + var param_type: []const u8 = trimmed_param; + + // Find the last space that separates type from name + if (std.mem.lastIndexOf(u8, trimmed_param, " ")) |space_pos| { + // Check if what comes after is an identifier (not a *) + const after_space = trimmed_param[space_pos + 1 ..]; + if (after_space.len > 0 and after_space[0] != '*') { + param_type = std.mem.trimRight(u8, trimmed_param[0..space_pos], " \t"); + } + } + + const zig_param = try convertType(param_type, allocator); + try params_list.append(zig_param); + } + + // Build Zig function pointer type + var result = std.ArrayList(u8).init(allocator); + defer result.deinit(); + + try result.appendSlice("?*const fn ("); + + for (params_list.items, 0..) |param, i| { + if (i > 0) try result.appendSlice(", "); + try result.appendSlice(param); + } + + try result.appendSlice(") callconv(.C) "); + try result.appendSlice(zig_return); + + return try result.toOwnedSlice(); +} + pub const CastType = enum { none, ptr_cast, diff --git a/lib/sdl3/test-iostream.json b/lib/sdl3/test-iostream.json new file mode 100644 index 0000000..dc163d8 --- /dev/null +++ b/lib/sdl3/test-iostream.json @@ -0,0 +1,734 @@ +{ + "header": "SDL_iostream.h", + "opaque_types": [ + { + "name": "SDL_IOStream" + } + ], + "typedefs": [], + "function_pointers": [], + "enums": [ + { + "name": "SDL_IOStatus", + "values": [] + }, + { + "name": "SDL_IOWhence", + "values": [] + } + ], + "structs": [ + { + "name": "SDL_IOStreamInterface", + "fields": [ + { + "name": "version", + "type": "Uint32" + }, + { + "name": "userdata", + "type": "Sint64 (SDLCALL *size)(void *" + }, + { + "name": "whence", + "type": "Sint64 (SDLCALL *seek)(void *userdata, Sint64 offset, SDL_IOWhence" + }, + { + "name": "status", + "type": "size_t (SDLCALL *read)(void *userdata, void *ptr, size_t size, SDL_IOStatus *" + }, + { + "name": "status", + "type": "size_t (SDLCALL *write)(void *userdata, const void *ptr, size_t size, SDL_IOStatus *" + }, + { + "name": "status", + "type": "bool (SDLCALL *flush)(void *userdata, SDL_IOStatus *" + }, + { + "name": "userdata", + "type": "bool (SDLCALL *close)(void *" + } + ] + } + ], + "unions": [], + "flags": [], + "functions": [ + { + "name": "SDL_IOFromFile", + "return_type": "SDL_IOStream *", + "parameters": [ + { + "name": "file", + "type": "const char *" + }, + { + "name": "mode", + "type": "const char *" + } + ] + }, + { + "name": "SDL_IOFromMem", + "return_type": "SDL_IOStream *", + "parameters": [ + { + "name": "mem", + "type": "void *" + }, + { + "name": "size", + "type": "size_t" + } + ] + }, + { + "name": "SDL_IOFromConstMem", + "return_type": "SDL_IOStream *", + "parameters": [ + { + "name": "mem", + "type": "const void *" + }, + { + "name": "size", + "type": "size_t" + } + ] + }, + { + "name": "SDL_IOFromDynamicMem", + "return_type": "SDL_IOStream *", + "parameters": [] + }, + { + "name": "SDL_OpenIO", + "return_type": "SDL_IOStream *", + "parameters": [ + { + "name": "iface", + "type": "const SDL_IOStreamInterface *" + }, + { + "name": "userdata", + "type": "void *" + } + ] + }, + { + "name": "SDL_CloseIO", + "return_type": "bool", + "parameters": [ + { + "name": "context", + "type": "SDL_IOStream *" + } + ] + }, + { + "name": "SDL_GetIOProperties", + "return_type": "SDL_PropertiesID", + "parameters": [ + { + "name": "context", + "type": "SDL_IOStream *" + } + ] + }, + { + "name": "SDL_GetIOStatus", + "return_type": "SDL_IOStatus", + "parameters": [ + { + "name": "context", + "type": "SDL_IOStream *" + } + ] + }, + { + "name": "SDL_GetIOSize", + "return_type": "Sint64", + "parameters": [ + { + "name": "context", + "type": "SDL_IOStream *" + } + ] + }, + { + "name": "SDL_SeekIO", + "return_type": "Sint64", + "parameters": [ + { + "name": "context", + "type": "SDL_IOStream *" + }, + { + "name": "offset", + "type": "Sint64" + }, + { + "name": "whence", + "type": "SDL_IOWhence" + } + ] + }, + { + "name": "SDL_TellIO", + "return_type": "Sint64", + "parameters": [ + { + "name": "context", + "type": "SDL_IOStream *" + } + ] + }, + { + "name": "SDL_ReadIO", + "return_type": "size_t", + "parameters": [ + { + "name": "context", + "type": "SDL_IOStream *" + }, + { + "name": "ptr", + "type": "void *" + }, + { + "name": "size", + "type": "size_t" + } + ] + }, + { + "name": "SDL_WriteIO", + "return_type": "size_t", + "parameters": [ + { + "name": "context", + "type": "SDL_IOStream *" + }, + { + "name": "ptr", + "type": "const void *" + }, + { + "name": "size", + "type": "size_t" + } + ] + }, + { + "name": "SDL_IOprintf", + "return_type": "size_t", + "parameters": [ + { + "name": "context", + "type": "SDL_IOStream *" + }, + { + "name": "fmt", + "type": "const char *" + }, + { + "name": "", + "type": "..." + } + ] + }, + { + "name": "SDL_IOvprintf", + "return_type": "size_t", + "parameters": [ + { + "name": "context", + "type": "SDL_IOStream *" + }, + { + "name": "fmt", + "type": "const char *" + }, + { + "name": "ap", + "type": "va_list" + } + ] + }, + { + "name": "SDL_FlushIO", + "return_type": "bool", + "parameters": [ + { + "name": "context", + "type": "SDL_IOStream *" + } + ] + }, + { + "name": "SDL_LoadFile_IO", + "return_type": "void *", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "datasize", + "type": "size_t *" + }, + { + "name": "closeio", + "type": "bool" + } + ] + }, + { + "name": "SDL_LoadFile", + "return_type": "void *", + "parameters": [ + { + "name": "file", + "type": "const char *" + }, + { + "name": "datasize", + "type": "size_t *" + } + ] + }, + { + "name": "SDL_SaveFile_IO", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "data", + "type": "const void *" + }, + { + "name": "datasize", + "type": "size_t" + }, + { + "name": "closeio", + "type": "bool" + } + ] + }, + { + "name": "SDL_SaveFile", + "return_type": "bool", + "parameters": [ + { + "name": "file", + "type": "const char *" + }, + { + "name": "data", + "type": "const void *" + }, + { + "name": "datasize", + "type": "size_t" + } + ] + }, + { + "name": "SDL_ReadU8", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint8 *" + } + ] + }, + { + "name": "SDL_ReadS8", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint8 *" + } + ] + }, + { + "name": "SDL_ReadU16LE", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint16 *" + } + ] + }, + { + "name": "SDL_ReadS16LE", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint16 *" + } + ] + }, + { + "name": "SDL_ReadU16BE", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint16 *" + } + ] + }, + { + "name": "SDL_ReadS16BE", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint16 *" + } + ] + }, + { + "name": "SDL_ReadU32LE", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint32 *" + } + ] + }, + { + "name": "SDL_ReadS32LE", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint32 *" + } + ] + }, + { + "name": "SDL_ReadU32BE", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint32 *" + } + ] + }, + { + "name": "SDL_ReadS32BE", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint32 *" + } + ] + }, + { + "name": "SDL_ReadU64LE", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint64 *" + } + ] + }, + { + "name": "SDL_ReadS64LE", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint64 *" + } + ] + }, + { + "name": "SDL_ReadU64BE", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint64 *" + } + ] + }, + { + "name": "SDL_ReadS64BE", + "return_type": "bool", + "parameters": [ + { + "name": "src", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint64 *" + } + ] + }, + { + "name": "SDL_WriteU8", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint8" + } + ] + }, + { + "name": "SDL_WriteS8", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint8" + } + ] + }, + { + "name": "SDL_WriteU16LE", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint16" + } + ] + }, + { + "name": "SDL_WriteS16LE", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint16" + } + ] + }, + { + "name": "SDL_WriteU16BE", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint16" + } + ] + }, + { + "name": "SDL_WriteS16BE", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint16" + } + ] + }, + { + "name": "SDL_WriteU32LE", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint32" + } + ] + }, + { + "name": "SDL_WriteS32LE", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint32" + } + ] + }, + { + "name": "SDL_WriteU32BE", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint32" + } + ] + }, + { + "name": "SDL_WriteS32BE", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint32" + } + ] + }, + { + "name": "SDL_WriteU64LE", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint64" + } + ] + }, + { + "name": "SDL_WriteS64LE", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint64" + } + ] + }, + { + "name": "SDL_WriteU64BE", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Uint64" + } + ] + }, + { + "name": "SDL_WriteS64BE", + "return_type": "bool", + "parameters": [ + { + "name": "dst", + "type": "SDL_IOStream *" + }, + { + "name": "value", + "type": "Sint64" + } + ] + } + ] +} \ No newline at end of file