sdlparser-scrap/src/types.zig

308 lines
14 KiB
Zig

const std = @import("std");
const Allocator = std.mem.Allocator;
const io = @import("io");
var fmtBuffer: [256]u8 = undefined;
/// Convert C type to Zig type
/// Simple table-based conversion for SDL3 types
pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 {
const trimmed = std.mem.trim(u8, c_type, " \t");
// Handle opaque struct pointers: "struct X *" -> "*anyopaque"
if (std.mem.startsWith(u8, trimmed, "struct ") and std.mem.endsWith(u8, trimmed, " *")) {
return try allocator.dupe(u8, "*anyopaque");
}
// Handle function pointers: For now, just return as placeholder until we implement full conversion
if (std.mem.indexOf(u8, trimmed, "(SDLCALL *") != null or std.mem.indexOf(u8, trimmed, "(*") != null) {
// TODO: Implement full function pointer conversion
// For now, return a placeholder type
return try std.fmt.allocPrint(allocator, "?*const anyopaque", .{});
}
// 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");
var array_part = trimmed[bracket_pos..]; // "[2]"
// Recursively convert the base type
const zig_base = try convertType(base_type, allocator);
defer allocator.free(zig_base);
const inner = array_part[1 .. array_part.len - 1];
if (inner.len > 0) {
var alias_to_c: bool = false;
_ = std.fmt.parseInt(u32, inner, 0) catch {
// not a real error
alias_to_c = true;
};
if (alias_to_c) {
var b = std.io.fixedBufferStream(&fmtBuffer);
_ = try b.write("[");
_ = try b.write("c.");
_ = try b.write(inner);
_ = try b.write("]");
array_part = b.getWritten();
std.debug.print("arrya_part = {s}\n", .{array_part});
}
}
// Return Zig array notation: [size]Type
return try std.fmt.allocPrint(allocator, "{s}{s}", .{ array_part, zig_base });
}
// Primitives
if (std.mem.eql(u8, trimmed, "void")) return try allocator.dupe(u8, "void");
if (std.mem.eql(u8, trimmed, "bool")) return try allocator.dupe(u8, "bool");
if (std.mem.eql(u8, trimmed, "SDL_bool")) return try allocator.dupe(u8, "bool");
if (std.mem.eql(u8, trimmed, "float")) return try allocator.dupe(u8, "f32");
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");
if (std.mem.eql(u8, trimmed, "Uint16")) return try allocator.dupe(u8, "u16");
if (std.mem.eql(u8, trimmed, "Uint32")) return try allocator.dupe(u8, "u32");
if (std.mem.eql(u8, trimmed, "Uint64")) return try allocator.dupe(u8, "u64");
if (std.mem.eql(u8, trimmed, "Sint8")) return try allocator.dupe(u8, "i8");
if (std.mem.eql(u8, trimmed, "Sint16")) return try allocator.dupe(u8, "i16");
if (std.mem.eql(u8, trimmed, "Sint32")) return try allocator.dupe(u8, "i32");
if (std.mem.eql(u8, trimmed, "Sint64")) return try allocator.dupe(u8, "i64");
if (std.mem.eql(u8, trimmed, "size_t")) return try allocator.dupe(u8, "usize");
if (std.mem.eql(u8, trimmed, "intptr_t")) return try allocator.dupe(u8, "isize");
// Common pointer types
if (std.mem.eql(u8, trimmed, "const char *")) return try allocator.dupe(u8, "[*c]const u8");
if (std.mem.eql(u8, trimmed, "const char **")) return try allocator.dupe(u8, "[*c][*c]const u8");
if (std.mem.eql(u8, trimmed, "const char * const *")) return try allocator.dupe(u8, "[*c]const [*c]const u8");
if (std.mem.eql(u8, trimmed, "char *")) return try allocator.dupe(u8, "[*c]u8");
if (std.mem.eql(u8, trimmed, "char **")) return try allocator.dupe(u8, "[*c][*c]u8");
if (std.mem.eql(u8, trimmed, "char**")) return try allocator.dupe(u8, "[*c][*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");
if (std.mem.eql(u8, trimmed, "Uint8 **")) return try allocator.dupe(u8, "[*c][*c]u8");
if (std.mem.eql(u8, trimmed, "const int *")) return try allocator.dupe(u8, "[*c]const c_int");
// Handle SDL types with pointers
// Check for double pointers like "SDL_Type **" or "SDL_Type *const *" or "SDL_Type * const *"
if (std.mem.startsWith(u8, trimmed, "SDL_")) {
// Match "SDL_Type *const *" (no space before const)
if (std.mem.indexOf(u8, trimmed, " *const *")) |pos| {
const base_type = trimmed[4..pos]; // Remove SDL_ prefix and get type
return std.fmt.allocPrint(allocator, "[*c]*const {s}", .{base_type});
}
// Match "SDL_Type * const *" (space before const)
if (std.mem.indexOf(u8, trimmed, " * const *")) |pos| {
const base_type = trimmed[4..pos]; // Remove SDL_ prefix and get type
return std.fmt.allocPrint(allocator, "[*c]*const {s}", .{base_type});
}
if (std.mem.indexOf(u8, trimmed, " **")) |pos| {
const base_type = trimmed[4..pos]; // Remove SDL_ prefix and get type
return std.fmt.allocPrint(allocator, "[*c][*c]{s}", .{base_type});
}
}
// Handle primitive pointer types
if (std.mem.eql(u8, trimmed, "int *")) return try allocator.dupe(u8, "*c_int");
if (std.mem.eql(u8, trimmed, "bool *")) return try allocator.dupe(u8, "*bool");
if (std.mem.eql(u8, trimmed, "size_t *")) return try allocator.dupe(u8, "*usize");
if (std.mem.eql(u8, trimmed, "float *")) return try allocator.dupe(u8, "*f32");
if (std.mem.eql(u8, trimmed, "const float *")) return try allocator.dupe(u8, "*const f32");
if (std.mem.eql(u8, trimmed, "double *")) return try allocator.dupe(u8, "*f64");
if (std.mem.eql(u8, trimmed, "Uint8 *")) return try allocator.dupe(u8, "*u8");
if (std.mem.eql(u8, trimmed, "Uint16 *")) return try allocator.dupe(u8, "*u16");
if (std.mem.eql(u8, trimmed, "Uint32 *")) return try allocator.dupe(u8, "*u32");
if (std.mem.eql(u8, trimmed, "Uint64 *")) return try allocator.dupe(u8, "*u64");
if (std.mem.eql(u8, trimmed, "Sint8 *")) return try allocator.dupe(u8, "*i8");
if (std.mem.eql(u8, trimmed, "Sint16 *")) return try allocator.dupe(u8, "*i16");
if (std.mem.eql(u8, trimmed, "Sint32 *")) return try allocator.dupe(u8, "*i32");
if (std.mem.eql(u8, trimmed, "const bool *")) return try allocator.dupe(u8, "*const bool");
if (std.mem.startsWith(u8, trimmed, "const ")) {
const rest = trimmed[6..];
if (std.mem.endsWith(u8, rest, " *") or std.mem.endsWith(u8, rest, "*")) {
const base_type = if (std.mem.endsWith(u8, rest, " *"))
rest[0 .. rest.len - 2]
else
rest[0 .. rest.len - 1];
if (std.mem.startsWith(u8, base_type, "SDL_")) {
// const SDL_Foo * -> *const Foo
const zig_type = base_type[4..]; // Remove SDL_
return std.fmt.allocPrint(allocator, "*const {s}", .{zig_type});
}
}
}
if (std.mem.endsWith(u8, trimmed, " *") or std.mem.endsWith(u8, trimmed, "*")) {
const base_type = if (std.mem.endsWith(u8, trimmed, " *"))
trimmed[0 .. trimmed.len - 2]
else
trimmed[0 .. trimmed.len - 1];
if (std.mem.startsWith(u8, base_type, "SDL_")) {
// SDL_Foo * or SDL_Foo* -> ?*Foo (nullable for opaque types from C)
const zig_type = base_type[4..]; // Remove SDL_
return std.fmt.allocPrint(allocator, "?*{s}", .{zig_type});
}
}
// Handle SDL types without pointers
if (std.mem.startsWith(u8, trimmed, "SDL_")) {
// SDL_Foo -> Foo
return try allocator.dupe(u8, trimmed[4..]);
}
// Generic pointer handling for any remaining pointer types
// Handle "const struct Foo *" -> "*const Foo"
if (std.mem.startsWith(u8, trimmed, "const struct ")) {
if (std.mem.endsWith(u8, trimmed, " *")) {
const struct_name = trimmed[13 .. trimmed.len - 2]; // Remove "const struct " and " *"
return std.fmt.allocPrint(allocator, "*const {s}", .{struct_name});
}
}
// Handle "Foo *" for any remaining types (fallback to C pointer)
if (std.mem.endsWith(u8, trimmed, " *")) {
const base_type = trimmed[0 .. trimmed.len - 2];
return std.fmt.allocPrint(allocator, "[*c]{s}", .{base_type});
}
if (std.mem.endsWith(u8, trimmed, "*")) {
const base_type = trimmed[0 .. trimmed.len - 1];
return std.fmt.allocPrint(allocator, "[*c]{s}", .{base_type});
}
// Fallback: return as-is
return try allocator.dupe(u8, trimmed);
}
/// Determine the appropriate cast for a given type when calling C functions
pub fn getCastType(zig_type: []const u8) CastType {
// Bool needs @bitCast
if (std.mem.eql(u8, zig_type, "bool")) {
return .bit_cast;
}
// Opaque pointers need @ptrCast (both ?*Type and *Type)
// Skip [*c] (C pointers) and *anyopaque
if (std.mem.startsWith(u8, zig_type, "?*") or std.mem.startsWith(u8, zig_type, "*")) {
// Exclude anyopaque and C pointers
if (std.mem.indexOf(u8, zig_type, "anyopaque") != null or
std.mem.startsWith(u8, zig_type, "[*c]") or
std.mem.startsWith(u8, zig_type, "?[*c]")) {
return .none;
}
return .ptr_cast;
}
// Enums need @intFromEnum
// We'll detect these by naming convention or explicit marking
// For now, assume types ending in certain patterns are enums
if (std.mem.indexOf(u8, zig_type, "Type") != null or
std.mem.indexOf(u8, zig_type, "Mode") != null or
std.mem.indexOf(u8, zig_type, "Op") != null)
{
return .int_from_enum;
}
// Flags (packed structs) need @bitCast
if (std.mem.endsWith(u8, zig_type, "Flags") or
std.mem.endsWith(u8, zig_type, "Format"))
{
return .bit_cast;
}
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 (but don't recursively convert function pointers)
const zig_return = if (std.mem.indexOf(u8, return_type_str, "(") != null)
try allocator.dupe(u8, return_type_str)
else
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");
}
}
// Don't recursively convert function pointers in params
const zig_param = if (std.mem.indexOf(u8, param_type, "(") != null)
try allocator.dupe(u8, param_type)
else
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,
bit_cast,
int_from_enum,
enum_from_int,
};