this enum detection code is getting wild. but it captures much more edge cases
This commit is contained in:
parent
a25a09e8fb
commit
094ac7b0b9
|
|
@ -168,9 +168,11 @@ pub inline fn getWindows(count: *c_int) [*c]?*Window {
|
||||||
After generating Zig code:
|
After generating Zig code:
|
||||||
1. Output written to `tmp/` directory
|
1. Output written to `tmp/` directory
|
||||||
2. `zig ast-check` runs on the temporary file
|
2. `zig ast-check` runs on the temporary file
|
||||||
3. If passes: `zig fmt` runs, then copied to final destination
|
3. If passes: `zig fmt` runs, then copied to final destination (`api/`)
|
||||||
4. If fails: debug output written to `debug/` with `_fmterror.zig` suffix
|
4. If fails: debug output written to `debug/` with `_fmterror.zig` suffix
|
||||||
|
|
||||||
|
**Note:** If a file exists in `api/`, it has already been validated. No need to run `zig ast-check` manually on final output files.
|
||||||
|
|
||||||
**Testing all outputs:**
|
**Testing all outputs:**
|
||||||
Use `zig build generate` to regenerate all SDL3 headers and verify no regressions.
|
Use `zig build generate` to regenerate all SDL3 headers and verify no regressions.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ pub const MouseButtonFlags = packed struct(u32) {
|
||||||
rsvd: bool = false,
|
rsvd: bool = false,
|
||||||
|
|
||||||
pub const None = MouseButtonFlags{};
|
pub const None = MouseButtonFlags{};
|
||||||
|
pub const ButtonRight: MouseButtonFlags = @bitCast(@as(u32, 3));
|
||||||
|
pub const ButtonX2: MouseButtonFlags = @bitCast(@as(u32, 5));
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Scancode = enum(c_int) {
|
pub const Scancode = enum(c_int) {
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,8 @@ pub const MouseButtonFlags = packed struct(u32) {
|
||||||
rsvd: bool = false,
|
rsvd: bool = false,
|
||||||
|
|
||||||
pub const None = MouseButtonFlags{};
|
pub const None = MouseButtonFlags{};
|
||||||
|
pub const ButtonRight: MouseButtonFlags = @bitCast(@as(u32, 3));
|
||||||
|
pub const ButtonX2: MouseButtonFlags = @bitCast(@as(u32, 5));
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const MouseMotionTransformCallback = c.SDL_MouseMotionTransformCallback;
|
pub const MouseMotionTransformCallback = c.SDL_MouseMotionTransformCallback;
|
||||||
|
|
|
||||||
|
|
@ -676,6 +676,8 @@ pub const MouseButtonFlags = packed struct(u32) {
|
||||||
rsvd: bool = false,
|
rsvd: bool = false,
|
||||||
|
|
||||||
pub const None = MouseButtonFlags{};
|
pub const None = MouseButtonFlags{};
|
||||||
|
pub const ButtonRight: MouseButtonFlags = @bitCast(@as(u32, 3));
|
||||||
|
pub const ButtonX2: MouseButtonFlags = @bitCast(@as(u32, 5));
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const PenInputFlags = packed struct(u32) {
|
pub const PenInputFlags = packed struct(u32) {
|
||||||
|
|
|
||||||
|
|
@ -2337,10 +2337,6 @@
|
||||||
"name": "SDL_GPUShaderFormat",
|
"name": "SDL_GPUShaderFormat",
|
||||||
"underlying_type": "Uint32",
|
"underlying_type": "Uint32",
|
||||||
"values": [
|
"values": [
|
||||||
{
|
|
||||||
"name": "SDL_GPU_SHADERFORMAT_INVALID",
|
|
||||||
"value": "0"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "SDL_GPU_SHADERFORMAT_PRIVATE",
|
"name": "SDL_GPU_SHADERFORMAT_PRIVATE",
|
||||||
"value": "(1u << 0)",
|
"value": "(1u << 0)",
|
||||||
|
|
|
||||||
|
|
@ -48,40 +48,40 @@
|
||||||
"values": [
|
"values": [
|
||||||
{
|
{
|
||||||
"name": "SDL_INIT_AUDIO",
|
"name": "SDL_INIT_AUDIO",
|
||||||
"value": "0x00000010u",
|
"value": "(1u << 4)",
|
||||||
"comment": "`SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS`"
|
"comment": "`SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_INIT_VIDEO",
|
"name": "SDL_INIT_VIDEO",
|
||||||
"value": "0x00000020u",
|
"value": "(1u << 5)",
|
||||||
"comment": "`SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread"
|
"comment": "`SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_INIT_JOYSTICK",
|
"name": "SDL_INIT_JOYSTICK",
|
||||||
"value": "0x00000200u",
|
"value": "(1u << 9)",
|
||||||
"comment": "`SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`"
|
"comment": "`SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_INIT_HAPTIC",
|
"name": "SDL_INIT_HAPTIC",
|
||||||
"value": "0x00001000u"
|
"value": "(1u << 12)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_INIT_GAMEPAD",
|
"name": "SDL_INIT_GAMEPAD",
|
||||||
"value": "0x00002000u",
|
"value": "(1u << 13)",
|
||||||
"comment": "`SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK`"
|
"comment": "`SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_INIT_EVENTS",
|
"name": "SDL_INIT_EVENTS",
|
||||||
"value": "0x00004000u"
|
"value": "(1u << 14)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_INIT_SENSOR",
|
"name": "SDL_INIT_SENSOR",
|
||||||
"value": "0x00008000u",
|
"value": "(1u << 15)",
|
||||||
"comment": "`SDL_INIT_SENSOR` implies `SDL_INIT_EVENTS`"
|
"comment": "`SDL_INIT_SENSOR` implies `SDL_INIT_EVENTS`"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_INIT_CAMERA",
|
"name": "SDL_INIT_CAMERA",
|
||||||
"value": "0x00010000u",
|
"value": "(1u << 16)",
|
||||||
"comment": "`SDL_INIT_CAMERA` implies `SDL_INIT_EVENTS`"
|
"comment": "`SDL_INIT_CAMERA` implies `SDL_INIT_EVENTS`"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -122,27 +122,27 @@
|
||||||
"values": [
|
"values": [
|
||||||
{
|
{
|
||||||
"name": "SDL_MESSAGEBOX_ERROR",
|
"name": "SDL_MESSAGEBOX_ERROR",
|
||||||
"value": "0x00000010u",
|
"value": "(1u << 4)",
|
||||||
"comment": "error dialog"
|
"comment": "error dialog"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_MESSAGEBOX_WARNING",
|
"name": "SDL_MESSAGEBOX_WARNING",
|
||||||
"value": "0x00000020u",
|
"value": "(1u << 5)",
|
||||||
"comment": "warning dialog"
|
"comment": "warning dialog"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_MESSAGEBOX_INFORMATION",
|
"name": "SDL_MESSAGEBOX_INFORMATION",
|
||||||
"value": "0x00000040u",
|
"value": "(1u << 6)",
|
||||||
"comment": "informational dialog"
|
"comment": "informational dialog"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_MESSAGEBOX_BUTTONS_LEFT_TO_RIGHT",
|
"name": "SDL_MESSAGEBOX_BUTTONS_LEFT_TO_RIGHT",
|
||||||
"value": "0x00000080u",
|
"value": "(1u << 7)",
|
||||||
"comment": "buttons placed left to right"
|
"comment": "buttons placed left to right"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT",
|
"name": "SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT",
|
||||||
"value": "0x00000100u",
|
"value": "(1u << 8)",
|
||||||
"comment": "buttons placed right to left"
|
"comment": "buttons placed right to left"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
@ -153,12 +153,12 @@
|
||||||
"values": [
|
"values": [
|
||||||
{
|
{
|
||||||
"name": "SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT",
|
"name": "SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT",
|
||||||
"value": "0x00000001u",
|
"value": "(1u << 0)",
|
||||||
"comment": "Marks the default button when return is hit"
|
"comment": "Marks the default button when return is hit"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT",
|
"name": "SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT",
|
||||||
"value": "0x00000002u",
|
"value": "(1u << 1)",
|
||||||
"comment": "Marks the default button when escape is hit"
|
"comment": "Marks the default button when escape is hit"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -145,23 +145,15 @@
|
||||||
"values": [
|
"values": [
|
||||||
{
|
{
|
||||||
"name": "SDL_BUTTON_LEFT",
|
"name": "SDL_BUTTON_LEFT",
|
||||||
"value": "1"
|
"value": "(1u << 0)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_BUTTON_MIDDLE",
|
"name": "SDL_BUTTON_MIDDLE",
|
||||||
"value": "2"
|
"value": "(1u << 1)"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "SDL_BUTTON_RIGHT",
|
|
||||||
"value": "3"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_BUTTON_X1",
|
"name": "SDL_BUTTON_X1",
|
||||||
"value": "4"
|
"value": "(1u << 2)"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "SDL_BUTTON_X2",
|
|
||||||
"value": "5"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,22 +57,22 @@
|
||||||
"values": [
|
"values": [
|
||||||
{
|
{
|
||||||
"name": "SDL_SURFACE_PREALLOCATED",
|
"name": "SDL_SURFACE_PREALLOCATED",
|
||||||
"value": "0x00000001u",
|
"value": "(1u << 0)",
|
||||||
"comment": "Surface uses preallocated pixel memory"
|
"comment": "Surface uses preallocated pixel memory"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_SURFACE_LOCK_NEEDED",
|
"name": "SDL_SURFACE_LOCK_NEEDED",
|
||||||
"value": "0x00000002u",
|
"value": "(1u << 1)",
|
||||||
"comment": "Surface needs to be locked to access pixels"
|
"comment": "Surface needs to be locked to access pixels"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_SURFACE_LOCKED",
|
"name": "SDL_SURFACE_LOCKED",
|
||||||
"value": "0x00000004u",
|
"value": "(1u << 2)",
|
||||||
"comment": "Surface is currently locked"
|
"comment": "Surface is currently locked"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_SURFACE_SIMD_ALIGNED",
|
"name": "SDL_SURFACE_SIMD_ALIGNED",
|
||||||
"value": "0x00000008u",
|
"value": "(1u << 3)",
|
||||||
"comment": "Surface uses pixel memory allocated with SDL_aligned_alloc()"
|
"comment": "Surface uses pixel memory allocated with SDL_aligned_alloc()"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -379,132 +379,132 @@
|
||||||
"values": [
|
"values": [
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_FULLSCREEN",
|
"name": "SDL_WINDOW_FULLSCREEN",
|
||||||
"value": "SDL_UINT64_C(0x0000000000000001)",
|
"value": "(1u << 0)",
|
||||||
"comment": "window is in fullscreen mode"
|
"comment": "window is in fullscreen mode"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_OPENGL",
|
"name": "SDL_WINDOW_OPENGL",
|
||||||
"value": "SDL_UINT64_C(0x0000000000000002)",
|
"value": "(1u << 1)",
|
||||||
"comment": "window usable with OpenGL context"
|
"comment": "window usable with OpenGL context"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_OCCLUDED",
|
"name": "SDL_WINDOW_OCCLUDED",
|
||||||
"value": "SDL_UINT64_C(0x0000000000000004)",
|
"value": "(1u << 2)",
|
||||||
"comment": "window is occluded"
|
"comment": "window is occluded"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_HIDDEN",
|
"name": "SDL_WINDOW_HIDDEN",
|
||||||
"value": "SDL_UINT64_C(0x0000000000000008)",
|
"value": "(1u << 3)",
|
||||||
"comment": "window is neither mapped onto the desktop nor shown in the taskbar/dock/window list; SDL_ShowWindow() is required for it to become visible"
|
"comment": "window is neither mapped onto the desktop nor shown in the taskbar/dock/window list; SDL_ShowWindow() is required for it to become visible"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_BORDERLESS",
|
"name": "SDL_WINDOW_BORDERLESS",
|
||||||
"value": "SDL_UINT64_C(0x0000000000000010)",
|
"value": "(1u << 4)",
|
||||||
"comment": "no window decoration"
|
"comment": "no window decoration"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_RESIZABLE",
|
"name": "SDL_WINDOW_RESIZABLE",
|
||||||
"value": "SDL_UINT64_C(0x0000000000000020)",
|
"value": "(1u << 5)",
|
||||||
"comment": "window can be resized"
|
"comment": "window can be resized"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_MINIMIZED",
|
"name": "SDL_WINDOW_MINIMIZED",
|
||||||
"value": "SDL_UINT64_C(0x0000000000000040)",
|
"value": "(1u << 6)",
|
||||||
"comment": "window is minimized"
|
"comment": "window is minimized"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_MAXIMIZED",
|
"name": "SDL_WINDOW_MAXIMIZED",
|
||||||
"value": "SDL_UINT64_C(0x0000000000000080)",
|
"value": "(1u << 7)",
|
||||||
"comment": "window is maximized"
|
"comment": "window is maximized"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_MOUSE_GRABBED",
|
"name": "SDL_WINDOW_MOUSE_GRABBED",
|
||||||
"value": "SDL_UINT64_C(0x0000000000000100)",
|
"value": "(1u << 8)",
|
||||||
"comment": "window has grabbed mouse input"
|
"comment": "window has grabbed mouse input"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_INPUT_FOCUS",
|
"name": "SDL_WINDOW_INPUT_FOCUS",
|
||||||
"value": "SDL_UINT64_C(0x0000000000000200)",
|
"value": "(1u << 9)",
|
||||||
"comment": "window has input focus"
|
"comment": "window has input focus"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_MOUSE_FOCUS",
|
"name": "SDL_WINDOW_MOUSE_FOCUS",
|
||||||
"value": "SDL_UINT64_C(0x0000000000000400)",
|
"value": "(1u << 10)",
|
||||||
"comment": "window has mouse focus"
|
"comment": "window has mouse focus"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_EXTERNAL",
|
"name": "SDL_WINDOW_EXTERNAL",
|
||||||
"value": "SDL_UINT64_C(0x0000000000000800)",
|
"value": "(1u << 11)",
|
||||||
"comment": "window not created by SDL"
|
"comment": "window not created by SDL"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_MODAL",
|
"name": "SDL_WINDOW_MODAL",
|
||||||
"value": "SDL_UINT64_C(0x0000000000001000)",
|
"value": "(1u << 12)",
|
||||||
"comment": "window is modal"
|
"comment": "window is modal"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_HIGH_PIXEL_DENSITY",
|
"name": "SDL_WINDOW_HIGH_PIXEL_DENSITY",
|
||||||
"value": "SDL_UINT64_C(0x0000000000002000)",
|
"value": "(1u << 13)",
|
||||||
"comment": "window uses high pixel density back buffer if possible"
|
"comment": "window uses high pixel density back buffer if possible"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_MOUSE_CAPTURE",
|
"name": "SDL_WINDOW_MOUSE_CAPTURE",
|
||||||
"value": "SDL_UINT64_C(0x0000000000004000)",
|
"value": "(1u << 14)",
|
||||||
"comment": "window has mouse captured (unrelated to MOUSE_GRABBED)"
|
"comment": "window has mouse captured (unrelated to MOUSE_GRABBED)"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_MOUSE_RELATIVE_MODE",
|
"name": "SDL_WINDOW_MOUSE_RELATIVE_MODE",
|
||||||
"value": "SDL_UINT64_C(0x0000000000008000)",
|
"value": "(1u << 15)",
|
||||||
"comment": "window has relative mode enabled"
|
"comment": "window has relative mode enabled"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_ALWAYS_ON_TOP",
|
"name": "SDL_WINDOW_ALWAYS_ON_TOP",
|
||||||
"value": "SDL_UINT64_C(0x0000000000010000)",
|
"value": "(1u << 16)",
|
||||||
"comment": "window should always be above others"
|
"comment": "window should always be above others"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_UTILITY",
|
"name": "SDL_WINDOW_UTILITY",
|
||||||
"value": "SDL_UINT64_C(0x0000000000020000)",
|
"value": "(1u << 17)",
|
||||||
"comment": "window should be treated as a utility window, not showing in the task bar and window list"
|
"comment": "window should be treated as a utility window, not showing in the task bar and window list"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_TOOLTIP",
|
"name": "SDL_WINDOW_TOOLTIP",
|
||||||
"value": "SDL_UINT64_C(0x0000000000040000)",
|
"value": "(1u << 18)",
|
||||||
"comment": "window should be treated as a tooltip and does not get mouse or keyboard focus, requires a parent window"
|
"comment": "window should be treated as a tooltip and does not get mouse or keyboard focus, requires a parent window"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_POPUP_MENU",
|
"name": "SDL_WINDOW_POPUP_MENU",
|
||||||
"value": "SDL_UINT64_C(0x0000000000080000)",
|
"value": "(1u << 19)",
|
||||||
"comment": "window should be treated as a popup menu, requires a parent window"
|
"comment": "window should be treated as a popup menu, requires a parent window"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_KEYBOARD_GRABBED",
|
"name": "SDL_WINDOW_KEYBOARD_GRABBED",
|
||||||
"value": "SDL_UINT64_C(0x0000000000100000)",
|
"value": "(1u << 20)",
|
||||||
"comment": "window has grabbed keyboard input"
|
"comment": "window has grabbed keyboard input"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_FILL_DOCUMENT",
|
"name": "SDL_WINDOW_FILL_DOCUMENT",
|
||||||
"value": "SDL_UINT64_C(0x0000000000200000)",
|
"value": "(1u << 21)",
|
||||||
"comment": "window is in fill-document mode (Emscripten only), since SDL 3.4.0"
|
"comment": "window is in fill-document mode (Emscripten only), since SDL 3.4.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_VULKAN",
|
"name": "SDL_WINDOW_VULKAN",
|
||||||
"value": "SDL_UINT64_C(0x0000000010000000)",
|
"value": "(1u << 28)",
|
||||||
"comment": "window usable for Vulkan surface"
|
"comment": "window usable for Vulkan surface"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_METAL",
|
"name": "SDL_WINDOW_METAL",
|
||||||
"value": "SDL_UINT64_C(0x0000000020000000)",
|
"value": "(1u << 29)",
|
||||||
"comment": "window usable for Metal view"
|
"comment": "window usable for Metal view"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_TRANSPARENT",
|
"name": "SDL_WINDOW_TRANSPARENT",
|
||||||
"value": "SDL_UINT64_C(0x0000000040000000)",
|
"value": "(1u << 30)",
|
||||||
"comment": "window with transparent buffer"
|
"comment": "window with transparent buffer"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "SDL_WINDOW_NOT_FOCUSABLE",
|
"name": "SDL_WINDOW_NOT_FOCUSABLE",
|
||||||
"value": "SDL_UINT64_C(0x0000000080000000)",
|
"value": "(1u << 31)",
|
||||||
"comment": "window should not be focusable"
|
"comment": "window should not be focusable"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -287,6 +287,7 @@ pub const CodeGen = struct {
|
||||||
.name = try self.allocator.dupe(u8, enum_decl.name),
|
.name = try self.allocator.dupe(u8, enum_decl.name),
|
||||||
.underlying_type = try self.allocator.dupe(u8, "Uint32"),
|
.underlying_type = try self.allocator.dupe(u8, "Uint32"),
|
||||||
.flags = try flags_list.toOwnedSlice(self.allocator),
|
.flags = try flags_list.toOwnedSlice(self.allocator),
|
||||||
|
.constants = &[_]patterns.ConstValue{}, // Empty for enum-to-flag conversion
|
||||||
.doc_comment = if (enum_decl.doc_comment) |doc| try self.allocator.dupe(u8, doc) else null,
|
.doc_comment = if (enum_decl.doc_comment) |doc| try self.allocator.dupe(u8, doc) else null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -576,6 +577,40 @@ pub const CodeGen = struct {
|
||||||
// Add None constant for zero value (C header parity)
|
// Add None constant for zero value (C header parity)
|
||||||
try self.output.writer(self.allocator).print(" pub const None = {s}{{}};\n", .{zig_name});
|
try self.output.writer(self.allocator).print(" pub const None = {s}{{}};\n", .{zig_name});
|
||||||
|
|
||||||
|
// Add constant values for non-power-of-2 defines
|
||||||
|
if (flag_decl.constants.len > 0) {
|
||||||
|
for (flag_decl.constants) |constant| {
|
||||||
|
const zig_const_camel = try naming.flagNameToZig(constant.name, prefix, self.allocator);
|
||||||
|
defer self.allocator.free(zig_const_camel);
|
||||||
|
|
||||||
|
// Capitalize first letter for pub const (PascalCase)
|
||||||
|
const zig_const = try self.allocator.alloc(u8, zig_const_camel.len);
|
||||||
|
errdefer self.allocator.free(zig_const);
|
||||||
|
@memcpy(zig_const, zig_const_camel);
|
||||||
|
if (zig_const.len > 0) {
|
||||||
|
zig_const[0] = std.ascii.toUpper(zig_const[0]);
|
||||||
|
}
|
||||||
|
defer self.allocator.free(zig_const);
|
||||||
|
|
||||||
|
if (constant.comment) |comment| {
|
||||||
|
try self.output.writer(self.allocator).print(" pub const {s}: {s} = @bitCast(@as({s}, {s})); // {s}\n", .{
|
||||||
|
zig_const,
|
||||||
|
zig_name,
|
||||||
|
underlying_type,
|
||||||
|
constant.value,
|
||||||
|
comment,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
try self.output.writer(self.allocator).print(" pub const {s}: {s} = @bitCast(@as({s}, {s}));\n", .{
|
||||||
|
zig_const,
|
||||||
|
zig_name,
|
||||||
|
underlying_type,
|
||||||
|
constant.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
try self.output.appendSlice(self.allocator, "};\n\n");
|
try self.output.appendSlice(self.allocator, "};\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -287,6 +287,7 @@ fn cloneDeclaration(allocator: Allocator, decl: Declaration) !Declaration {
|
||||||
.name = try allocator.dupe(u8, f.name),
|
.name = try allocator.dupe(u8, f.name),
|
||||||
.underlying_type = try allocator.dupe(u8, f.underlying_type),
|
.underlying_type = try allocator.dupe(u8, f.underlying_type),
|
||||||
.flags = try cloneFlagValues(allocator, f.flags),
|
.flags = try cloneFlagValues(allocator, f.flags),
|
||||||
|
.constants = try cloneConstValues(allocator, f.constants),
|
||||||
.doc_comment = if (f.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
|
.doc_comment = if (f.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -339,6 +340,18 @@ fn cloneFlagValues(allocator: Allocator, flags: []const patterns.FlagValue) ![]p
|
||||||
return new_flags;
|
return new_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn cloneConstValues(allocator: Allocator, constants: []const patterns.ConstValue) ![]patterns.ConstValue {
|
||||||
|
const new_constants = try allocator.alloc(patterns.ConstValue, constants.len);
|
||||||
|
for (constants, 0..) |constant, i| {
|
||||||
|
new_constants[i] = .{
|
||||||
|
.name = try allocator.dupe(u8, constant.name),
|
||||||
|
.value = try allocator.dupe(u8, constant.value),
|
||||||
|
.comment = if (constant.comment) |c| try allocator.dupe(u8, c) else null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return new_constants;
|
||||||
|
}
|
||||||
|
|
||||||
fn cloneFields(allocator: Allocator, fields: []const patterns.FieldDecl) ![]patterns.FieldDecl {
|
fn cloneFields(allocator: Allocator, fields: []const patterns.FieldDecl) ![]patterns.FieldDecl {
|
||||||
const new_fields = try allocator.alloc(patterns.FieldDecl, fields.len);
|
const new_fields = try allocator.alloc(patterns.FieldDecl, fields.len);
|
||||||
for (fields, 0..) |field, i| {
|
for (fields, 0..) |field, i| {
|
||||||
|
|
|
||||||
430
src/patterns.zig
430
src/patterns.zig
|
|
@ -1,5 +1,6 @@
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const io = @import("io");
|
const io = @import("io");
|
||||||
|
const naming = @import("naming.zig");
|
||||||
const Allocator = std.mem.Allocator;
|
const Allocator = std.mem.Allocator;
|
||||||
|
|
||||||
fn fixupZigName(name: []const u8) []u8 {
|
fn fixupZigName(name: []const u8) []u8 {
|
||||||
|
|
@ -102,6 +103,7 @@ pub const FlagDecl = struct {
|
||||||
name: []const u8, // SDL_GPUTextureUsageFlags
|
name: []const u8, // SDL_GPUTextureUsageFlags
|
||||||
underlying_type: []const u8, // Uint32
|
underlying_type: []const u8, // Uint32
|
||||||
flags: []FlagValue,
|
flags: []FlagValue,
|
||||||
|
constants: []ConstValue, // For non-power-of-2 values
|
||||||
doc_comment: ?[]const u8,
|
doc_comment: ?[]const u8,
|
||||||
|
|
||||||
pub fn deinit(self: FlagDecl, allocator: Allocator) void {
|
pub fn deinit(self: FlagDecl, allocator: Allocator) void {
|
||||||
|
|
@ -114,6 +116,12 @@ pub const FlagDecl = struct {
|
||||||
if (flag.comment) |c| allocator.free(c);
|
if (flag.comment) |c| allocator.free(c);
|
||||||
}
|
}
|
||||||
allocator.free(self.flags);
|
allocator.free(self.flags);
|
||||||
|
for (self.constants) |constant| {
|
||||||
|
allocator.free(constant.name);
|
||||||
|
allocator.free(constant.value);
|
||||||
|
if (constant.comment) |c| allocator.free(c);
|
||||||
|
}
|
||||||
|
allocator.free(self.constants);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -123,6 +131,12 @@ pub const FlagValue = struct {
|
||||||
comment: ?[]const u8,
|
comment: ?[]const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const ConstValue = struct {
|
||||||
|
name: []const u8, // SDL_BUTTON_RIGHT
|
||||||
|
value: []const u8, // 3
|
||||||
|
comment: ?[]const u8,
|
||||||
|
};
|
||||||
|
|
||||||
pub const TypedefDecl = struct {
|
pub const TypedefDecl = struct {
|
||||||
name: []const u8, // SDL_PropertiesID
|
name: []const u8, // SDL_PropertiesID
|
||||||
underlying_type: []const u8, // Uint32
|
underlying_type: []const u8, // Uint32
|
||||||
|
|
@ -1132,16 +1146,30 @@ pub const Scanner = struct {
|
||||||
};
|
};
|
||||||
|
|
||||||
const clean_name = std.mem.trimRight(u8, name, ";");
|
const clean_name = std.mem.trimRight(u8, name, ";");
|
||||||
if (!std.mem.endsWith(u8, clean_name, "Flags") and !std.mem.endsWith(u8, clean_name, "Format")) {
|
|
||||||
|
// Skip any whitespace/newlines before looking for #define
|
||||||
|
self.skipWhitespace();
|
||||||
|
|
||||||
|
// Look ahead to detect if this is a flag type by checking for #define patterns
|
||||||
|
const lookahead_pos = self.pos;
|
||||||
|
const is_bitshift_flag = try self.detectFlagPattern(clean_name);
|
||||||
|
self.pos = lookahead_pos; // Restore position after detection
|
||||||
|
|
||||||
|
// If bitshift detection failed, try suffix-based detection for types ending in "Flags" or "Format"
|
||||||
|
var is_suffix_flag = false;
|
||||||
|
if (!is_bitshift_flag and (std.mem.endsWith(u8, clean_name, "Flags") or std.mem.endsWith(u8, clean_name, "Format"))) {
|
||||||
|
is_suffix_flag = try self.detectSuffixBasedFlags(clean_name);
|
||||||
|
self.pos = lookahead_pos; // Restore position after detection
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_bitshift_flag and !is_suffix_flag) {
|
||||||
self.pos = start;
|
self.pos = start;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now collect following #define lines
|
// Now collect following #define lines
|
||||||
var flags = try std.ArrayList(FlagValue).initCapacity(self.allocator, 10);
|
var flags = try std.ArrayList(FlagValue).initCapacity(self.allocator, 10);
|
||||||
|
var constants = try std.ArrayList(ConstValue).initCapacity(self.allocator, 10);
|
||||||
// Skip any whitespace/newlines before looking for #define
|
|
||||||
self.skipWhitespace();
|
|
||||||
|
|
||||||
// Look ahead for #define lines
|
// Look ahead for #define lines
|
||||||
while (!self.isAtEnd()) {
|
while (!self.isAtEnd()) {
|
||||||
|
|
@ -1154,13 +1182,14 @@ pub const Scanner = struct {
|
||||||
const define_line = try self.readLine();
|
const define_line = try self.readLine();
|
||||||
defer self.allocator.free(define_line);
|
defer self.allocator.free(define_line);
|
||||||
|
|
||||||
if (try self.parseFlagDefine(define_line)) |flag| {
|
const result = try self.parseFlagOrConstDefine(define_line);
|
||||||
|
if (result.flag) |flag| {
|
||||||
try flags.append(self.allocator, flag);
|
try flags.append(self.allocator, flag);
|
||||||
} else {
|
} else if (result.constant) |constant| {
|
||||||
// Not a flag define, restore position
|
try constants.append(self.allocator, constant);
|
||||||
self.pos = define_start;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
// If neither flag nor constant, just skip this define and continue
|
||||||
|
// (don't break - it might be a 0 value or macro that we want to skip)
|
||||||
}
|
}
|
||||||
|
|
||||||
const doc = self.consumePendingDocComment();
|
const doc = self.consumePendingDocComment();
|
||||||
|
|
@ -1169,17 +1198,260 @@ pub const Scanner = struct {
|
||||||
.name = fixupZigName(clean_name),
|
.name = fixupZigName(clean_name),
|
||||||
.underlying_type = try self.allocator.dupe(u8, underlying),
|
.underlying_type = try self.allocator.dupe(u8, underlying),
|
||||||
.flags = try flags.toOwnedSlice(self.allocator),
|
.flags = try flags.toOwnedSlice(self.allocator),
|
||||||
|
.constants = try constants.toOwnedSlice(self.allocator),
|
||||||
.doc_comment = doc,
|
.doc_comment = doc,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseFlagDefine(self: *Scanner, line: []const u8) !?FlagValue {
|
fn detectFlagPattern(self: *Scanner, typedef_name: []const u8) !bool {
|
||||||
// Format after #define consumed: "SDL_GPU_TEXTUREUSAGE_SAMPLER (1u << 0) /**< comment */"
|
// Look ahead up to 15 lines for #define patterns that indicate this is a flag type
|
||||||
|
// Criteria:
|
||||||
|
// 1. Find #define statements with bit shift operators (<<)
|
||||||
|
// 2. Check if they have a common prefix
|
||||||
|
// 3. Check if the prefix relates to the typedef name
|
||||||
|
|
||||||
|
var bitshift_defines = std.ArrayList([]const u8){};
|
||||||
|
defer {
|
||||||
|
for (bitshift_defines.items) |item| {
|
||||||
|
self.allocator.free(item);
|
||||||
|
}
|
||||||
|
bitshift_defines.deinit(self.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines_checked: usize = 0;
|
||||||
|
const max_lines = 15;
|
||||||
|
|
||||||
|
while (lines_checked < max_lines and !self.isAtEnd()) {
|
||||||
|
// Skip whitespace/comments
|
||||||
|
self.skipWhitespace();
|
||||||
|
|
||||||
|
if (self.matchPrefix("#define ")) {
|
||||||
|
const define_line = try self.readLine();
|
||||||
|
|
||||||
|
// Extract the define name (first token)
|
||||||
|
var parts = std.mem.tokenizeScalar(u8, define_line, ' ');
|
||||||
|
if (parts.next()) |define_name| {
|
||||||
|
// Skip macro definitions like SDL_BUTTON_MASK(X)
|
||||||
|
if (std.mem.indexOf(u8, define_name, "(") != null) {
|
||||||
|
self.allocator.free(define_line);
|
||||||
|
lines_checked += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if it contains bit shift operator
|
||||||
|
if (std.mem.indexOf(u8, define_line, "<<") != null) {
|
||||||
|
try bitshift_defines.append(self.allocator, try self.allocator.dupe(u8, define_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.allocator.free(define_line);
|
||||||
|
} else {
|
||||||
|
// Not a #define, skip the line
|
||||||
|
const line = try self.readLine();
|
||||||
|
self.allocator.free(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
lines_checked += 1;
|
||||||
|
|
||||||
|
// Keep collecting defines up to max_lines
|
||||||
|
// (don't break early - we need to see all potential flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need at least 1 bit-shift define to consider it a bitshift flag type
|
||||||
|
if (bitshift_defines.items.len < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For single define, just check if it relates to the typedef name
|
||||||
|
if (bitshift_defines.items.len == 1) {
|
||||||
|
// Skip prefix detection, just verify the define name relates to typedef
|
||||||
|
return try self.matchesTypedefName(bitshift_defines.items[0], typedef_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if defines have a common prefix
|
||||||
|
const common_prefix = try naming.detectCommonPrefix(bitshift_defines.items, self.allocator);
|
||||||
|
defer self.allocator.free(common_prefix);
|
||||||
|
|
||||||
|
if (common_prefix.len == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the prefix relates to the typedef name
|
||||||
|
return self.matchesTypedefName(common_prefix, typedef_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn detectSuffixBasedFlags(self: *Scanner, typedef_name: []const u8) !bool {
|
||||||
|
// For types ending in "Flags", look for simple numeric defines
|
||||||
|
// Example: SDL_MouseButtonFlags with SDL_BUTTON_LEFT = 1, SDL_BUTTON_MIDDLE = 2
|
||||||
|
|
||||||
|
var numeric_defines = std.ArrayList([]const u8){};
|
||||||
|
defer {
|
||||||
|
for (numeric_defines.items) |item| {
|
||||||
|
self.allocator.free(item);
|
||||||
|
}
|
||||||
|
numeric_defines.deinit(self.allocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
var lines_checked: usize = 0;
|
||||||
|
const max_lines = 15;
|
||||||
|
|
||||||
|
while (lines_checked < max_lines and !self.isAtEnd()) {
|
||||||
|
self.skipWhitespace();
|
||||||
|
|
||||||
|
if (self.matchPrefix("#define ")) {
|
||||||
|
const define_line = try self.readLine();
|
||||||
|
|
||||||
|
var parts = std.mem.tokenizeScalar(u8, define_line, ' ');
|
||||||
|
if (parts.next()) |define_name| {
|
||||||
|
// Skip macro definitions like SDL_BUTTON_MASK(X)
|
||||||
|
if (std.mem.indexOf(u8, define_name, "(") != null) {
|
||||||
|
self.allocator.free(define_line);
|
||||||
|
lines_checked += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the value part
|
||||||
|
if (parts.next()) |value_part| {
|
||||||
|
// Check if it's a macro wrapper like SDL_UINT64_C(0x...)
|
||||||
|
const is_macro_wrapped_hex = blk: {
|
||||||
|
if (std.mem.startsWith(u8, value_part, "SDL_UINT64_C(") or
|
||||||
|
std.mem.startsWith(u8, value_part, "SDL_UINT32_C(")) {
|
||||||
|
// Extract hex value from SDL_UINT64_C(0x0000000000000001)
|
||||||
|
if (std.mem.indexOf(u8, value_part, "0x")) |hex_start| {
|
||||||
|
if (std.mem.indexOf(u8, value_part[hex_start..], ")")) |paren_pos| {
|
||||||
|
const hex_str = value_part[hex_start..hex_start + paren_pos];
|
||||||
|
_ = std.fmt.parseInt(u64, hex_str, 0) catch break :blk false;
|
||||||
|
break :blk true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break :blk false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if it's a plain hex literal like 0x00000010u
|
||||||
|
const is_plain_hex = blk: {
|
||||||
|
if (std.mem.indexOf(u8, value_part, "<<") != null) break :blk false;
|
||||||
|
if (std.mem.indexOf(u8, value_part, "|") != null) break :blk false;
|
||||||
|
if (std.mem.indexOf(u8, value_part, "SDL_") != null) break :blk false;
|
||||||
|
|
||||||
|
// Check if it starts with 0x
|
||||||
|
if (std.mem.startsWith(u8, value_part, "0x") or std.mem.startsWith(u8, value_part, "0X")) {
|
||||||
|
// Try to parse as hex (strip trailing 'u' if present)
|
||||||
|
var hex_val = value_part;
|
||||||
|
if (std.mem.endsWith(u8, value_part, "u") or std.mem.endsWith(u8, value_part, "U")) {
|
||||||
|
hex_val = value_part[0..value_part.len - 1];
|
||||||
|
}
|
||||||
|
_ = std.fmt.parseInt(u64, hex_val, 0) catch break :blk false;
|
||||||
|
break :blk true;
|
||||||
|
}
|
||||||
|
break :blk false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if it's a simple numeric value (1, 2, 3, etc.)
|
||||||
|
// Skip if it references other defines or has operators
|
||||||
|
const is_simple_numeric = blk: {
|
||||||
|
if (std.mem.indexOf(u8, value_part, "<<") != null) break :blk false;
|
||||||
|
if (std.mem.indexOf(u8, value_part, "|") != null) break :blk false;
|
||||||
|
if (std.mem.indexOf(u8, value_part, "(") != null) break :blk false;
|
||||||
|
if (std.mem.indexOf(u8, value_part, "SDL_") != null) break :blk false;
|
||||||
|
|
||||||
|
// Try to parse as integer
|
||||||
|
_ = std.fmt.parseInt(u32, value_part, 0) catch break :blk false;
|
||||||
|
break :blk true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (is_simple_numeric or is_macro_wrapped_hex or is_plain_hex) {
|
||||||
|
try numeric_defines.append(self.allocator, try self.allocator.dupe(u8, define_name));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.allocator.free(define_line);
|
||||||
|
} else {
|
||||||
|
const line = try self.readLine();
|
||||||
|
self.allocator.free(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
lines_checked += 1;
|
||||||
|
|
||||||
|
// Keep collecting defines up to max_lines
|
||||||
|
// (don't break early - we need to see all potential flags)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Need at least 1 numeric define
|
||||||
|
if (numeric_defines.items.len < 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For single define, just check if it relates to the typedef name
|
||||||
|
if (numeric_defines.items.len == 1) {
|
||||||
|
return try self.matchesTypedefName(numeric_defines.items[0], typedef_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if defines have a common prefix
|
||||||
|
const common_prefix = try naming.detectCommonPrefix(numeric_defines.items, self.allocator);
|
||||||
|
defer self.allocator.free(common_prefix);
|
||||||
|
|
||||||
|
if (common_prefix.len == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the prefix relates to the typedef name
|
||||||
|
return self.matchesTypedefName(common_prefix, typedef_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matchesTypedefName(self: *Scanner, common_prefix: []const u8, typedef_name: []const u8) !bool {
|
||||||
|
// Convert typedef name to uppercase and remove SDL_ prefix for comparison
|
||||||
|
const typedef_upper = try std.ascii.allocUpperString(self.allocator, typedef_name);
|
||||||
|
defer self.allocator.free(typedef_upper);
|
||||||
|
|
||||||
|
const typedef_without_sdl = if (std.mem.startsWith(u8, typedef_upper, "SDL_"))
|
||||||
|
typedef_upper[4..]
|
||||||
|
else
|
||||||
|
typedef_upper;
|
||||||
|
|
||||||
|
// Remove common suffixes like FLAGS, FORMAT from typedef for comparison
|
||||||
|
var typedef_core = typedef_without_sdl;
|
||||||
|
if (std.mem.endsWith(u8, typedef_core, "FLAGS")) {
|
||||||
|
typedef_core = typedef_core[0..typedef_core.len - 5];
|
||||||
|
} else if (std.mem.endsWith(u8, typedef_core, "FORMAT")) {
|
||||||
|
typedef_core = typedef_core[0..typedef_core.len - 6];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if prefix contains the typedef core (ignoring underscores)
|
||||||
|
// SDL_GPU_TEXTUREUSAGE should match GPUTEXTUREUSAGE
|
||||||
|
const prefix_no_underscores = try std.mem.replaceOwned(u8, self.allocator, common_prefix, "_", "");
|
||||||
|
defer self.allocator.free(prefix_no_underscores);
|
||||||
|
const typedef_no_underscores = try std.mem.replaceOwned(u8, self.allocator, typedef_core, "_", "");
|
||||||
|
defer self.allocator.free(typedef_no_underscores);
|
||||||
|
|
||||||
|
// Remove SDL from prefix if present
|
||||||
|
const prefix_without_sdl = if (std.mem.startsWith(u8, prefix_no_underscores, "SDL"))
|
||||||
|
prefix_no_underscores[3..]
|
||||||
|
else
|
||||||
|
prefix_no_underscores;
|
||||||
|
|
||||||
|
// Check if typedef starts with the prefix (GPU vs GPUTEXTUREUSAGE)
|
||||||
|
const typedef_starts_with_prefix = std.mem.startsWith(u8, typedef_no_underscores, prefix_without_sdl);
|
||||||
|
const prefix_starts_with_typedef = std.mem.startsWith(u8, prefix_without_sdl, typedef_no_underscores);
|
||||||
|
const significant_overlap = prefix_without_sdl.len >= 3 and typedef_no_underscores.len >= prefix_without_sdl.len and
|
||||||
|
std.mem.startsWith(u8, typedef_no_underscores, prefix_without_sdl);
|
||||||
|
|
||||||
|
return typedef_starts_with_prefix or prefix_starts_with_typedef or significant_overlap;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FlagOrConstResult = struct {
|
||||||
|
flag: ?FlagValue,
|
||||||
|
constant: ?ConstValue,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn parseFlagOrConstDefine(self: *Scanner, line: []const u8) !FlagOrConstResult {
|
||||||
|
// Format after #define consumed: "SDL_BUTTON_LEFT 1" or "SDL_GPU_TEXTUREUSAGE_SAMPLER (1u << 0)"
|
||||||
// Note: line doesn't include "#define" - it was already consumed by matchPrefix
|
// Note: line doesn't include "#define" - it was already consumed by matchPrefix
|
||||||
|
|
||||||
// Split by whitespace and get first token (the flag name)
|
// Split by whitespace and get first token (the define name)
|
||||||
var parts = std.mem.tokenizeScalar(u8, line, ' ');
|
var parts = std.mem.tokenizeScalar(u8, line, ' ');
|
||||||
const name = parts.next() orelse return null;
|
const name = parts.next() orelse return FlagOrConstResult{ .flag = null, .constant = null };
|
||||||
|
|
||||||
// Collect the value part (everything until comment)
|
// Collect the value part (everything until comment)
|
||||||
var value_parts = try std.ArrayList(u8).initCapacity(self.allocator, 32);
|
var value_parts = try std.ArrayList(u8).initCapacity(self.allocator, 32);
|
||||||
|
|
@ -1191,7 +1463,7 @@ pub const Scanner = struct {
|
||||||
try value_parts.appendSlice(self.allocator, part);
|
try value_parts.appendSlice(self.allocator, part);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value_parts.items.len == 0) return null;
|
if (value_parts.items.len == 0) return FlagOrConstResult{ .flag = null, .constant = null };
|
||||||
|
|
||||||
// Extract comment
|
// Extract comment
|
||||||
var comment: ?[]const u8 = null;
|
var comment: ?[]const u8 = null;
|
||||||
|
|
@ -1202,13 +1474,141 @@ pub const Scanner = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return FlagValue{
|
const value_str = value_parts.items;
|
||||||
|
|
||||||
|
// If it already has << or |, it's a flag define
|
||||||
|
if (std.mem.indexOf(u8, value_str, "<<") != null) {
|
||||||
|
return FlagOrConstResult{
|
||||||
|
.flag = FlagValue{
|
||||||
.name = try self.allocator.dupe(u8, name),
|
.name = try self.allocator.dupe(u8, name),
|
||||||
.value = try value_parts.toOwnedSlice(self.allocator),
|
.value = try value_parts.toOwnedSlice(self.allocator),
|
||||||
.comment = comment,
|
.comment = comment,
|
||||||
|
},
|
||||||
|
.constant = null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle SDL_UINT64_C(0x...) or SDL_UINT32_C(0x...) macros
|
||||||
|
if (std.mem.startsWith(u8, value_str, "SDL_UINT64_C(") or
|
||||||
|
std.mem.startsWith(u8, value_str, "SDL_UINT32_C(")) {
|
||||||
|
// Extract hex value
|
||||||
|
if (std.mem.indexOf(u8, value_str, "0x")) |hex_start| {
|
||||||
|
if (std.mem.indexOf(u8, value_str[hex_start..], ")")) |paren_pos| {
|
||||||
|
const hex_str = value_str[hex_start..hex_start + paren_pos];
|
||||||
|
if (std.fmt.parseInt(u64, hex_str, 0)) |numeric_val| {
|
||||||
|
if (numeric_val == 0) return FlagOrConstResult{ .flag = null, .constant = null };
|
||||||
|
|
||||||
|
// Power of 2: create a flag with bitshift
|
||||||
|
if (isPowerOfTwo(@intCast(numeric_val))) {
|
||||||
|
const bit_pos = @ctz(numeric_val);
|
||||||
|
const converted = try std.fmt.allocPrint(self.allocator, "(1u << {d})", .{bit_pos});
|
||||||
|
return FlagOrConstResult{
|
||||||
|
.flag = FlagValue{
|
||||||
|
.name = try self.allocator.dupe(u8, name),
|
||||||
|
.value = converted,
|
||||||
|
.comment = comment,
|
||||||
|
},
|
||||||
|
.constant = null,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Not a power of 2: create a constant
|
||||||
|
return FlagOrConstResult{
|
||||||
|
.flag = null,
|
||||||
|
.constant = ConstValue{
|
||||||
|
.name = try self.allocator.dupe(u8, name),
|
||||||
|
.value = try value_parts.toOwnedSlice(self.allocator),
|
||||||
|
.comment = comment,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else |_| {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Couldn't parse, skip
|
||||||
|
return FlagOrConstResult{ .flag = null, .constant = null };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle plain hex literals like 0x00000010u
|
||||||
|
if (std.mem.startsWith(u8, value_str, "0x") or std.mem.startsWith(u8, value_str, "0X")) {
|
||||||
|
// Strip trailing 'u' or 'U' if present
|
||||||
|
var hex_val = value_str;
|
||||||
|
if (std.mem.endsWith(u8, value_str, "u") or std.mem.endsWith(u8, value_str, "U")) {
|
||||||
|
hex_val = value_str[0..value_str.len - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std.fmt.parseInt(u64, hex_val, 0)) |numeric_val| {
|
||||||
|
if (numeric_val == 0) return FlagOrConstResult{ .flag = null, .constant = null };
|
||||||
|
|
||||||
|
// Power of 2: create a flag with bitshift
|
||||||
|
if (isPowerOfTwo(@intCast(numeric_val))) {
|
||||||
|
const bit_pos = @ctz(numeric_val);
|
||||||
|
const converted = try std.fmt.allocPrint(self.allocator, "(1u << {d})", .{bit_pos});
|
||||||
|
return FlagOrConstResult{
|
||||||
|
.flag = FlagValue{
|
||||||
|
.name = try self.allocator.dupe(u8, name),
|
||||||
|
.value = converted,
|
||||||
|
.comment = comment,
|
||||||
|
},
|
||||||
|
.constant = null,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Not a power of 2: create a constant
|
||||||
|
return FlagOrConstResult{
|
||||||
|
.flag = null,
|
||||||
|
.constant = ConstValue{
|
||||||
|
.name = try self.allocator.dupe(u8, name),
|
||||||
|
.value = try value_parts.toOwnedSlice(self.allocator),
|
||||||
|
.comment = comment,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else |_| {}
|
||||||
|
// Couldn't parse, skip
|
||||||
|
return FlagOrConstResult{ .flag = null, .constant = null };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip complex expressions
|
||||||
|
if (std.mem.indexOf(u8, value_str, "|") != null) return FlagOrConstResult{ .flag = null, .constant = null };
|
||||||
|
if (std.mem.indexOf(u8, value_str, "(") != null) return FlagOrConstResult{ .flag = null, .constant = null };
|
||||||
|
if (std.mem.indexOf(u8, value_str, "SDL_") != null) return FlagOrConstResult{ .flag = null, .constant = null };
|
||||||
|
|
||||||
|
// Try to parse as integer
|
||||||
|
if (std.fmt.parseInt(u32, value_str, 0)) |numeric_val| {
|
||||||
|
if (numeric_val == 0) return FlagOrConstResult{ .flag = null, .constant = null };
|
||||||
|
|
||||||
|
// Power of 2: create a flag with bitshift
|
||||||
|
if (isPowerOfTwo(numeric_val)) {
|
||||||
|
const bit_pos = @ctz(numeric_val);
|
||||||
|
const converted = try std.fmt.allocPrint(self.allocator, "(1u << {d})", .{bit_pos});
|
||||||
|
return FlagOrConstResult{
|
||||||
|
.flag = FlagValue{
|
||||||
|
.name = try self.allocator.dupe(u8, name),
|
||||||
|
.value = converted,
|
||||||
|
.comment = comment,
|
||||||
|
},
|
||||||
|
.constant = null,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Not a power of 2: create a constant
|
||||||
|
return FlagOrConstResult{
|
||||||
|
.flag = null,
|
||||||
|
.constant = ConstValue{
|
||||||
|
.name = try self.allocator.dupe(u8, name),
|
||||||
|
.value = try value_parts.toOwnedSlice(self.allocator),
|
||||||
|
.comment = comment,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else |_| {}
|
||||||
|
|
||||||
|
// Can't parse, skip
|
||||||
|
return FlagOrConstResult{ .flag = null, .constant = null };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn isPowerOfTwo(n: u32) bool {
|
||||||
|
return n != 0 and (n & (n - 1)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Pattern: extern SDL_DECLSPEC Type SDLCALL SDL_Name(...);
|
// Pattern: extern SDL_DECLSPEC Type SDLCALL SDL_Name(...);
|
||||||
fn scanFunction(self: *Scanner) !?FunctionDecl {
|
fn scanFunction(self: *Scanner) !?FunctionDecl {
|
||||||
if (!self.matchPrefix("extern SDL_DECLSPEC ")) {
|
if (!self.matchPrefix("extern SDL_DECLSPEC ")) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue