feat: add JSON output mode for SDL header parser
- Add --generate-json=<file> flag to output API metadata as JSON - JSONSerializer collects all declarations and serializes to JSON - Includes all types: opaque, typedefs, function pointers, enums, structs, unions, flags, functions - Tested with SDL_init.h, SDL_video.h, SDL_gpu.h, SDL_pixels.h, SDL_rect.h - JSON can be queried with jq for API analysis Note: Minor memory leaks exist in comment duplication, will address separately
This commit is contained in:
parent
002ceb891a
commit
4440566657
|
|
@ -1,161 +0,0 @@
|
||||||
# Mock Testing Implementation Complete
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
Successfully implemented a complete test harness for the SDL3 parser that:
|
|
||||||
1. Generates Zig bindings from C headers (SDL_gpu.h - 169 declarations)
|
|
||||||
2. Generates C mock implementations with proper SDL header includes
|
|
||||||
3. Compiles mocks into a static library (71KB with 94 functions)
|
|
||||||
4. Links Zig tests against the mock library
|
|
||||||
5. Verifies compilation and execution
|
|
||||||
|
|
||||||
## Build Commands
|
|
||||||
|
|
||||||
### Regenerate test mocks
|
|
||||||
```bash
|
|
||||||
zig build regenerate-test-mocks
|
|
||||||
```
|
|
||||||
Generates from SDL_gpu.h:
|
|
||||||
- `zig-out/gpu_test.zig` - Zig bindings (1,229 lines, 53KB)
|
|
||||||
- `zig-out/gpu_test_mock.c` - C mock implementations (577 lines, 18KB)
|
|
||||||
|
|
||||||
### Compile check (no tests)
|
|
||||||
```bash
|
|
||||||
zig build check-mocks
|
|
||||||
```
|
|
||||||
Verifies the generated code compiles without running tests.
|
|
||||||
|
|
||||||
### Full test suite
|
|
||||||
```bash
|
|
||||||
zig build test-mocks
|
|
||||||
```
|
|
||||||
Compiles and runs 7 tests:
|
|
||||||
- ✅ Can call createGPUDevice with various parameters
|
|
||||||
- ✅ Can call module-level query functions
|
|
||||||
- ✅ Device methods compile and link
|
|
||||||
- ✅ Enum values are distinct
|
|
||||||
- ✅ Packed struct shader format has correct size and fields
|
|
||||||
- ✅ Opaque types have correct pointer semantics
|
|
||||||
- ✅ Large header compilation stress test (169 declarations)
|
|
||||||
|
|
||||||
## Implementation Details
|
|
||||||
|
|
||||||
### Build Pipeline
|
|
||||||
1. **Parse**: `SDL/include/SDL3/SDL_gpu.h` → 169 declarations
|
|
||||||
2. **Generate**: Zig bindings + C mocks
|
|
||||||
3. **Compile**: C mocks → `libtest_mocks.a` (71KB, 94 functions)
|
|
||||||
4. **Link**: Zig tests + mock library
|
|
||||||
5. **Test**: Execute and verify
|
|
||||||
|
|
||||||
### File Structure
|
|
||||||
```
|
|
||||||
lib/sdl3/
|
|
||||||
├── SDL/include/SDL3/
|
|
||||||
│ └── SDL_gpu.h # Input C header (169 declarations)
|
|
||||||
├── parser/test/
|
|
||||||
│ └── mock_test.zig # Test harness (7 tests)
|
|
||||||
├── zig-out/
|
|
||||||
│ ├── gpu_test.zig # Generated bindings
|
|
||||||
│ └── gpu_test_mock.c # Generated mocks
|
|
||||||
└── build.zig # Build system integration
|
|
||||||
```
|
|
||||||
|
|
||||||
### Generated Mock Example
|
|
||||||
```c
|
|
||||||
// Auto-generated C mock implementations
|
|
||||||
// DO NOT EDIT - Generated by sdl-parser --mocks
|
|
||||||
|
|
||||||
#include <SDL3/SDL_stdinc.h>
|
|
||||||
#include <SDL3/SDL_gpu.h>
|
|
||||||
|
|
||||||
SDL_GPUDevice * SDL_CreateGPUDevice(SDL_GPUShaderFormat format_flags, bool debug_mode, const char * name) {
|
|
||||||
(void)format_flags;
|
|
||||||
(void)debug_mode;
|
|
||||||
(void)name;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Generated Binding Example
|
|
||||||
```zig
|
|
||||||
pub const GPUDevice = opaque {
|
|
||||||
pub inline fn createGPUTexture(
|
|
||||||
gpudevice: *GPUDevice,
|
|
||||||
createinfo: *const GPUTextureCreateInfo
|
|
||||||
) ?*GPUTexture {
|
|
||||||
return c.SDL_CreateGPUTexture(gpudevice, @ptrCast(createinfo));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test Results
|
|
||||||
```
|
|
||||||
Build Summary: 7/7 steps succeeded; 7/7 tests passed
|
|
||||||
test-mocks success
|
|
||||||
+- run test 7 passed 543us MaxRSS:3M
|
|
||||||
+- compile test Debug native cached 17ms MaxRSS:56M
|
|
||||||
+- compile lib test_mocks Debug native cached 19ms MaxRSS:55M
|
|
||||||
```
|
|
||||||
|
|
||||||
## Verified Capabilities
|
|
||||||
|
|
||||||
✅ Parser generates syntactically valid Zig code (1,229 lines)
|
|
||||||
✅ Parser generates compilable C mock code (577 lines)
|
|
||||||
✅ C mocks compile with SDL headers (includes SDL_stdinc.h, SDL_gpu.h)
|
|
||||||
✅ C mocks compile to static library with 94 exported functions
|
|
||||||
✅ Zig code links against C mock library
|
|
||||||
✅ Generated functions are callable from Zig
|
|
||||||
✅ Generated types (13 opaque, 24 enums, 35 structs, 3 flags) work correctly
|
|
||||||
✅ Type safety is preserved across C/Zig boundary
|
|
||||||
✅ Large header (169 declarations) processes successfully
|
|
||||||
|
|
||||||
## Statistics
|
|
||||||
|
|
||||||
**SDL_gpu.h parsing:**
|
|
||||||
- 169 total declarations
|
|
||||||
- 13 opaque types (GPUDevice, GPUBuffer, etc.)
|
|
||||||
- 24 enums (GPUPrimitiveType, GPULoadOp, etc.)
|
|
||||||
- 35 structs (GPUTextureCreateInfo, etc.)
|
|
||||||
- 3 flags (GPUShaderFormat, etc.)
|
|
||||||
- 94 functions (all mocked and linkable)
|
|
||||||
|
|
||||||
**Generated output:**
|
|
||||||
- Zig bindings: 1,229 lines, 53KB
|
|
||||||
- C mocks: 577 lines, 18KB
|
|
||||||
- Compiled library: 71KB, 94 symbols
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
With mock testing working on full SDL_gpu.h, we can now:
|
|
||||||
1. Implement dependency resolution for cross-header types (FColor, Rect, etc.)
|
|
||||||
2. Test with other SDL3 headers (SDL_video.h, SDL_audio.h, etc.)
|
|
||||||
3. Add integration with real SDL3 library
|
|
||||||
4. Validate generated bindings match handwritten bindings
|
|
||||||
|
|
||||||
## Time Investment
|
|
||||||
|
|
||||||
- Build system setup: 30 minutes
|
|
||||||
- API fixes (Zig 0.15): 15 minutes
|
|
||||||
- Test harness creation: 20 minutes
|
|
||||||
- SDL header integration: 15 minutes
|
|
||||||
- Full SDL_gpu.h testing: 10 minutes
|
|
||||||
- Documentation: 10 minutes
|
|
||||||
**Total**: ~100 minutes
|
|
||||||
|
|
||||||
## Key Learnings
|
|
||||||
|
|
||||||
1. Zig 0.15 uses `addLibrary(.linkage = .static)` instead of `addStaticLibrary`
|
|
||||||
2. Must create root_module with target/optimize for libraries
|
|
||||||
3. `extern fn` declarations need to be in public scope for linkage
|
|
||||||
4. C mocks should include actual SDL headers for proper type definitions
|
|
||||||
5. Mock library with 94 functions compiles to only 71KB
|
|
||||||
6. Large headers (169 declarations) parse and compile successfully
|
|
||||||
7. Type safety preserved: opaque types, enums, structs all work correctly
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Date: 2026-01-22
|
|
||||||
Status: Complete ✅
|
|
||||||
Tests: 7/7 passing
|
|
||||||
Header: SDL_gpu.h (169 declarations)
|
|
||||||
Generated: 1,806 lines of code
|
|
||||||
|
|
@ -1,135 +0,0 @@
|
||||||
# SDL_video.h Parsing Analysis
|
|
||||||
|
|
||||||
## Current Status: ✅ MOSTLY WORKING
|
|
||||||
|
|
||||||
The SDL_video.h header parses successfully with only minor missing type warnings. All major functionality is captured.
|
|
||||||
|
|
||||||
## Statistics
|
|
||||||
|
|
||||||
- **Total declarations found**: 124
|
|
||||||
- Opaque types: 2
|
|
||||||
- Typedefs: 6
|
|
||||||
- Function pointers: 0
|
|
||||||
- Enums: 4
|
|
||||||
- Structs: 2
|
|
||||||
- Flags: 1
|
|
||||||
- Functions: 109
|
|
||||||
|
|
||||||
## Successfully Resolved Dependencies
|
|
||||||
|
|
||||||
The parser successfully resolves and imports these types from dependency headers:
|
|
||||||
|
|
||||||
✅ **SDL_PixelFormat** (from SDL_pixels.h)
|
|
||||||
✅ **SDL_Point** (from SDL_rect.h)
|
|
||||||
✅ **SDL_Rect** (from SDL_rect.h)
|
|
||||||
✅ **SDL_Surface** (from SDL_surface.h)
|
|
||||||
✅ **SDL_PropertiesID** (from SDL_properties.h)
|
|
||||||
|
|
||||||
## Missing Type Definitions (7 types)
|
|
||||||
|
|
||||||
These types are referenced but not found in the included headers:
|
|
||||||
|
|
||||||
### 1. EGL-Related Types (5 types)
|
|
||||||
|
|
||||||
These are OpenGL ES/EGL integration types defined within SDL_video.h itself:
|
|
||||||
|
|
||||||
- **SDL_EGLConfig** - `typedef void *SDL_EGLConfig;`
|
|
||||||
- **SDL_EGLDisplay** - `typedef void *SDL_EGLDisplay;`
|
|
||||||
- **SDL_EGLSurface** - `typedef void *SDL_EGLSurface;`
|
|
||||||
- **SDL_EGLAttribArrayCallback** - Function pointer typedef
|
|
||||||
- **SDL_EGLIntArrayCallback** - Function pointer typedef
|
|
||||||
|
|
||||||
**Root Cause**: These are defined in SDL_video.h but the parser's typedef scanner is not picking them up properly.
|
|
||||||
|
|
||||||
**Issue**: The typedef scanner currently only processes simple typedefs and doesn't handle:
|
|
||||||
- Pointer typedefs (`typedef void *Type;`)
|
|
||||||
- Function pointer typedefs with complex signatures
|
|
||||||
|
|
||||||
### 2. OpenGL Types (2 types)
|
|
||||||
|
|
||||||
- **SDL_GLAttr** - Enum type for GL attributes
|
|
||||||
- **SDL_GLContext** - `typedef struct SDL_GLContextState *SDL_GLContext;`
|
|
||||||
|
|
||||||
**Root Cause**: Similar to EGL types - these are typedef'd in SDL_video.h but not captured by the scanner.
|
|
||||||
|
|
||||||
### 3. Callback Types (1 type)
|
|
||||||
|
|
||||||
- **SDL_HitTest** - `typedef SDL_HitTestResult (SDLCALL *SDL_HitTest)(...);`
|
|
||||||
|
|
||||||
**Root Cause**: Function pointer typedef with calling convention modifier.
|
|
||||||
|
|
||||||
### 4. Generic Types (1 type)
|
|
||||||
|
|
||||||
- **SDL_FunctionPointer** - `typedef void (SDLCALL *SDL_FunctionPointer)(void);`
|
|
||||||
|
|
||||||
**Root Cause**: Function pointer typedef.
|
|
||||||
|
|
||||||
## Implementation Plan
|
|
||||||
|
|
||||||
### Phase 1: Enhance Typedef Scanner ✅ PRIORITY
|
|
||||||
|
|
||||||
**Goal**: Make the typedef scanner capture all typedef forms in the same file being parsed.
|
|
||||||
|
|
||||||
**Tasks**:
|
|
||||||
|
|
||||||
1. **Add pointer typedef support**
|
|
||||||
```c
|
|
||||||
typedef void *SDL_EGLConfig;
|
|
||||||
typedef struct SDL_GLContextState *SDL_GLContext;
|
|
||||||
```
|
|
||||||
- Pattern: `typedef <type> *<name>;`
|
|
||||||
- Store as opaque pointer type
|
|
||||||
|
|
||||||
2. **Add function pointer typedef support**
|
|
||||||
```c
|
|
||||||
typedef SDL_HitTestResult (SDLCALL *SDL_HitTest)(SDL_Window *win, const SDL_Point *area, void *data);
|
|
||||||
typedef void (SDLCALL *SDL_FunctionPointer)(void);
|
|
||||||
```
|
|
||||||
- Pattern: `typedef <return> (SDLCALL *<name>)(<params>);`
|
|
||||||
- Store as function pointer type with signature
|
|
||||||
|
|
||||||
3. **Add enum typedef support**
|
|
||||||
```c
|
|
||||||
typedef enum SDL_GLAttr { ... } SDL_GLAttr;
|
|
||||||
```
|
|
||||||
- Pattern: Already handled, but verify it works for GL types
|
|
||||||
|
|
||||||
**Implementation Location**: `src/dependency_resolver.zig` - `scanFileForTypedefs()`
|
|
||||||
|
|
||||||
**Expected Result**: After this phase, all 7 missing types should be found and properly typed.
|
|
||||||
|
|
||||||
### Phase 2: Test and Validate
|
|
||||||
|
|
||||||
1. Run parser on SDL_video.h
|
|
||||||
2. Verify all 14 originally missing types are now resolved (7 from deps, 7 from typedefs)
|
|
||||||
3. Verify generated Zig code compiles
|
|
||||||
4. Check that function signatures using these types are correct
|
|
||||||
|
|
||||||
### Phase 3: Apply to Other Headers
|
|
||||||
|
|
||||||
Once SDL_video.h parses completely clean, apply the same pattern to other headers with similar issues.
|
|
||||||
|
|
||||||
## Error Categories
|
|
||||||
|
|
||||||
### Category A: Typedef Scanner Limitations ⭐ PRIMARY ISSUE
|
|
||||||
- **Impact**: 7/14 missing types (50%)
|
|
||||||
- **Difficulty**: Medium
|
|
||||||
- **Files affected**: SDL_video.h, potentially others
|
|
||||||
- **Solution**: Enhance typedef scanner (Phase 1)
|
|
||||||
|
|
||||||
### Category B: Cross-header Dependencies ✅ SOLVED
|
|
||||||
- **Impact**: 7/14 missing types (50%) - but these work!
|
|
||||||
- **Difficulty**: N/A (already working)
|
|
||||||
- **Solution**: Existing dependency resolver handles this correctly
|
|
||||||
|
|
||||||
## Success Metrics
|
|
||||||
|
|
||||||
After implementing Phase 1:
|
|
||||||
- ⬜ Zero "Could not find definition" warnings for SDL_video.h
|
|
||||||
- ⬜ Generated code compiles without errors
|
|
||||||
- ⬜ All 124 declarations properly typed
|
|
||||||
- ⬜ Can use as template for other complex headers
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
The current parsing system is quite robust. The main gap is in the typedef scanner not recognizing all forms of typedef. This is a focused, solvable problem that will unlock SDL_video.h and similar headers.
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,36 @@
|
||||||
|
{
|
||||||
|
"header": "SDL_init.h",
|
||||||
|
"opaque_types": [
|
||||||
|
],
|
||||||
|
"typedefs": [
|
||||||
|
],
|
||||||
|
"function_pointers": [
|
||||||
|
{"name": "SDL_AppInit_func", "return_type": "SDL_AppResult", "parameters": [{"name": "appstate", "type": "void **"}, {"name": "argc", "type": "int"}, {"name": "argv[]", "type": "char *"}]},
|
||||||
|
{"name": "SDL_AppIterate_func", "return_type": "SDL_AppResult", "parameters": [{"name": "appstate", "type": "void *"}]},
|
||||||
|
{"name": "SDL_AppEvent_func", "return_type": "SDL_AppResult", "parameters": [{"name": "appstate", "type": "void *"}, {"name": "event", "type": "SDL_Event *"}]},
|
||||||
|
{"name": "SDL_AppQuit_func", "return_type": "void", "parameters": [{"name": "appstate", "type": "void *"}, {"name": "result", "type": "SDL_AppResult"}]},
|
||||||
|
{"name": "SDL_MainThreadCallback", "return_type": "void", "parameters": [{"name": "userdata", "type": "void *"}]}
|
||||||
|
],
|
||||||
|
"enums": [
|
||||||
|
{"name": "SDL_AppResult", "values": []}
|
||||||
|
],
|
||||||
|
"structs": [
|
||||||
|
],
|
||||||
|
"unions": [
|
||||||
|
],
|
||||||
|
"flags": [
|
||||||
|
{"name": "SDL_InitFlags", "underlying_type": "Uint32", "values": [{"name": "SDL_INIT_AUDIO", "value": "0x00000010u", "comment": "`SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS`"}, {"name": "SDL_INIT_VIDEO", "value": "0x00000020u", "comment": "`SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread"}, {"name": "SDL_INIT_JOYSTICK", "value": "0x00000200u", "comment": "`SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`, should be initialized on the same thread as SDL_INIT_VIDEO on Windows if you don't set SDL_HINT_JOYSTICK_THREAD"}, {"name": "SDL_INIT_HAPTIC", "value": "0x00001000u"}, {"name": "SDL_INIT_GAMEPAD", "value": "0x00002000u", "comment": "`SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK`"}, {"name": "SDL_INIT_EVENTS", "value": "0x00004000u"}, {"name": "SDL_INIT_SENSOR", "value": "0x00008000u", "comment": "`SDL_INIT_SENSOR` implies `SDL_INIT_EVENTS`"}, {"name": "SDL_INIT_CAMERA", "value": "0x00010000u", "comment": "`SDL_INIT_CAMERA` implies `SDL_INIT_EVENTS`"}]}
|
||||||
|
],
|
||||||
|
"functions": [
|
||||||
|
{"name": "SDL_Init", "return_type": "bool", "parameters": [{"name": "flags", "type": "SDL_InitFlags"}]},
|
||||||
|
{"name": "SDL_InitSubSystem", "return_type": "bool", "parameters": [{"name": "flags", "type": "SDL_InitFlags"}]},
|
||||||
|
{"name": "SDL_QuitSubSystem", "return_type": "void", "parameters": [{"name": "flags", "type": "SDL_InitFlags"}]},
|
||||||
|
{"name": "SDL_WasInit", "return_type": "SDL_InitFlags", "parameters": [{"name": "flags", "type": "SDL_InitFlags"}]},
|
||||||
|
{"name": "SDL_Quit", "return_type": "void", "parameters": []},
|
||||||
|
{"name": "SDL_IsMainThread", "return_type": "bool", "parameters": []},
|
||||||
|
{"name": "SDL_RunOnMainThread", "return_type": "bool", "parameters": [{"name": "callback", "type": "SDL_MainThreadCallback"}, {"name": "userdata", "type": "void *"}, {"name": "wait_complete", "type": "bool"}]},
|
||||||
|
{"name": "SDL_SetAppMetadata", "return_type": "bool", "parameters": [{"name": "appname", "type": "const char *"}, {"name": "appversion", "type": "const char *"}, {"name": "appidentifier", "type": "const char *"}]},
|
||||||
|
{"name": "SDL_SetAppMetadataProperty", "return_type": "bool", "parameters": [{"name": "name", "type": "const char *"}, {"name": "value", "type": "const char *"}]},
|
||||||
|
{"name": "SDL_GetAppMetadataProperty", "return_type": "const char *", "parameters": [{"name": "name", "type": "const char *"}]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"header": "SDL_pixels.h",
|
||||||
|
"opaque_types": [
|
||||||
|
],
|
||||||
|
"typedefs": [
|
||||||
|
],
|
||||||
|
"function_pointers": [
|
||||||
|
],
|
||||||
|
"enums": [
|
||||||
|
{"name": "SDL_PixelType", "values": [{"name": "SDL_PIXELTYPE_UNKNOWN"}, {"name": "SDL_PIXELTYPE_INDEX1"}, {"name": "SDL_PIXELTYPE_INDEX4"}, {"name": "SDL_PIXELTYPE_INDEX8"}, {"name": "SDL_PIXELTYPE_PACKED8"}, {"name": "SDL_PIXELTYPE_PACKED16"}, {"name": "SDL_PIXELTYPE_PACKED32"}, {"name": "SDL_PIXELTYPE_ARRAYU8"}, {"name": "SDL_PIXELTYPE_ARRAYU16"}, {"name": "SDL_PIXELTYPE_ARRAYU32"}, {"name": "SDL_PIXELTYPE_ARRAYF16"}, {"name": "SDL_PIXELTYPE_ARRAYF32"}, {"name": "SDL_PIXELTYPE_INDEX2"}]},
|
||||||
|
{"name": "SDL_BitmapOrder", "values": [{"name": "SDL_BITMAPORDER_NONE"}, {"name": "SDL_BITMAPORDER_4321"}, {"name": "SDL_BITMAPORDER_1234"}]},
|
||||||
|
{"name": "SDL_PackedOrder", "values": [{"name": "SDL_PACKEDORDER_NONE"}, {"name": "SDL_PACKEDORDER_XRGB"}, {"name": "SDL_PACKEDORDER_RGBX"}, {"name": "SDL_PACKEDORDER_ARGB"}, {"name": "SDL_PACKEDORDER_RGBA"}, {"name": "SDL_PACKEDORDER_XBGR"}, {"name": "SDL_PACKEDORDER_BGRX"}, {"name": "SDL_PACKEDORDER_ABGR"}, {"name": "SDL_PACKEDORDER_BGRA"}]},
|
||||||
|
{"name": "SDL_ArrayOrder", "values": [{"name": "SDL_ARRAYORDER_NONE"}, {"name": "SDL_ARRAYORDER_RGB"}, {"name": "SDL_ARRAYORDER_RGBA"}, {"name": "SDL_ARRAYORDER_ARGB"}, {"name": "SDL_ARRAYORDER_BGR"}, {"name": "SDL_ARRAYORDER_BGRA"}, {"name": "SDL_ARRAYORDER_ABGR"}]},
|
||||||
|
{"name": "SDL_PackedLayout", "values": [{"name": "SDL_PACKEDLAYOUT_NONE"}, {"name": "SDL_PACKEDLAYOUT_332"}, {"name": "SDL_PACKEDLAYOUT_4444"}, {"name": "SDL_PACKEDLAYOUT_1555"}, {"name": "SDL_PACKEDLAYOUT_5551"}, {"name": "SDL_PACKEDLAYOUT_565"}, {"name": "SDL_PACKEDLAYOUT_8888"}, {"name": "SDL_PACKEDLAYOUT_2101010"}, {"name": "SDL_PACKEDLAYOUT_1010102"}]},
|
||||||
|
{"name": "SDL_PixelFormat", "values": [{"name": "SDL_PIXELFORMAT_UNKNOWN", "value": "0"}, {"name": "SDL_PIXELFORMAT_INDEX1LSB", "value": "0x11100100u"}, {"name": "SDL_PIXELFORMAT_INDEX1MSB", "value": "0x11200100u"}, {"name": "SDL_PIXELFORMAT_INDEX2LSB", "value": "0x1c100200u"}, {"name": "SDL_PIXELFORMAT_INDEX2MSB", "value": "0x1c200200u"}, {"name": "SDL_PIXELFORMAT_INDEX4LSB", "value": "0x12100400u"}, {"name": "SDL_PIXELFORMAT_INDEX4MSB", "value": "0x12200400u"}, {"name": "SDL_PIXELFORMAT_INDEX8", "value": "0x13000801u"}, {"name": "SDL_PIXELFORMAT_RGB332", "value": "0x14110801u"}, {"name": "SDL_PIXELFORMAT_XRGB4444", "value": "0x15120c02u"}, {"name": "SDL_PIXELFORMAT_XBGR4444", "value": "0x15520c02u"}, {"name": "SDL_PIXELFORMAT_XRGB1555", "value": "0x15130f02u"}, {"name": "SDL_PIXELFORMAT_XBGR1555", "value": "0x15530f02u"}, {"name": "SDL_PIXELFORMAT_ARGB4444", "value": "0x15321002u"}, {"name": "SDL_PIXELFORMAT_RGBA4444", "value": "0x15421002u"}, {"name": "SDL_PIXELFORMAT_ABGR4444", "value": "0x15721002u"}, {"name": "SDL_PIXELFORMAT_BGRA4444", "value": "0x15821002u"}, {"name": "SDL_PIXELFORMAT_ARGB1555", "value": "0x15331002u"}, {"name": "SDL_PIXELFORMAT_RGBA5551", "value": "0x15441002u"}, {"name": "SDL_PIXELFORMAT_ABGR1555", "value": "0x15731002u"}, {"name": "SDL_PIXELFORMAT_BGRA5551", "value": "0x15841002u"}, {"name": "SDL_PIXELFORMAT_RGB565", "value": "0x15151002u"}, {"name": "SDL_PIXELFORMAT_BGR565", "value": "0x15551002u"}, {"name": "SDL_PIXELFORMAT_RGB24", "value": "0x17101803u"}, {"name": "SDL_PIXELFORMAT_BGR24", "value": "0x17401803u"}, {"name": "SDL_PIXELFORMAT_XRGB8888", "value": "0x16161804u"}, {"name": "SDL_PIXELFORMAT_RGBX8888", "value": "0x16261804u"}, {"name": "SDL_PIXELFORMAT_XBGR8888", "value": "0x16561804u"}, {"name": "SDL_PIXELFORMAT_BGRX8888", "value": "0x16661804u"}, {"name": "SDL_PIXELFORMAT_ARGB8888", "value": "0x16362004u"}, {"name": "SDL_PIXELFORMAT_RGBA8888", "value": "0x16462004u"}, {"name": "SDL_PIXELFORMAT_ABGR8888", "value": "0x16762004u"}, {"name": "SDL_PIXELFORMAT_BGRA8888", "value": "0x16862004u"}, {"name": "SDL_PIXELFORMAT_XRGB2101010", "value": "0x16172004u"}, {"name": "SDL_PIXELFORMAT_XBGR2101010", "value": "0x16572004u"}, {"name": "SDL_PIXELFORMAT_ARGB2101010", "value": "0x16372004u"}, {"name": "SDL_PIXELFORMAT_ABGR2101010", "value": "0x16772004u"}, {"name": "SDL_PIXELFORMAT_RGB48", "value": "0x18103006u"}, {"name": "SDL_PIXELFORMAT_BGR48", "value": "0x18403006u"}, {"name": "SDL_PIXELFORMAT_RGBA64", "value": "0x18204008u"}, {"name": "SDL_PIXELFORMAT_ARGB64", "value": "0x18304008u"}, {"name": "SDL_PIXELFORMAT_BGRA64", "value": "0x18504008u"}, {"name": "SDL_PIXELFORMAT_ABGR64", "value": "0x18604008u"}, {"name": "SDL_PIXELFORMAT_RGB48_FLOAT", "value": "0x1a103006u"}, {"name": "SDL_PIXELFORMAT_BGR48_FLOAT", "value": "0x1a403006u"}, {"name": "SDL_PIXELFORMAT_RGBA64_FLOAT", "value": "0x1a204008u"}, {"name": "SDL_PIXELFORMAT_ARGB64_FLOAT", "value": "0x1a304008u"}, {"name": "SDL_PIXELFORMAT_BGRA64_FLOAT", "value": "0x1a504008u"}, {"name": "SDL_PIXELFORMAT_ABGR64_FLOAT", "value": "0x1a604008u"}, {"name": "SDL_PIXELFORMAT_RGB96_FLOAT", "value": "0x1b10600cu"}, {"name": "SDL_PIXELFORMAT_BGR96_FLOAT", "value": "0x1b40600cu"}, {"name": "SDL_PIXELFORMAT_RGBA128_FLOAT", "value": "0x1b208010u"}, {"name": "SDL_PIXELFORMAT_ARGB128_FLOAT", "value": "0x1b308010u"}, {"name": "SDL_PIXELFORMAT_BGRA128_FLOAT", "value": "0x1b508010u"}, {"name": "SDL_PIXELFORMAT_ABGR128_FLOAT", "value": "0x1b608010u"}, {"name": "SDL_PIXELFORMAT_RGBA32", "value": "SDL_PIXELFORMAT_RGBA8888"}, {"name": "SDL_PIXELFORMAT_ARGB32", "value": "SDL_PIXELFORMAT_ARGB8888"}, {"name": "SDL_PIXELFORMAT_BGRA32", "value": "SDL_PIXELFORMAT_BGRA8888"}, {"name": "SDL_PIXELFORMAT_ABGR32", "value": "SDL_PIXELFORMAT_ABGR8888"}, {"name": "SDL_PIXELFORMAT_RGBX32", "value": "SDL_PIXELFORMAT_RGBX8888"}, {"name": "SDL_PIXELFORMAT_XRGB32", "value": "SDL_PIXELFORMAT_XRGB8888"}, {"name": "SDL_PIXELFORMAT_BGRX32", "value": "SDL_PIXELFORMAT_BGRX8888"}, {"name": "SDL_PIXELFORMAT_XBGR32", "value": "SDL_PIXELFORMAT_XBGR8888"}]},
|
||||||
|
{"name": "SDL_ColorType", "values": [{"name": "SDL_COLOR_TYPE_UNKNOWN", "value": "0"}, {"name": "SDL_COLOR_TYPE_RGB", "value": "1"}, {"name": "SDL_COLOR_TYPE_YCBCR", "value": "2"}]},
|
||||||
|
{"name": "SDL_ColorRange", "values": [{"name": "SDL_COLOR_RANGE_UNKNOWN", "value": "0"}]},
|
||||||
|
{"name": "SDL_ColorPrimaries", "values": [{"name": "SDL_COLOR_PRIMARIES_UNKNOWN", "value": "0"}, {"name": "SDL_COLOR_PRIMARIES_UNSPECIFIED", "value": "2"}, {"name": "SDL_COLOR_PRIMARIES_CUSTOM", "value": "31"}]},
|
||||||
|
{"name": "SDL_TransferCharacteristics", "values": [{"name": "SDL_TRANSFER_CHARACTERISTICS_UNKNOWN", "value": "0"}, {"name": "SDL_TRANSFER_CHARACTERISTICS_UNSPECIFIED", "value": "2"}, {"name": "SDL_TRANSFER_CHARACTERISTICS_LINEAR", "value": "8"}, {"name": "SDL_TRANSFER_CHARACTERISTICS_LOG100", "value": "9"}, {"name": "SDL_TRANSFER_CHARACTERISTICS_LOG100_SQRT10", "value": "10"}, {"name": "SDL_TRANSFER_CHARACTERISTICS_CUSTOM", "value": "31"}]},
|
||||||
|
{"name": "SDL_MatrixCoefficients", "values": [{"name": "SDL_MATRIX_COEFFICIENTS_IDENTITY", "value": "0"}, {"name": "SDL_MATRIX_COEFFICIENTS_UNSPECIFIED", "value": "2"}, {"name": "SDL_MATRIX_COEFFICIENTS_YCGCO", "value": "8"}, {"name": "SDL_MATRIX_COEFFICIENTS_CHROMA_DERIVED_NCL", "value": "12"}, {"name": "SDL_MATRIX_COEFFICIENTS_CHROMA_DERIVED_CL", "value": "13"}, {"name": "SDL_MATRIX_COEFFICIENTS_CUSTOM", "value": "31"}]},
|
||||||
|
{"name": "SDL_ChromaLocation", "values": []},
|
||||||
|
{"name": "SDL_Colorspace", "values": [{"name": "SDL_COLORSPACE_UNKNOWN", "value": "0"}]}
|
||||||
|
],
|
||||||
|
"structs": [
|
||||||
|
{"name": "SDL_Color", "fields": [{"name": "r", "type": "Uint8"}, {"name": "g", "type": "Uint8"}, {"name": "b", "type": "Uint8"}, {"name": "a", "type": "Uint8"}]},
|
||||||
|
{"name": "SDL_FColor", "fields": [{"name": "r", "type": "float"}, {"name": "g", "type": "float"}, {"name": "b", "type": "float"}, {"name": "a", "type": "float"}]},
|
||||||
|
{"name": "SDL_Palette", "fields": [{"name": "ncolors", "type": "int", "comment": "number of elements in `colors`."}, {"name": "colors", "type": "SDL_Color *", "comment": "an array of colors, `ncolors` long."}, {"name": "version", "type": "Uint32", "comment": "internal use only, do not touch."}, {"name": "refcount", "type": "int", "comment": "internal use only, do not touch."}]},
|
||||||
|
{"name": "SDL_PixelFormatDetails", "fields": [{"name": "format", "type": "SDL_PixelFormat"}, {"name": "bits_per_pixel", "type": "Uint8"}, {"name": "bytes_per_pixel", "type": "Uint8"}, {"name": "padding", "type": "Uint8[2]"}, {"name": "Rmask", "type": "Uint32"}, {"name": "Gmask", "type": "Uint32"}, {"name": "Bmask", "type": "Uint32"}, {"name": "Amask", "type": "Uint32"}, {"name": "Rbits", "type": "Uint8"}, {"name": "Gbits", "type": "Uint8"}, {"name": "Bbits", "type": "Uint8"}, {"name": "Abits", "type": "Uint8"}, {"name": "Rshift", "type": "Uint8"}, {"name": "Gshift", "type": "Uint8"}, {"name": "Bshift", "type": "Uint8"}, {"name": "Ashift", "type": "Uint8"}]}
|
||||||
|
],
|
||||||
|
"unions": [
|
||||||
|
],
|
||||||
|
"flags": [
|
||||||
|
],
|
||||||
|
"functions": [
|
||||||
|
{"name": "SDL_GetPixelFormatName", "return_type": "const char *", "parameters": [{"name": "format", "type": "SDL_PixelFormat"}]},
|
||||||
|
{"name": "SDL_GetMasksForPixelFormat", "return_type": "bool", "parameters": [{"name": "format", "type": "SDL_PixelFormat"}, {"name": "bpp", "type": "int *"}, {"name": "Rmask", "type": "Uint32 *"}, {"name": "Gmask", "type": "Uint32 *"}, {"name": "Bmask", "type": "Uint32 *"}, {"name": "Amask", "type": "Uint32 *"}]},
|
||||||
|
{"name": "SDL_GetPixelFormatForMasks", "return_type": "SDL_PixelFormat", "parameters": [{"name": "bpp", "type": "int"}, {"name": "Rmask", "type": "Uint32"}, {"name": "Gmask", "type": "Uint32"}, {"name": "Bmask", "type": "Uint32"}, {"name": "Amask", "type": "Uint32"}]},
|
||||||
|
{"name": "SDL_GetPixelFormatDetails", "return_type": "const SDL_PixelFormatDetails *", "parameters": [{"name": "format", "type": "SDL_PixelFormat"}]},
|
||||||
|
{"name": "SDL_CreatePalette", "return_type": "SDL_Palette *", "parameters": [{"name": "ncolors", "type": "int"}]},
|
||||||
|
{"name": "SDL_SetPaletteColors", "return_type": "bool", "parameters": [{"name": "palette", "type": "SDL_Palette *"}, {"name": "colors", "type": "const SDL_Color *"}, {"name": "firstcolor", "type": "int"}, {"name": "ncolors", "type": "int"}]},
|
||||||
|
{"name": "SDL_DestroyPalette", "return_type": "void", "parameters": [{"name": "palette", "type": "SDL_Palette *"}]},
|
||||||
|
{"name": "SDL_MapRGB", "return_type": "Uint32", "parameters": [{"name": "format", "type": "const SDL_PixelFormatDetails *"}, {"name": "palette", "type": "const SDL_Palette *"}, {"name": "r", "type": "Uint8"}, {"name": "g", "type": "Uint8"}, {"name": "b", "type": "Uint8"}]},
|
||||||
|
{"name": "SDL_MapRGBA", "return_type": "Uint32", "parameters": [{"name": "format", "type": "const SDL_PixelFormatDetails *"}, {"name": "palette", "type": "const SDL_Palette *"}, {"name": "r", "type": "Uint8"}, {"name": "g", "type": "Uint8"}, {"name": "b", "type": "Uint8"}, {"name": "a", "type": "Uint8"}]},
|
||||||
|
{"name": "SDL_GetRGB", "return_type": "void", "parameters": [{"name": "pixel", "type": "Uint32"}, {"name": "format", "type": "const SDL_PixelFormatDetails *"}, {"name": "palette", "type": "const SDL_Palette *"}, {"name": "r", "type": "Uint8 *"}, {"name": "g", "type": "Uint8 *"}, {"name": "b", "type": "Uint8 *"}]},
|
||||||
|
{"name": "SDL_GetRGBA", "return_type": "void", "parameters": [{"name": "pixel", "type": "Uint32"}, {"name": "format", "type": "const SDL_PixelFormatDetails *"}, {"name": "palette", "type": "const SDL_Palette *"}, {"name": "r", "type": "Uint8 *"}, {"name": "g", "type": "Uint8 *"}, {"name": "b", "type": "Uint8 *"}, {"name": "a", "type": "Uint8 *"}]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"header": "SDL_rect.h",
|
||||||
|
"opaque_types": [
|
||||||
|
],
|
||||||
|
"typedefs": [
|
||||||
|
],
|
||||||
|
"function_pointers": [
|
||||||
|
],
|
||||||
|
"enums": [
|
||||||
|
],
|
||||||
|
"structs": [
|
||||||
|
{"name": "SDL_Point", "fields": [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}]},
|
||||||
|
{"name": "SDL_FPoint", "fields": [{"name": "x", "type": "float"}, {"name": "y", "type": "float"}]},
|
||||||
|
{"name": "SDL_Rect", "fields": [{"name": "x", "type": "int"}, {"name": "y", "type": "int"}, {"name": "w", "type": "int"}, {"name": "h", "type": "int"}]},
|
||||||
|
{"name": "SDL_FRect", "fields": [{"name": "x", "type": "float"}, {"name": "y", "type": "float"}, {"name": "w", "type": "float"}, {"name": "h", "type": "float"}]}
|
||||||
|
],
|
||||||
|
"unions": [
|
||||||
|
],
|
||||||
|
"flags": [
|
||||||
|
],
|
||||||
|
"functions": [
|
||||||
|
{"name": "SDL_HasRectIntersection", "return_type": "bool", "parameters": [{"name": "A", "type": "const SDL_Rect *"}, {"name": "B", "type": "const SDL_Rect *"}]},
|
||||||
|
{"name": "SDL_GetRectIntersection", "return_type": "bool", "parameters": [{"name": "A", "type": "const SDL_Rect *"}, {"name": "B", "type": "const SDL_Rect *"}, {"name": "result", "type": "SDL_Rect *"}]},
|
||||||
|
{"name": "SDL_GetRectUnion", "return_type": "bool", "parameters": [{"name": "A", "type": "const SDL_Rect *"}, {"name": "B", "type": "const SDL_Rect *"}, {"name": "result", "type": "SDL_Rect *"}]},
|
||||||
|
{"name": "SDL_GetRectEnclosingPoints", "return_type": "bool", "parameters": [{"name": "points", "type": "const SDL_Point *"}, {"name": "count", "type": "int"}, {"name": "clip", "type": "const SDL_Rect *"}, {"name": "result", "type": "SDL_Rect *"}]},
|
||||||
|
{"name": "SDL_GetRectAndLineIntersection", "return_type": "bool", "parameters": [{"name": "rect", "type": "const SDL_Rect *"}, {"name": "X1", "type": "int *"}, {"name": "Y1", "type": "int *"}, {"name": "X2", "type": "int *"}, {"name": "Y2", "type": "int *"}]},
|
||||||
|
{"name": "SDL_HasRectIntersectionFloat", "return_type": "bool", "parameters": [{"name": "A", "type": "const SDL_FRect *"}, {"name": "B", "type": "const SDL_FRect *"}]},
|
||||||
|
{"name": "SDL_GetRectIntersectionFloat", "return_type": "bool", "parameters": [{"name": "A", "type": "const SDL_FRect *"}, {"name": "B", "type": "const SDL_FRect *"}, {"name": "result", "type": "SDL_FRect *"}]},
|
||||||
|
{"name": "SDL_GetRectUnionFloat", "return_type": "bool", "parameters": [{"name": "A", "type": "const SDL_FRect *"}, {"name": "B", "type": "const SDL_FRect *"}, {"name": "result", "type": "SDL_FRect *"}]},
|
||||||
|
{"name": "SDL_GetRectEnclosingPointsFloat", "return_type": "bool", "parameters": [{"name": "points", "type": "const SDL_FPoint *"}, {"name": "count", "type": "int"}, {"name": "clip", "type": "const SDL_FRect *"}, {"name": "result", "type": "SDL_FRect *"}]},
|
||||||
|
{"name": "SDL_GetRectAndLineIntersectionFloat", "return_type": "bool", "parameters": [{"name": "rect", "type": "const SDL_FRect *"}, {"name": "X1", "type": "float *"}, {"name": "Y1", "type": "float *"}, {"name": "X2", "type": "float *"}, {"name": "Y2", "type": "float *"}]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,143 @@
|
||||||
|
{
|
||||||
|
"header": "SDL_video.h",
|
||||||
|
"opaque_types": [
|
||||||
|
{"name": "SDL_DisplayModeData"},
|
||||||
|
{"name": "SDL_Window"}
|
||||||
|
],
|
||||||
|
"typedefs": [
|
||||||
|
{"name": "SDL_DisplayID", "underlying_type": "Uint32"},
|
||||||
|
{"name": "SDL_WindowID", "underlying_type": "Uint32"},
|
||||||
|
{"name": "SDL_GLProfile", "underlying_type": "Uint32"},
|
||||||
|
{"name": "SDL_GLContextFlag", "underlying_type": "Uint32"},
|
||||||
|
{"name": "SDL_GLContextReleaseFlag", "underlying_type": "Uint32"},
|
||||||
|
{"name": "SDL_GLContextResetNotification", "underlying_type": "Uint32"}
|
||||||
|
],
|
||||||
|
"function_pointers": [
|
||||||
|
],
|
||||||
|
"enums": [
|
||||||
|
{"name": "SDL_SystemTheme", "values": []},
|
||||||
|
{"name": "SDL_DisplayOrientation", "values": []},
|
||||||
|
{"name": "SDL_FlashOperation", "values": []},
|
||||||
|
{"name": "SDL_HitTestResult", "values": []}
|
||||||
|
],
|
||||||
|
"structs": [
|
||||||
|
{"name": "SDL_DisplayMode", "fields": [{"name": "displayID", "type": "SDL_DisplayID", "comment": "the display this mode is associated with"}, {"name": "format", "type": "SDL_PixelFormat", "comment": "pixel format"}, {"name": "w", "type": "int", "comment": "width"}, {"name": "h", "type": "int", "comment": "height"}, {"name": "pixel_density", "type": "float", "comment": "scale converting size to pixels (e.g. a 1920x1080 mode with 2.0 scale would have 3840x2160 pixels)"}, {"name": "refresh_rate", "type": "float", "comment": "refresh rate (or 0.0f for unspecified)"}, {"name": "refresh_rate_numerator", "type": "int", "comment": "precise refresh rate numerator (or 0 for unspecified)"}, {"name": "refresh_rate_denominator", "type": "int", "comment": "precise refresh rate denominator"}, {"name": "internal", "type": "SDL_DisplayModeData *", "comment": "Private"}]},
|
||||||
|
{"name": "SDL_GLContextState", "fields": []}
|
||||||
|
],
|
||||||
|
"unions": [
|
||||||
|
],
|
||||||
|
"flags": [
|
||||||
|
{"name": "SDL_WindowFlags", "underlying_type": "Uint64", "values": [{"name": "SDL_WINDOW_FULLSCREEN", "value": "SDL_UINT64_C(0x0000000000000001)", "comment": "window is in fullscreen mode"}, {"name": "SDL_WINDOW_OPENGL", "value": "SDL_UINT64_C(0x0000000000000002)", "comment": "window usable with OpenGL context"}, {"name": "SDL_WINDOW_OCCLUDED", "value": "SDL_UINT64_C(0x0000000000000004)", "comment": "window is occluded"}, {"name": "SDL_WINDOW_HIDDEN", "value": "SDL_UINT64_C(0x0000000000000008)", "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", "value": "SDL_UINT64_C(0x0000000000000010)", "comment": "no window decoration"}, {"name": "SDL_WINDOW_RESIZABLE", "value": "SDL_UINT64_C(0x0000000000000020)", "comment": "window can be resized"}, {"name": "SDL_WINDOW_MINIMIZED", "value": "SDL_UINT64_C(0x0000000000000040)", "comment": "window is minimized"}, {"name": "SDL_WINDOW_MAXIMIZED", "value": "SDL_UINT64_C(0x0000000000000080)", "comment": "window is maximized"}, {"name": "SDL_WINDOW_MOUSE_GRABBED", "value": "SDL_UINT64_C(0x0000000000000100)", "comment": "window has grabbed mouse input"}, {"name": "SDL_WINDOW_INPUT_FOCUS", "value": "SDL_UINT64_C(0x0000000000000200)", "comment": "window has input focus"}, {"name": "SDL_WINDOW_MOUSE_FOCUS", "value": "SDL_UINT64_C(0x0000000000000400)", "comment": "window has mouse focus"}, {"name": "SDL_WINDOW_EXTERNAL", "value": "SDL_UINT64_C(0x0000000000000800)", "comment": "window not created by SDL"}, {"name": "SDL_WINDOW_MODAL", "value": "SDL_UINT64_C(0x0000000000001000)", "comment": "window is modal"}, {"name": "SDL_WINDOW_HIGH_PIXEL_DENSITY", "value": "SDL_UINT64_C(0x0000000000002000)", "comment": "window uses high pixel density back buffer if possible"}, {"name": "SDL_WINDOW_MOUSE_CAPTURE", "value": "SDL_UINT64_C(0x0000000000004000)", "comment": "window has mouse captured (unrelated to MOUSE_GRABBED)"}, {"name": "SDL_WINDOW_MOUSE_RELATIVE_MODE", "value": "SDL_UINT64_C(0x0000000000008000)", "comment": "window has relative mode enabled"}, {"name": "SDL_WINDOW_ALWAYS_ON_TOP", "value": "SDL_UINT64_C(0x0000000000010000)", "comment": "window should always be above others"}, {"name": "SDL_WINDOW_UTILITY", "value": "SDL_UINT64_C(0x0000000000020000)", "comment": "window should be treated as a utility window, not showing in the task bar and window list"}, {"name": "SDL_WINDOW_TOOLTIP", "value": "SDL_UINT64_C(0x0000000000040000)", "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", "value": "SDL_UINT64_C(0x0000000000080000)", "comment": "window should be treated as a popup menu, requires a parent window"}, {"name": "SDL_WINDOW_KEYBOARD_GRABBED", "value": "SDL_UINT64_C(0x0000000000100000)", "comment": "window has grabbed keyboard input"}, {"name": "SDL_WINDOW_VULKAN", "value": "SDL_UINT64_C(0x0000000010000000)", "comment": "window usable for Vulkan surface"}, {"name": "SDL_WINDOW_METAL", "value": "SDL_UINT64_C(0x0000000020000000)", "comment": "window usable for Metal view"}, {"name": "SDL_WINDOW_TRANSPARENT", "value": "SDL_UINT64_C(0x0000000040000000)", "comment": "window with transparent buffer"}, {"name": "SDL_WINDOW_NOT_FOCUSABLE", "value": "SDL_UINT64_C(0x0000000080000000)", "comment": "window should not be focusable"}]}
|
||||||
|
],
|
||||||
|
"functions": [
|
||||||
|
{"name": "SDL_GetNumVideoDrivers", "return_type": "int", "parameters": []},
|
||||||
|
{"name": "SDL_GetVideoDriver", "return_type": "const char *", "parameters": [{"name": "index", "type": "int"}]},
|
||||||
|
{"name": "SDL_GetCurrentVideoDriver", "return_type": "const char *", "parameters": []},
|
||||||
|
{"name": "SDL_GetSystemTheme", "return_type": "SDL_SystemTheme", "parameters": []},
|
||||||
|
{"name": "SDL_GetDisplays", "return_type": "SDL_DisplayID *", "parameters": [{"name": "count", "type": "int *"}]},
|
||||||
|
{"name": "SDL_GetPrimaryDisplay", "return_type": "SDL_DisplayID", "parameters": []},
|
||||||
|
{"name": "SDL_GetDisplayProperties", "return_type": "SDL_PropertiesID", "parameters": [{"name": "displayID", "type": "SDL_DisplayID"}]},
|
||||||
|
{"name": "SDL_GetDisplayName", "return_type": "const char *", "parameters": [{"name": "displayID", "type": "SDL_DisplayID"}]},
|
||||||
|
{"name": "SDL_GetDisplayBounds", "return_type": "bool", "parameters": [{"name": "displayID", "type": "SDL_DisplayID"}, {"name": "rect", "type": "SDL_Rect *"}]},
|
||||||
|
{"name": "SDL_GetDisplayUsableBounds", "return_type": "bool", "parameters": [{"name": "displayID", "type": "SDL_DisplayID"}, {"name": "rect", "type": "SDL_Rect *"}]},
|
||||||
|
{"name": "SDL_GetNaturalDisplayOrientation", "return_type": "SDL_DisplayOrientation", "parameters": [{"name": "displayID", "type": "SDL_DisplayID"}]},
|
||||||
|
{"name": "SDL_GetCurrentDisplayOrientation", "return_type": "SDL_DisplayOrientation", "parameters": [{"name": "displayID", "type": "SDL_DisplayID"}]},
|
||||||
|
{"name": "SDL_GetDisplayContentScale", "return_type": "float", "parameters": [{"name": "displayID", "type": "SDL_DisplayID"}]},
|
||||||
|
{"name": "SDL_GetFullscreenDisplayModes", "return_type": "SDL_DisplayMode **", "parameters": [{"name": "displayID", "type": "SDL_DisplayID"}, {"name": "count", "type": "int *"}]},
|
||||||
|
{"name": "SDL_GetClosestFullscreenDisplayMode", "return_type": "bool", "parameters": [{"name": "displayID", "type": "SDL_DisplayID"}, {"name": "w", "type": "int"}, {"name": "h", "type": "int"}, {"name": "refresh_rate", "type": "float"}, {"name": "include_high_density_modes", "type": "bool"}, {"name": "closest", "type": "SDL_DisplayMode *"}]},
|
||||||
|
{"name": "SDL_GetDesktopDisplayMode", "return_type": "const SDL_DisplayMode *", "parameters": [{"name": "displayID", "type": "SDL_DisplayID"}]},
|
||||||
|
{"name": "SDL_GetCurrentDisplayMode", "return_type": "const SDL_DisplayMode *", "parameters": [{"name": "displayID", "type": "SDL_DisplayID"}]},
|
||||||
|
{"name": "SDL_GetDisplayForPoint", "return_type": "SDL_DisplayID", "parameters": [{"name": "point", "type": "const SDL_Point *"}]},
|
||||||
|
{"name": "SDL_GetDisplayForRect", "return_type": "SDL_DisplayID", "parameters": [{"name": "rect", "type": "const SDL_Rect *"}]},
|
||||||
|
{"name": "SDL_GetDisplayForWindow", "return_type": "SDL_DisplayID", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_GetWindowPixelDensity", "return_type": "float", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_GetWindowDisplayScale", "return_type": "float", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_SetWindowFullscreenMode", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "mode", "type": "const SDL_DisplayMode *"}]},
|
||||||
|
{"name": "SDL_GetWindowFullscreenMode", "return_type": "const SDL_DisplayMode *", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_GetWindowICCProfile", "return_type": "void *", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "size", "type": "size_t *"}]},
|
||||||
|
{"name": "SDL_GetWindowPixelFormat", "return_type": "SDL_PixelFormat", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_GetWindows", "return_type": "SDL_Window **", "parameters": [{"name": "count", "type": "int *"}]},
|
||||||
|
{"name": "SDL_CreateWindow", "return_type": "SDL_Window *", "parameters": [{"name": "title", "type": "const char *"}, {"name": "w", "type": "int"}, {"name": "h", "type": "int"}, {"name": "flags", "type": "SDL_WindowFlags"}]},
|
||||||
|
{"name": "SDL_CreatePopupWindow", "return_type": "SDL_Window *", "parameters": [{"name": "parent", "type": "SDL_Window *"}, {"name": "offset_x", "type": "int"}, {"name": "offset_y", "type": "int"}, {"name": "w", "type": "int"}, {"name": "h", "type": "int"}, {"name": "flags", "type": "SDL_WindowFlags"}]},
|
||||||
|
{"name": "SDL_CreateWindowWithProperties", "return_type": "SDL_Window *", "parameters": [{"name": "props", "type": "SDL_PropertiesID"}]},
|
||||||
|
{"name": "SDL_GetWindowID", "return_type": "SDL_WindowID", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_GetWindowFromID", "return_type": "SDL_Window *", "parameters": [{"name": "id", "type": "SDL_WindowID"}]},
|
||||||
|
{"name": "SDL_GetWindowParent", "return_type": "SDL_Window *", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_GetWindowProperties", "return_type": "SDL_PropertiesID", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_GetWindowFlags", "return_type": "SDL_WindowFlags", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_SetWindowTitle", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "title", "type": "const char *"}]},
|
||||||
|
{"name": "SDL_GetWindowTitle", "return_type": "const char *", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_SetWindowIcon", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "icon", "type": "SDL_Surface *"}]},
|
||||||
|
{"name": "SDL_SetWindowPosition", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "x", "type": "int"}, {"name": "y", "type": "int"}]},
|
||||||
|
{"name": "SDL_GetWindowPosition", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "x", "type": "int *"}, {"name": "y", "type": "int *"}]},
|
||||||
|
{"name": "SDL_SetWindowSize", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "w", "type": "int"}, {"name": "h", "type": "int"}]},
|
||||||
|
{"name": "SDL_GetWindowSize", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "w", "type": "int *"}, {"name": "h", "type": "int *"}]},
|
||||||
|
{"name": "SDL_GetWindowSafeArea", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "rect", "type": "SDL_Rect *"}]},
|
||||||
|
{"name": "SDL_SetWindowAspectRatio", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "min_aspect", "type": "float"}, {"name": "max_aspect", "type": "float"}]},
|
||||||
|
{"name": "SDL_GetWindowAspectRatio", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "min_aspect", "type": "float *"}, {"name": "max_aspect", "type": "float *"}]},
|
||||||
|
{"name": "SDL_GetWindowBordersSize", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "top", "type": "int *"}, {"name": "left", "type": "int *"}, {"name": "bottom", "type": "int *"}, {"name": "right", "type": "int *"}]},
|
||||||
|
{"name": "SDL_GetWindowSizeInPixels", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "w", "type": "int *"}, {"name": "h", "type": "int *"}]},
|
||||||
|
{"name": "SDL_SetWindowMinimumSize", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "min_w", "type": "int"}, {"name": "min_h", "type": "int"}]},
|
||||||
|
{"name": "SDL_GetWindowMinimumSize", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "w", "type": "int *"}, {"name": "h", "type": "int *"}]},
|
||||||
|
{"name": "SDL_SetWindowMaximumSize", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "max_w", "type": "int"}, {"name": "max_h", "type": "int"}]},
|
||||||
|
{"name": "SDL_GetWindowMaximumSize", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "w", "type": "int *"}, {"name": "h", "type": "int *"}]},
|
||||||
|
{"name": "SDL_SetWindowBordered", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "bordered", "type": "bool"}]},
|
||||||
|
{"name": "SDL_SetWindowResizable", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "resizable", "type": "bool"}]},
|
||||||
|
{"name": "SDL_SetWindowAlwaysOnTop", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "on_top", "type": "bool"}]},
|
||||||
|
{"name": "SDL_ShowWindow", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_HideWindow", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_RaiseWindow", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_MaximizeWindow", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_MinimizeWindow", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_RestoreWindow", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_SetWindowFullscreen", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "fullscreen", "type": "bool"}]},
|
||||||
|
{"name": "SDL_SyncWindow", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_WindowHasSurface", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_GetWindowSurface", "return_type": "SDL_Surface *", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_SetWindowSurfaceVSync", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "vsync", "type": "int"}]},
|
||||||
|
{"name": "SDL_GetWindowSurfaceVSync", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "vsync", "type": "int *"}]},
|
||||||
|
{"name": "SDL_UpdateWindowSurface", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_UpdateWindowSurfaceRects", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "rects", "type": "const SDL_Rect *"}, {"name": "numrects", "type": "int"}]},
|
||||||
|
{"name": "SDL_DestroyWindowSurface", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_SetWindowKeyboardGrab", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "grabbed", "type": "bool"}]},
|
||||||
|
{"name": "SDL_SetWindowMouseGrab", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "grabbed", "type": "bool"}]},
|
||||||
|
{"name": "SDL_GetWindowKeyboardGrab", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_GetWindowMouseGrab", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_GetGrabbedWindow", "return_type": "SDL_Window *", "parameters": []},
|
||||||
|
{"name": "SDL_SetWindowMouseRect", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "rect", "type": "const SDL_Rect *"}]},
|
||||||
|
{"name": "SDL_GetWindowMouseRect", "return_type": "const SDL_Rect *", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_SetWindowOpacity", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "opacity", "type": "float"}]},
|
||||||
|
{"name": "SDL_GetWindowOpacity", "return_type": "float", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_SetWindowParent", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "parent", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_SetWindowModal", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "modal", "type": "bool"}]},
|
||||||
|
{"name": "SDL_SetWindowFocusable", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "focusable", "type": "bool"}]},
|
||||||
|
{"name": "SDL_ShowWindowSystemMenu", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "x", "type": "int"}, {"name": "y", "type": "int"}]},
|
||||||
|
{"name": "SDL_SetWindowHitTest", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "callback", "type": "SDL_HitTest"}, {"name": "callback_data", "type": "void *"}]},
|
||||||
|
{"name": "SDL_SetWindowShape", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "shape", "type": "SDL_Surface *"}]},
|
||||||
|
{"name": "SDL_FlashWindow", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "operation", "type": "SDL_FlashOperation"}]},
|
||||||
|
{"name": "SDL_DestroyWindow", "return_type": "void", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_ScreenSaverEnabled", "return_type": "bool", "parameters": []},
|
||||||
|
{"name": "SDL_EnableScreenSaver", "return_type": "bool", "parameters": []},
|
||||||
|
{"name": "SDL_DisableScreenSaver", "return_type": "bool", "parameters": []},
|
||||||
|
{"name": "SDL_GL_LoadLibrary", "return_type": "bool", "parameters": [{"name": "path", "type": "const char *"}]},
|
||||||
|
{"name": "SDL_GL_GetProcAddress", "return_type": "SDL_FunctionPointer", "parameters": [{"name": "proc", "type": "const char *"}]},
|
||||||
|
{"name": "SDL_EGL_GetProcAddress", "return_type": "SDL_FunctionPointer", "parameters": [{"name": "proc", "type": "const char *"}]},
|
||||||
|
{"name": "SDL_GL_UnloadLibrary", "return_type": "void", "parameters": []},
|
||||||
|
{"name": "SDL_GL_ExtensionSupported", "return_type": "bool", "parameters": [{"name": "extension", "type": "const char *"}]},
|
||||||
|
{"name": "SDL_GL_ResetAttributes", "return_type": "void", "parameters": []},
|
||||||
|
{"name": "SDL_GL_SetAttribute", "return_type": "bool", "parameters": [{"name": "attr", "type": "SDL_GLAttr"}, {"name": "value", "type": "int"}]},
|
||||||
|
{"name": "SDL_GL_GetAttribute", "return_type": "bool", "parameters": [{"name": "attr", "type": "SDL_GLAttr"}, {"name": "value", "type": "int *"}]},
|
||||||
|
{"name": "SDL_GL_CreateContext", "return_type": "SDL_GLContext", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_GL_MakeCurrent", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}, {"name": "context", "type": "SDL_GLContext"}]},
|
||||||
|
{"name": "SDL_GL_GetCurrentWindow", "return_type": "SDL_Window *", "parameters": []},
|
||||||
|
{"name": "SDL_GL_GetCurrentContext", "return_type": "SDL_GLContext", "parameters": []},
|
||||||
|
{"name": "SDL_EGL_GetCurrentDisplay", "return_type": "SDL_EGLDisplay", "parameters": []},
|
||||||
|
{"name": "SDL_EGL_GetCurrentConfig", "return_type": "SDL_EGLConfig", "parameters": []},
|
||||||
|
{"name": "SDL_EGL_GetWindowSurface", "return_type": "SDL_EGLSurface", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_EGL_SetAttributeCallbacks", "return_type": "void", "parameters": [{"name": "platformAttribCallback", "type": "SDL_EGLAttribArrayCallback"}, {"name": "surfaceAttribCallback", "type": "SDL_EGLIntArrayCallback"}, {"name": "contextAttribCallback", "type": "SDL_EGLIntArrayCallback"}, {"name": "userdata", "type": "void *"}]},
|
||||||
|
{"name": "SDL_GL_SetSwapInterval", "return_type": "bool", "parameters": [{"name": "interval", "type": "int"}]},
|
||||||
|
{"name": "SDL_GL_GetSwapInterval", "return_type": "bool", "parameters": [{"name": "interval", "type": "int *"}]},
|
||||||
|
{"name": "SDL_GL_SwapWindow", "return_type": "bool", "parameters": [{"name": "window", "type": "SDL_Window *"}]},
|
||||||
|
{"name": "SDL_GL_DestroyContext", "return_type": "bool", "parameters": [{"name": "context", "type": "SDL_GLContext"}]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -17,16 +17,16 @@ pub const JsonSerializer = struct {
|
||||||
pub fn init(allocator: std.mem.Allocator, header_name: []const u8) JsonSerializer {
|
pub fn init(allocator: std.mem.Allocator, header_name: []const u8) JsonSerializer {
|
||||||
return .{
|
return .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.output = std.ArrayList(u8){},
|
.output = .{},
|
||||||
.header_name = header_name,
|
.header_name = header_name,
|
||||||
.opaque_types = std.ArrayList(patterns.OpaqueType){},
|
.opaque_types = .{},
|
||||||
.typedefs = std.ArrayList(patterns.TypedefDecl){},
|
.typedefs = .{},
|
||||||
.function_pointers = std.ArrayList(patterns.FunctionPointerDecl){},
|
.function_pointers = .{},
|
||||||
.enums = std.ArrayList(patterns.EnumDecl){},
|
.enums = .{},
|
||||||
.structs = std.ArrayList(patterns.StructDecl){},
|
.structs = .{},
|
||||||
.unions = std.ArrayList(patterns.UnionDecl){},
|
.unions = .{},
|
||||||
.flags = std.ArrayList(patterns.FlagDecl){},
|
.flags = .{},
|
||||||
.functions = std.ArrayList(patterns.FunctionDecl){},
|
.functions = .{},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,314 +0,0 @@
|
||||||
# SDL3 Parser Implementation Summary
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Successfully implemented a fully functional C header parser for SDL3 in Zig that automatically generates idiomatic Zig bindings from SDL3's C headers. The parser uses a simplified text-matching approach rather than a full C parser, taking advantage of SDL3's highly regular header structure.
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
lib/sdl3/parser/
|
|
||||||
├── build.zig # Build configuration for parser executable
|
|
||||||
├── parser.zig # Main entry point (107 lines)
|
|
||||||
├── patterns.zig # Pattern scanner (700+ lines, 2 tests)
|
|
||||||
├── naming.zig # Name conversion utilities (130+ lines, 6 tests)
|
|
||||||
├── types.zig # Type conversion utilities (88 lines, 3 tests)
|
|
||||||
└── codegen.zig # Code generation (339 lines, 3 tests)
|
|
||||||
|
|
||||||
Total: ~1,364 lines of code, 14 tests (all passing)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Features Implemented
|
|
||||||
|
|
||||||
### 1. Pattern Detection
|
|
||||||
|
|
||||||
The parser successfully detects and extracts:
|
|
||||||
|
|
||||||
**Opaque Types**
|
|
||||||
```c
|
|
||||||
typedef struct SDL_GPUDevice SDL_GPUDevice;
|
|
||||||
```
|
|
||||||
→
|
|
||||||
```zig
|
|
||||||
pub const GPUDevice = opaque {};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Enums**
|
|
||||||
```c
|
|
||||||
typedef enum SDL_GPUPrimitiveType {
|
|
||||||
SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
|
|
||||||
SDL_GPU_PRIMITIVETYPE_LINELIST
|
|
||||||
} SDL_GPUPrimitiveType;
|
|
||||||
```
|
|
||||||
→
|
|
||||||
```zig
|
|
||||||
pub const GPUPrimitiveType = enum(c_int) {
|
|
||||||
trianglelist,
|
|
||||||
linelist,
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Structs**
|
|
||||||
```c
|
|
||||||
typedef struct SDL_GPUBlitInfo {
|
|
||||||
SDL_GPUBlitRegion source;
|
|
||||||
SDL_GPUBlitRegion destination;
|
|
||||||
bool cycle;
|
|
||||||
} SDL_GPUBlitInfo;
|
|
||||||
```
|
|
||||||
→
|
|
||||||
```zig
|
|
||||||
pub const GPUBlitInfo = extern struct {
|
|
||||||
source: GPUBlitRegion,
|
|
||||||
destination: GPUBlitRegion,
|
|
||||||
cycle: bool,
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Functions**
|
|
||||||
```c
|
|
||||||
extern SDL_DECLSPEC bool SDLCALL SDL_GPUSupportsShaderFormats(
|
|
||||||
SDL_GPUShaderFormat format_flags,
|
|
||||||
const char *name);
|
|
||||||
```
|
|
||||||
→
|
|
||||||
```zig
|
|
||||||
pub inline fn gpuSupportsShaderFormats(format_flags: GPUShaderFormat, name: [*c]const u8) bool {
|
|
||||||
return c.SDL_GPUSupportsShaderFormats(@bitCast(format_flags), name);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Name Conversion
|
|
||||||
|
|
||||||
Intelligent naming conventions to match idiomatic Zig style:
|
|
||||||
|
|
||||||
| C Name | Zig Name | Rule |
|
|
||||||
|--------|----------|------|
|
|
||||||
| `SDL_GPUDevice` | `GPUDevice` | Type: Remove SDL_ prefix |
|
|
||||||
| `SDL_CreateGPUDevice` | `createGPUDevice` | Function: Remove SDL_, lowercase first |
|
|
||||||
| `SDL_GPUSupportsShaderFormats` | `gpuSupportsShaderFormats` | Function: Lowercase leading acronym |
|
|
||||||
| `SDL_GPU_PRIMITIVETYPE_TRIANGLELIST` | `trianglelist` | Enum value: Remove common prefix, lowercase |
|
|
||||||
|
|
||||||
Key insight: Leading acronyms (GPU, API, etc.) are fully lowercased when at the start of function names.
|
|
||||||
|
|
||||||
### 3. Type Conversion
|
|
||||||
|
|
||||||
Automatic C to Zig type mapping:
|
|
||||||
|
|
||||||
| C Type | Zig Type |
|
|
||||||
|--------|----------|
|
|
||||||
| `float` | `f32` |
|
|
||||||
| `Uint32` | `u32` |
|
|
||||||
| `bool` | `bool` |
|
|
||||||
| `const char *` | `[*c]const u8` |
|
|
||||||
| `void *` | `?*anyopaque` |
|
|
||||||
| `SDL_GPUDevice *` | `*GPUDevice` |
|
|
||||||
|
|
||||||
### 4. Cast Detection
|
|
||||||
|
|
||||||
Smart cast insertion based on type patterns:
|
|
||||||
|
|
||||||
| Type Pattern | Cast Used | Example |
|
|
||||||
|--------------|-----------|---------|
|
|
||||||
| Pointer types | `@ptrCast` | `*GPUDevice` |
|
|
||||||
| Flags/packed structs | `@bitCast` | `GPUShaderFormat` |
|
|
||||||
| Enums | `@intFromEnum` | `GPUPrimitiveType` |
|
|
||||||
| Primitives | None | `bool`, `u32` |
|
|
||||||
|
|
||||||
## Major Bugs Fixed
|
|
||||||
|
|
||||||
### 1. Memory Leaks in scanFunction (FIXED ✓)
|
|
||||||
|
|
||||||
**Problem**: `readLine()` allocations in loop were never freed.
|
|
||||||
|
|
||||||
**Solution**:
|
|
||||||
```zig
|
|
||||||
while (!self.isAtEnd()) {
|
|
||||||
const line = try self.readLine();
|
|
||||||
defer self.allocator.free(line); // ← Added defer
|
|
||||||
// ... use line ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Result**: Zero memory leaks detected by GPA.
|
|
||||||
|
|
||||||
### 2. Function Name Conversion (FIXED ✓)
|
|
||||||
|
|
||||||
**Problem**: `SDL_GPUSupportsShaderFormats` became `gPUSupportsShaderFormats` instead of `gpuSupportsShaderFormats`.
|
|
||||||
|
|
||||||
**Solution**: Implemented proper leading acronym detection:
|
|
||||||
```zig
|
|
||||||
// Lowercase entire leading acronym until lowercase char found
|
|
||||||
var i: usize = 0;
|
|
||||||
while (i < result.len and std.ascii.isUpper(result[i])) : (i += 1) {
|
|
||||||
if (i > 0 and i + 1 < result.len and std.ascii.isLower(result[i + 1])) {
|
|
||||||
break; // Keep last uppercase - it starts next word
|
|
||||||
}
|
|
||||||
result[i] = std.ascii.toLower(result[i]);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Result**: Correctly generates `gpuSupportsShaderFormats`, `createGPUDevice`, etc.
|
|
||||||
|
|
||||||
### 3. Enum/Struct Parsing Broken (FIXED ✓)
|
|
||||||
|
|
||||||
**Problem**: `matchPrefix()` consumes input, then `readLine()` reads from wrong position.
|
|
||||||
|
|
||||||
**Before (broken)**:
|
|
||||||
```zig
|
|
||||||
if (self.matchPrefix("typedef enum ")) { // pos moves past "typedef enum "
|
|
||||||
const line = try self.readLine(); // reads "SDL_GPUPrimitiveType {"
|
|
||||||
var iter = std.mem.tokenizeScalar(u8, line, ' ');
|
|
||||||
_ = iter.next(); // expects "typedef" - NOT THERE!
|
|
||||||
_ = iter.next(); // expects "enum" - NOT THERE!
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**After (fixed)**:
|
|
||||||
```zig
|
|
||||||
if (self.matchPrefix("typedef enum ")) {
|
|
||||||
const name_start = self.pos;
|
|
||||||
while (self.pos < self.source.len and self.source[self.pos] != '{') {
|
|
||||||
self.pos += 1;
|
|
||||||
}
|
|
||||||
const name_slice = std.mem.trim(u8, self.source[name_start..self.pos], " \t\n\r");
|
|
||||||
var iter = std.mem.tokenizeScalar(u8, name_slice, ' ');
|
|
||||||
const name = iter.next() orelse return null; // Gets "SDL_GPUPrimitiveType"
|
|
||||||
const body = try self.readBracedBlock(); // Now positioned at '{'
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Result**: Enums and structs parse correctly.
|
|
||||||
|
|
||||||
### 4. Brace Characters in Output (FIXED ✓)
|
|
||||||
|
|
||||||
**Problem**: `readBracedBlock()` returns full source including `{`, `}`, and typedef name. These appeared as enum values.
|
|
||||||
|
|
||||||
**Solution**: Filter brace lines:
|
|
||||||
```zig
|
|
||||||
while (lines.next()) |line| {
|
|
||||||
const trimmed = std.mem.trim(u8, line, " \t\r");
|
|
||||||
if (trimmed.len == 0) continue;
|
|
||||||
if (std.mem.startsWith(u8, trimmed, "{")) continue; // ← Added
|
|
||||||
if (std.mem.startsWith(u8, trimmed, "}")) continue; // ← Added
|
|
||||||
// Parse actual content...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Result**: Clean enum values and struct fields.
|
|
||||||
|
|
||||||
## Test Results
|
|
||||||
|
|
||||||
All 14 tests passing:
|
|
||||||
|
|
||||||
```
|
|
||||||
1/14 codegen.test.generate opaque type...OK
|
|
||||||
2/14 codegen.test.generate enum...OK
|
|
||||||
3/14 codegen.test.parse bit position...OK
|
|
||||||
4/14 patterns.test.scan opaque typedef...OK
|
|
||||||
5/14 patterns.test.scan function declaration...OK
|
|
||||||
6/14 naming.test.strip SDL prefix...OK
|
|
||||||
7/14 naming.test.type name to Zig...OK
|
|
||||||
8/14 naming.test.function name to Zig...OK
|
|
||||||
9/14 naming.test.detect common prefix...OK
|
|
||||||
10/14 naming.test.enum value to Zig...OK
|
|
||||||
11/14 naming.test.screaming to lower camel...OK
|
|
||||||
12/14 types.test.convert primitive types...OK
|
|
||||||
13/14 types.test.convert SDL types...OK
|
|
||||||
14/14 types.test.convert pointer types...OK
|
|
||||||
All 14 tests passed.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Example Output
|
|
||||||
|
|
||||||
**Input** (`/tmp/test_sdl.h`):
|
|
||||||
```c
|
|
||||||
typedef struct SDL_GPUDevice SDL_GPUDevice;
|
|
||||||
|
|
||||||
typedef enum SDL_GPUPrimitiveType {
|
|
||||||
SDL_GPU_PRIMITIVETYPE_TRIANGLELIST,
|
|
||||||
SDL_GPU_PRIMITIVETYPE_LINELIST
|
|
||||||
} SDL_GPUPrimitiveType;
|
|
||||||
|
|
||||||
extern SDL_DECLSPEC bool SDLCALL SDL_GPUSupportsShaderFormats(
|
|
||||||
SDL_GPUShaderFormat format_flags,
|
|
||||||
const char *name);
|
|
||||||
|
|
||||||
extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice(
|
|
||||||
SDL_GPUShaderFormat format_flags,
|
|
||||||
bool debug_mode,
|
|
||||||
const char *name);
|
|
||||||
```
|
|
||||||
|
|
||||||
**Output**:
|
|
||||||
```zig
|
|
||||||
pub const c = @import("c.zig").c;
|
|
||||||
|
|
||||||
pub const GPUDevice = opaque {};
|
|
||||||
|
|
||||||
pub const GPUPrimitiveType = enum(c_int) {
|
|
||||||
trianglelist,
|
|
||||||
linelist,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub inline fn gpuSupportsShaderFormats(format_flags: GPUShaderFormat, name: [*c]const u8) bool {
|
|
||||||
return c.SDL_GPUSupportsShaderFormats(@bitCast(format_flags), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub inline fn createGPUDevice(format_flags: GPUShaderFormat, debug_mode: bool, name: [*c]const u8) *GPUDevice {
|
|
||||||
return @ptrCast(c.SDL_CreateGPUDevice(@bitCast(format_flags), debug_mode, name));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Statistics**:
|
|
||||||
- Found 4 declarations
|
|
||||||
- 1 opaque type, 1 enum, 2 functions
|
|
||||||
- Zero memory leaks
|
|
||||||
- Valid Zig code ready to compile
|
|
||||||
|
|
||||||
## Lessons Learned
|
|
||||||
|
|
||||||
### Scanner State Management
|
|
||||||
|
|
||||||
The biggest challenge was managing scanner position correctly when using `matchPrefix()` + other position-modifying operations. Key insight: **Don't mix `matchPrefix()` with `readLine()`** - they both move position and expect different starting states.
|
|
||||||
|
|
||||||
### Memory Management
|
|
||||||
|
|
||||||
Zig's explicit allocator pattern catches leaks early. Using `defer` for cleanup is essential, especially in loops where early `break` or `return` can skip manual cleanup.
|
|
||||||
|
|
||||||
### Text Transformation > Full Parsing
|
|
||||||
|
|
||||||
SDL3's headers are extremely regular. A simple text transformation approach (pattern matching + line-by-line parsing) is **significantly simpler** than a full recursive descent parser with semantic analysis. Original plan: 2000+ lines, 10+ modules. Final implementation: ~1400 lines, 4 modules.
|
|
||||||
|
|
||||||
### Zig 0.15 API Changes
|
|
||||||
|
|
||||||
Major changes encountered:
|
|
||||||
- ArrayList requires allocator for all methods
|
|
||||||
- Build system uses `root_module` instead of `root_source_file`
|
|
||||||
- `std.io.getStdOut()` moved to `std.posix.STDOUT_FILENO`
|
|
||||||
- Bit shift operand types must match exactly (u5 for u32 shifts)
|
|
||||||
|
|
||||||
## Remaining Work
|
|
||||||
|
|
||||||
- [ ] Test flag parsing (#define-based flags)
|
|
||||||
- [ ] Run on full SDL_gpu.h header
|
|
||||||
- [ ] Implement doc comment extraction and formatting
|
|
||||||
- [ ] Handle edge cases (function pointers, varargs, etc.)
|
|
||||||
- [ ] Performance testing on all 85 SDL3 headers
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build
|
|
||||||
zig build
|
|
||||||
|
|
||||||
# Parse a header
|
|
||||||
./zig-cache/o/*/sdl-parser path/to/header.h > output.zig
|
|
||||||
|
|
||||||
# Example
|
|
||||||
./zig-cache/o/*/sdl-parser ../SDL/include/SDL3/SDL_gpu.h > gpu.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
Successfully built a working SDL3 header parser in Zig with clean architecture, comprehensive tests, and proper memory management. The simplified approach proved significantly more maintainable than the original full-parser design, demonstrating the value of understanding your input domain before choosing an implementation strategy.
|
|
||||||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue