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:
Peterino2 2026-01-22 16:53:39 -08:00
parent 002ceb891a
commit 4440566657
10 changed files with 457 additions and 2322 deletions

View File

@ -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

View File

@ -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.

189
lib/sdl3/parser/output/SDL_gpu.h.json vendored Normal file

File diff suppressed because one or more lines are too long

36
lib/sdl3/parser/output/SDL_init.json vendored Normal file
View File

@ -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 *"}]}
]
}

View File

@ -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 *"}]}
]
}

33
lib/sdl3/parser/output/SDL_rect.h.json vendored Normal file
View File

@ -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 *"}]}
]
}

143
lib/sdl3/parser/output/SDL_video.json vendored Normal file
View File

@ -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"}]}
]
}

View File

@ -17,16 +17,16 @@ pub const JsonSerializer = struct {
pub fn init(allocator: std.mem.Allocator, header_name: []const u8) JsonSerializer {
return .{
.allocator = allocator,
.output = std.ArrayList(u8){},
.output = .{},
.header_name = header_name,
.opaque_types = std.ArrayList(patterns.OpaqueType){},
.typedefs = std.ArrayList(patterns.TypedefDecl){},
.function_pointers = std.ArrayList(patterns.FunctionPointerDecl){},
.enums = std.ArrayList(patterns.EnumDecl){},
.structs = std.ArrayList(patterns.StructDecl){},
.unions = std.ArrayList(patterns.UnionDecl){},
.flags = std.ArrayList(patterns.FlagDecl){},
.functions = std.ArrayList(patterns.FunctionDecl){},
.opaque_types = .{},
.typedefs = .{},
.function_pointers = .{},
.enums = .{},
.structs = .{},
.unions = .{},
.flags = .{},
.functions = .{},
};
}

View File

@ -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