290 lines
9.9 KiB
Zig
290 lines
9.9 KiB
Zig
const std = @import("std");
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
/// Remove SDL_ prefix from a name
|
|
pub fn stripSDLPrefix(name: []const u8) []const u8 {
|
|
if (std.mem.startsWith(u8, name, "SDL_")) {
|
|
return name[4..];
|
|
}
|
|
return name;
|
|
}
|
|
|
|
/// Convert SDL type name to Zig type name
|
|
/// SDL_GPUDevice -> GPUDevice
|
|
pub fn typeNameToZig(c_name: []const u8) []const u8 {
|
|
return stripSDLPrefix(c_name);
|
|
}
|
|
|
|
/// Convert SDL function name to Zig function name
|
|
/// SDL_CreateGPUDevice -> createGPUDevice
|
|
pub fn functionNameToZig(c_name: []const u8, allocator: Allocator) ![]const u8 {
|
|
const without_prefix = stripSDLPrefix(c_name);
|
|
if (without_prefix.len == 0) return try allocator.dupe(u8, c_name);
|
|
|
|
var result = try allocator.dupe(u8, without_prefix);
|
|
|
|
// Lowercase leading acronyms (e.g., "GPUSupports" -> "gpuSupports")
|
|
// An acronym is multiple consecutive uppercase letters
|
|
var i: usize = 0;
|
|
while (i < result.len and std.ascii.isUpper(result[i])) : (i += 1) {
|
|
// If we have at least 2 uppercase letters and the next char is lowercase,
|
|
// we've found the end of the acronym (e.g., "GPUs" -> "gpu" + "Supports")
|
|
if (i > 0 and i + 1 < result.len and std.ascii.isLower(result[i + 1])) {
|
|
// Don't lowercase this last uppercase letter - it starts the next word
|
|
break;
|
|
}
|
|
result[i] = std.ascii.toLower(result[i]);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// Detect common prefix in a list of names
|
|
/// For SDL3, this should only strip the SDL_GPU_ or SDL_ prefix,
|
|
/// NOT the type name portion. This allows the type name to be preserved
|
|
/// in the enum values, preventing invalid identifiers that start with numbers.
|
|
pub fn detectCommonPrefix(names: []const []const u8, allocator: Allocator) ![]const u8 {
|
|
if (names.len == 0) return try allocator.dupe(u8, "");
|
|
|
|
const first = names[0];
|
|
|
|
// For SDL3, we want to find the "SDL_GPU_" or "SDL_" prefix
|
|
// but NOT include the type name part
|
|
if (std.mem.startsWith(u8, first, "SDL_GPU_")) {
|
|
return try allocator.dupe(u8, "SDL_GPU_");
|
|
} else if (std.mem.startsWith(u8, first, "SDL_")) {
|
|
return try allocator.dupe(u8, "SDL_");
|
|
}
|
|
|
|
return try allocator.dupe(u8, "");
|
|
}
|
|
|
|
/// Convert enum value name to Zig using the "first underscore after prefix" rule
|
|
/// SDL_GPU_PRIMITIVETYPE_TRIANGLELIST -> primitivetypeTrianglelist
|
|
/// SDL_GPU_TEXTURETYPE_2D_ARRAY -> texturetype2dArray
|
|
/// SDL_GPU_SAMPLECOUNT_1 -> samplecount1
|
|
pub fn enumValueToZig(c_name: []const u8, prefix: []const u8, allocator: Allocator) ![]const u8 {
|
|
// Remove SDL_GPU_ or SDL_ prefix
|
|
var name = c_name;
|
|
if (std.mem.startsWith(u8, name, prefix)) {
|
|
name = name[prefix.len..];
|
|
}
|
|
|
|
// Find FIRST underscore: splits type name from value
|
|
// e.g., "PRIMITIVETYPE_TRIANGLELIST" -> "PRIMITIVETYPE" + "TRIANGLELIST"
|
|
// e.g., "TEXTURETYPE_2D_ARRAY" -> "TEXTURETYPE" + "2D_ARRAY"
|
|
const first_underscore = std.mem.indexOfScalar(u8, name, '_');
|
|
|
|
if (first_underscore) |pos| {
|
|
const type_part = name[0..pos]; // "PRIMITIVETYPE" or "TEXTURETYPE"
|
|
const value_part = name[pos + 1 ..]; // "TRIANGLELIST" or "2D_ARRAY"
|
|
|
|
// Build result
|
|
var result = try std.ArrayList(u8).initCapacity(allocator, name.len);
|
|
errdefer result.deinit(allocator);
|
|
|
|
// Type part: all lowercase
|
|
for (type_part) |c| {
|
|
try result.append(allocator, std.ascii.toLower(c));
|
|
}
|
|
|
|
// Value part: convert to camelCase (first letter uppercase, handle underscores)
|
|
const value_camel = try screaminToTitleCamel(value_part, allocator);
|
|
defer allocator.free(value_camel);
|
|
try result.appendSlice(allocator, value_camel);
|
|
|
|
return try result.toOwnedSlice(allocator);
|
|
} else {
|
|
// No underscore found - just convert to lowercase
|
|
// This handles single-word enum values
|
|
return try screaminToLowerCamel(name, allocator);
|
|
}
|
|
}
|
|
|
|
/// Convert flag name to Zig
|
|
/// SDL_GPU_TEXTUREUSAGE_SAMPLER -> textureusageSampler
|
|
pub fn flagNameToZig(c_name: []const u8, prefix: []const u8, allocator: Allocator) ![]const u8 {
|
|
return enumValueToZig(c_name, prefix, allocator);
|
|
}
|
|
|
|
/// Convert SCREAMING_SNAKE_CASE to lowerCamelCase
|
|
fn screaminToLowerCamel(s: []const u8, allocator: Allocator) ![]const u8 {
|
|
if (s.len == 0) return try allocator.dupe(u8, "");
|
|
|
|
var result = try std.ArrayList(u8).initCapacity(allocator, s.len);
|
|
errdefer result.deinit(allocator);
|
|
|
|
var capitalize_next = false;
|
|
var is_first = true;
|
|
|
|
for (s) |c| {
|
|
if (c == '_') {
|
|
capitalize_next = true;
|
|
continue;
|
|
}
|
|
|
|
if (is_first) {
|
|
try result.append(allocator, std.ascii.toLower(c));
|
|
is_first = false;
|
|
} else if (capitalize_next) {
|
|
try result.append(allocator, std.ascii.toUpper(c));
|
|
capitalize_next = false;
|
|
} else {
|
|
try result.append(allocator, std.ascii.toLower(c));
|
|
}
|
|
}
|
|
|
|
return try result.toOwnedSlice(allocator);
|
|
}
|
|
|
|
/// Convert SCREAMING_SNAKE_CASE to TitleCamelCase (first letter uppercase)
|
|
fn screaminToTitleCamel(s: []const u8, allocator: Allocator) ![]const u8 {
|
|
if (s.len == 0) return try allocator.dupe(u8, "");
|
|
|
|
var result = try std.ArrayList(u8).initCapacity(allocator, s.len);
|
|
errdefer result.deinit(allocator);
|
|
|
|
var capitalize_next = true; // Start with capitalize for TitleCase
|
|
|
|
for (s) |c| {
|
|
if (c == '_') {
|
|
capitalize_next = true;
|
|
continue;
|
|
}
|
|
|
|
if (capitalize_next) {
|
|
try result.append(allocator, std.ascii.toUpper(c));
|
|
capitalize_next = false;
|
|
} else {
|
|
try result.append(allocator, std.ascii.toLower(c));
|
|
}
|
|
}
|
|
|
|
return try result.toOwnedSlice(allocator);
|
|
}
|
|
|
|
test "strip SDL prefix" {
|
|
try std.testing.expectEqualStrings("GPUDevice", stripSDLPrefix("SDL_GPUDevice"));
|
|
try std.testing.expectEqualStrings("Foo", stripSDLPrefix("SDL_Foo"));
|
|
try std.testing.expectEqualStrings("Bar", stripSDLPrefix("Bar"));
|
|
}
|
|
|
|
test "type name to Zig" {
|
|
try std.testing.expectEqualStrings("GPUDevice", typeNameToZig("SDL_GPUDevice"));
|
|
try std.testing.expectEqualStrings("GPUPrimitiveType", typeNameToZig("SDL_GPUPrimitiveType"));
|
|
}
|
|
|
|
test "function name to Zig" {
|
|
const name1 = try functionNameToZig("SDL_CreateGPUDevice", std.testing.allocator);
|
|
defer std.testing.allocator.free(name1);
|
|
try std.testing.expectEqualStrings("createGPUDevice", name1);
|
|
|
|
const name2 = try functionNameToZig("SDL_DestroyGPUDevice", std.testing.allocator);
|
|
defer std.testing.allocator.free(name2);
|
|
try std.testing.expectEqualStrings("destroyGPUDevice", name2);
|
|
}
|
|
|
|
test "detect common prefix - should only strip SDL prefix" {
|
|
const names = [_][]const u8{
|
|
"SDL_GPU_PRIMITIVETYPE_TRIANGLELIST",
|
|
"SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP",
|
|
"SDL_GPU_PRIMITIVETYPE_LINELIST",
|
|
};
|
|
|
|
const prefix = try detectCommonPrefix(&names, std.testing.allocator);
|
|
defer std.testing.allocator.free(prefix);
|
|
// Should only strip SDL_GPU_, not the type name
|
|
try std.testing.expectEqualStrings("SDL_GPU_", prefix);
|
|
}
|
|
|
|
test "detect common prefix - SDL without GPU" {
|
|
const names = [_][]const u8{
|
|
"SDL_LOADOP_LOAD",
|
|
"SDL_LOADOP_CLEAR",
|
|
};
|
|
|
|
const prefix = try detectCommonPrefix(&names, std.testing.allocator);
|
|
defer std.testing.allocator.free(prefix);
|
|
try std.testing.expectEqualStrings("SDL_", prefix);
|
|
}
|
|
|
|
test "enum value to Zig - basic case" {
|
|
const result = try enumValueToZig(
|
|
"SDL_GPU_PRIMITIVETYPE_TRIANGLELIST",
|
|
"SDL_GPU_",
|
|
std.testing.allocator,
|
|
);
|
|
defer std.testing.allocator.free(result);
|
|
try std.testing.expectEqualStrings("primitivetypeTrianglelist", result);
|
|
}
|
|
|
|
test "enum value to Zig - numeric value" {
|
|
const result = try enumValueToZig(
|
|
"SDL_GPU_SAMPLECOUNT_1",
|
|
"SDL_GPU_",
|
|
std.testing.allocator,
|
|
);
|
|
defer std.testing.allocator.free(result);
|
|
try std.testing.expectEqualStrings("samplecount1", result);
|
|
}
|
|
|
|
test "enum value to Zig - number in middle" {
|
|
const result = try enumValueToZig(
|
|
"SDL_GPU_TEXTURETYPE_2D_ARRAY",
|
|
"SDL_GPU_",
|
|
std.testing.allocator,
|
|
);
|
|
defer std.testing.allocator.free(result);
|
|
try std.testing.expectEqualStrings("texturetype2dArray", result);
|
|
}
|
|
|
|
test "enum value to Zig - simple number" {
|
|
const result = try enumValueToZig(
|
|
"SDL_GPU_TEXTURETYPE_2D",
|
|
"SDL_GPU_",
|
|
std.testing.allocator,
|
|
);
|
|
defer std.testing.allocator.free(result);
|
|
try std.testing.expectEqualStrings("texturetype2d", result);
|
|
}
|
|
|
|
test "enum value to Zig - 16bit case" {
|
|
const result = try enumValueToZig(
|
|
"SDL_GPU_INDEXELEMENTSIZE_16BIT",
|
|
"SDL_GPU_",
|
|
std.testing.allocator,
|
|
);
|
|
defer std.testing.allocator.free(result);
|
|
try std.testing.expectEqualStrings("indexelementsize16bit", result);
|
|
}
|
|
|
|
test "flag name to Zig - basic case" {
|
|
const result = try flagNameToZig(
|
|
"SDL_GPU_TEXTUREUSAGE_SAMPLER",
|
|
"SDL_GPU_",
|
|
std.testing.allocator,
|
|
);
|
|
defer std.testing.allocator.free(result);
|
|
try std.testing.expectEqualStrings("textureusageSampler", result);
|
|
}
|
|
|
|
test "flag name to Zig - complex name" {
|
|
const result = try flagNameToZig(
|
|
"SDL_GPU_TEXTUREUSAGE_COMPUTE_STORAGE_SIMULTANEOUS_READ_WRITE",
|
|
"SDL_GPU_",
|
|
std.testing.allocator,
|
|
);
|
|
defer std.testing.allocator.free(result);
|
|
try std.testing.expectEqualStrings("textureusageComputeStorageSimultaneousReadWrite", result);
|
|
}
|
|
|
|
test "screaming to lower camel" {
|
|
const result1 = try screaminToLowerCamel("TRIANGLE_LIST", std.testing.allocator);
|
|
defer std.testing.allocator.free(result1);
|
|
try std.testing.expectEqualStrings("triangleList", result1);
|
|
|
|
const result2 = try screaminToLowerCamel("SAMPLER", std.testing.allocator);
|
|
defer std.testing.allocator.free(result2);
|
|
try std.testing.expectEqualStrings("sampler", result2);
|
|
}
|