getting rid of the extra clanker docs
This commit is contained in:
parent
4ffb701a36
commit
7c47116ff0
|
|
@ -1,348 +0,0 @@
|
||||||
# API Reference
|
|
||||||
|
|
||||||
Complete reference for the SDL3 header parser command-line interface.
|
|
||||||
|
|
||||||
## Command Syntax
|
|
||||||
|
|
||||||
```bash
|
|
||||||
zig build run -- <header_file> [options]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Arguments
|
|
||||||
|
|
||||||
### Required
|
|
||||||
|
|
||||||
**`<header_file>`** - Path to SDL C header file
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
```bash
|
|
||||||
zig build run -- ../SDL/include/SDL3/SDL_gpu.h
|
|
||||||
zig build run -- /full/path/to/SDL_video.h
|
|
||||||
zig build run -- relative/path/to/header.h
|
|
||||||
```
|
|
||||||
|
|
||||||
### Optional
|
|
||||||
|
|
||||||
**`--output=<file>`** - Write output to file instead of stdout
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
```bash
|
|
||||||
--output=gpu.zig
|
|
||||||
--output=bindings/video.zig
|
|
||||||
--output=/tmp/test.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
**`--mocks=<file>`** - Generate C mock implementations
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
```bash
|
|
||||||
--mocks=gpu_mock.c
|
|
||||||
--mocks=test/mocks.c
|
|
||||||
```
|
|
||||||
|
|
||||||
**`--generate-json=<file>`** - Generate JSON representation of parsed types
|
|
||||||
|
|
||||||
Examples:
|
|
||||||
```bash
|
|
||||||
--generate-json=gpu.json
|
|
||||||
--generate-json=api/types.json
|
|
||||||
```
|
|
||||||
|
|
||||||
## Output Formats
|
|
||||||
|
|
||||||
### Zig Bindings (Default)
|
|
||||||
|
|
||||||
Generated when `--output` is specified (or to stdout if not):
|
|
||||||
|
|
||||||
```zig
|
|
||||||
pub const c = @import("c.zig").c;
|
|
||||||
|
|
||||||
pub const GPUDevice = opaque {
|
|
||||||
pub inline fn createGPUDevice(debug_mode: bool) ?*GPUDevice {
|
|
||||||
return c.SDL_CreateGPUDevice(debug_mode);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Features**:
|
|
||||||
- Type conversions (C → Zig)
|
|
||||||
- Method organization
|
|
||||||
- Dependency inclusion
|
|
||||||
- Doc comments preserved
|
|
||||||
|
|
||||||
### C Mocks (Optional)
|
|
||||||
|
|
||||||
Generated when `--mocks` is specified:
|
|
||||||
|
|
||||||
```c
|
|
||||||
// Auto-generated C mock implementations
|
|
||||||
#include <SDL3/SDL_gpu.h>
|
|
||||||
|
|
||||||
SDL_GPUDevice* SDL_CreateGPUDevice(bool debug_mode) {
|
|
||||||
return NULL; // Mock: always returns null
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL_DestroyGPUDevice(SDL_GPUDevice *device) {
|
|
||||||
// Mock: no-op
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Use Case**: Testing without real SDL implementation
|
|
||||||
|
|
||||||
### JSON Output (Optional)
|
|
||||||
|
|
||||||
Generated when `--generate-json` is specified:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"header": "SDL_gpu.h",
|
|
||||||
"opaque_types": [
|
|
||||||
{"name": "SDL_GPUDevice"}
|
|
||||||
],
|
|
||||||
"typedefs": [
|
|
||||||
{"name": "SDL_PropertiesID", "underlying_type": "Uint32"}
|
|
||||||
],
|
|
||||||
"enums": [
|
|
||||||
{
|
|
||||||
"name": "SDL_GPUPrimitiveType",
|
|
||||||
"values": [
|
|
||||||
{"name": "SDL_GPU_PRIMITIVETYPE_TRIANGLELIST"},
|
|
||||||
{"name": "SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"structs": [
|
|
||||||
{
|
|
||||||
"name": "SDL_GPUViewport",
|
|
||||||
"fields": [
|
|
||||||
{"name": "x", "type": "float"},
|
|
||||||
{"name": "y", "type": "float"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"functions": [
|
|
||||||
{
|
|
||||||
"name": "SDL_CreateGPUDevice",
|
|
||||||
"return_type": "SDL_GPUDevice*",
|
|
||||||
"parameters": [
|
|
||||||
{"name": "debug_mode", "type": "bool"}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Use Cases**:
|
|
||||||
- API documentation generation
|
|
||||||
- Schema validation
|
|
||||||
- Cross-language binding generation
|
|
||||||
- Type introspection tools
|
|
||||||
|
|
||||||
## Build System Integration
|
|
||||||
|
|
||||||
### In build.zig
|
|
||||||
|
|
||||||
```zig
|
|
||||||
const parser_dep = b.dependency("sdl3_parser", .{
|
|
||||||
.target = target,
|
|
||||||
.optimize = optimize,
|
|
||||||
});
|
|
||||||
const parser_exe = parser_dep.artifact("sdl-parser");
|
|
||||||
|
|
||||||
const gen = b.addRunArtifact(parser_exe);
|
|
||||||
gen.addFileArg(b.path("SDL/include/SDL3/SDL_gpu.h"));
|
|
||||||
gen.addArg("--output=src/gpu.zig");
|
|
||||||
|
|
||||||
const gen_step = b.step("generate", "Generate SDL bindings");
|
|
||||||
gen_step.dependOn(&gen.step);
|
|
||||||
```
|
|
||||||
|
|
||||||
Then run:
|
|
||||||
```bash
|
|
||||||
zig build generate
|
|
||||||
```
|
|
||||||
|
|
||||||
## Parser Behavior
|
|
||||||
|
|
||||||
### Dependency Resolution
|
|
||||||
|
|
||||||
**Automatic** - No configuration needed
|
|
||||||
|
|
||||||
When the parser detects missing types, it:
|
|
||||||
1. Parses `#include` directives from the header
|
|
||||||
2. Searches each included header
|
|
||||||
3. Extracts matching type definitions
|
|
||||||
4. Includes them in the output
|
|
||||||
|
|
||||||
**Progress Reporting**:
|
|
||||||
```
|
|
||||||
Analyzing dependencies...
|
|
||||||
Found 5 missing types:
|
|
||||||
- SDL_Window
|
|
||||||
- SDL_Rect
|
|
||||||
...
|
|
||||||
|
|
||||||
Resolving dependencies...
|
|
||||||
✓ Found SDL_Window in SDL_video.h
|
|
||||||
✓ Found SDL_Rect in SDL_rect.h
|
|
||||||
```
|
|
||||||
|
|
||||||
### Type Filtering
|
|
||||||
|
|
||||||
Only SDL types are processed:
|
|
||||||
- Types starting with `SDL_`
|
|
||||||
- Known SDL types (Window, Rect, etc.)
|
|
||||||
|
|
||||||
Primitive types are ignored:
|
|
||||||
- `bool`, `int`, `float`, `void`, etc.
|
|
||||||
|
|
||||||
### Pattern Matching Order
|
|
||||||
|
|
||||||
Patterns are tried in this order:
|
|
||||||
1. Opaque types (`typedef struct X X;`)
|
|
||||||
2. Enums (`typedef enum {...} X;`)
|
|
||||||
3. Structs (`typedef struct {...} X;`)
|
|
||||||
4. Flags (`typedef Uint32 SDL_Flags;` + `#define` values)
|
|
||||||
5. Typedefs (`typedef Type SDL_Alias;`)
|
|
||||||
6. Functions (`extern SDL_DECLSPEC ...`)
|
|
||||||
|
|
||||||
**Note**: Order matters! Flags must be tried before simple typedefs.
|
|
||||||
|
|
||||||
### Naming Conventions
|
|
||||||
|
|
||||||
**Types**:
|
|
||||||
- `SDL_GPUDevice` → `GPUDevice` (strip `SDL_` prefix)
|
|
||||||
- `SDL_GPU_PRIMITIVE_TYPE` → `GPUPrimitiveType` (remove first underscore)
|
|
||||||
|
|
||||||
**Functions**:
|
|
||||||
- `SDL_CreateGPUDevice` → `createGPUDevice` (strip `SDL_`, camelCase)
|
|
||||||
|
|
||||||
**Enum Values**:
|
|
||||||
- `SDL_GPU_PRIMITIVETYPE_TRIANGLELIST` → `primitiveTypeTrianglelist`
|
|
||||||
|
|
||||||
**Parameters**:
|
|
||||||
- `SDL_GPUDevice *device` → `device: ?*GPUDevice`
|
|
||||||
|
|
||||||
## Exit Codes
|
|
||||||
|
|
||||||
- `0` - Success
|
|
||||||
- `1` - Error (file not found, out of memory, invalid arguments)
|
|
||||||
|
|
||||||
## Console Output
|
|
||||||
|
|
||||||
### Normal Operation
|
|
||||||
|
|
||||||
```
|
|
||||||
SDL3 Header Parser
|
|
||||||
==================
|
|
||||||
|
|
||||||
Parsing: header.h
|
|
||||||
|
|
||||||
Found N declarations
|
|
||||||
- Opaque types: X
|
|
||||||
- Typedefs: X
|
|
||||||
- Enums: X
|
|
||||||
- Structs: X
|
|
||||||
- Flags: X
|
|
||||||
- Functions: X
|
|
||||||
|
|
||||||
Analyzing dependencies...
|
|
||||||
[dependency information]
|
|
||||||
|
|
||||||
Generated: output.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
File is still written, but may need manual fixes.
|
|
||||||
|
|
||||||
## Type Conversion Reference
|
|
||||||
|
|
||||||
### Integer Types
|
|
||||||
|
|
||||||
| C Type | Zig Type |
|
|
||||||
|--------|----------|
|
|
||||||
| `Uint8` | `u8` |
|
|
||||||
| `Uint16` | `u16` |
|
|
||||||
| `Uint32` | `u32` |
|
|
||||||
| `Uint64` | `u64` |
|
|
||||||
| `Sint8` | `i8` |
|
|
||||||
| `Sint16` | `i16` |
|
|
||||||
| `Sint32` | `i32` |
|
|
||||||
| `Sint64` | `i64` |
|
|
||||||
| `int` | `c_int` |
|
|
||||||
| `unsigned int` | `c_uint` |
|
|
||||||
| `size_t` | `usize` |
|
|
||||||
|
|
||||||
### Pointer Types
|
|
||||||
|
|
||||||
| C Type | Zig Type |
|
|
||||||
|--------|----------|
|
|
||||||
| `SDL_Type*` | `?*Type` (nullable) |
|
|
||||||
| `const SDL_Type*` | `*const Type` |
|
|
||||||
| `SDL_Type**` | `?*?*Type` |
|
|
||||||
| `void*` | `?*anyopaque` |
|
|
||||||
| `const void*` | `*const anyopaque` |
|
|
||||||
| `const char*` | `[*c]const u8` |
|
|
||||||
|
|
||||||
### Special Types
|
|
||||||
|
|
||||||
| C Type | Zig Type |
|
|
||||||
|--------|----------|
|
|
||||||
| `bool` | `bool` |
|
|
||||||
| `float` | `f32` |
|
|
||||||
| `double` | `f64` |
|
|
||||||
| `size_t` | `usize` |
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
**Input** (depends.h):
|
|
||||||
```c
|
|
||||||
#include <SDL3/SDL_rect.h>
|
|
||||||
|
|
||||||
extern void SDL_UseRect(SDL_Rect *rect);
|
|
||||||
```
|
|
||||||
|
|
||||||
**Command**:
|
|
||||||
```bash
|
|
||||||
zig build run -- depends.h --output=depends.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
**Output**:
|
|
||||||
```zig
|
|
||||||
pub const c = @import("c.zig").c;
|
|
||||||
|
|
||||||
// Dependency automatically included
|
|
||||||
pub const Rect = extern struct {
|
|
||||||
x: c_int,
|
|
||||||
y: c_int,
|
|
||||||
w: c_int,
|
|
||||||
h: c_int,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub inline fn useRect(rect: *Rect) void {
|
|
||||||
return c.SDL_UseRect(rect);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Mocks example
|
|
||||||
|
|
||||||
**Command**:
|
|
||||||
```bash
|
|
||||||
zig build run -- simple.h --output=thing.zig --mocks=thing_mock.c
|
|
||||||
```
|
|
||||||
|
|
||||||
**Output** (thing_mock.c):
|
|
||||||
```c
|
|
||||||
#include <SDL3/SDL.h>
|
|
||||||
|
|
||||||
SDL_ThingID SDL_CreateThing(void) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SDL_DestroyThing(SDL_Thing *thing) {
|
|
||||||
// No-op
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
@ -1,430 +0,0 @@
|
||||||
# ## Documentation
|
|
||||||
|
|
||||||
- **[README](../README.md)** - Project overview and quick start
|
|
||||||
- **[Getting Started](GETTING_STARTED.md)** - Installation and first steps
|
|
||||||
- **[Architecture](ARCHITECTURE.md)** - How the parser works
|
|
||||||
- **[Dependency Resolution](DEPENDENCY_RESOLUTION.md)** - Automatic type extraction
|
|
||||||
- **[API Reference](API_REFERENCE.md)** - Command-line options and features
|
|
||||||
- **[Known Issues](KNOWN_ISSUES.md)** - Limitations and workarounds
|
|
||||||
- **[Quickstart Guide](QUICKSTART.md)** - Quick reference
|
|
||||||
- **[Roadmap](ROADMAP.md)** - Future plans and priorities
|
|
||||||
|
|
||||||
## Technical Deep Dives
|
|
||||||
|
|
||||||
For implementation details and visual guides:
|
|
||||||
- **[Dependency Flow](DEPENDENCY_FLOW.md)** - Complete technical walkthrough
|
|
||||||
- **[Visual Flow Diagrams](VISUAL_FLOW.md)** - Quick reference diagrams
|
|
||||||
- **[Multi-Field Structs](MULTI_FIELD_IMPLEMENTATION.md)** - Struct parsing details
|
|
||||||
- **[Typedef Support](TYPEDEF_IMPLEMENTATION.md)** - Typedef implementation
|
|
||||||
- **[Multi-Header Testing](MULTI_HEADER_TEST_RESULTS.md)** - Test results
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
- **[Development Guide](DEVELOPMENT.md)** - Contributing and extending the parser
|
|
||||||
|
|
||||||
## Archive
|
|
||||||
|
|
||||||
Historical planning documents are in `archive/` for reference.
|
|
||||||
|
|
||||||
## High-Level Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
Input (C Header) → Scanner → Declarations → Dependency Resolver → CodeGen → Output (Zig)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Core Components
|
|
||||||
|
|
||||||
### 1. Scanner (`src/patterns.zig`)
|
|
||||||
|
|
||||||
**Purpose**: Parse C header files into structured declarations
|
|
||||||
|
|
||||||
**Process**:
|
|
||||||
1. Reads header file line by line
|
|
||||||
2. Tries to match each line against known patterns
|
|
||||||
3. Extracts type information, comments, and structure
|
|
||||||
4. Returns array of `Declaration` structures
|
|
||||||
|
|
||||||
**Supported Patterns**:
|
|
||||||
- Opaque types: `typedef struct SDL_X SDL_X;`
|
|
||||||
- Typedefs: `typedef Uint32 SDL_PropertiesID;`
|
|
||||||
- Enums: `typedef enum { ... } SDL_Type;`
|
|
||||||
- Structs: `typedef struct { int x, y; } SDL_Rect;`
|
|
||||||
- Flags: `typedef Uint32 SDL_Flags;` + `#define` values
|
|
||||||
- Functions: `extern SDL_DECLSPEC void SDLCALL SDL_Func(...);`
|
|
||||||
|
|
||||||
### 2. Dependency Resolver (`src/dependency_resolver.zig`)
|
|
||||||
|
|
||||||
**Purpose**: Automatically find and extract missing type definitions
|
|
||||||
|
|
||||||
**Process**:
|
|
||||||
1. Scans all declarations to find referenced types
|
|
||||||
2. Compares referenced types against defined types
|
|
||||||
3. Identifies missing types
|
|
||||||
4. Parses `#include` directives from source
|
|
||||||
5. Searches included headers for missing types
|
|
||||||
6. Extracts and clones matching declarations
|
|
||||||
|
|
||||||
**Key Features**:
|
|
||||||
- Type string normalization (strips `*`, `const`, etc.)
|
|
||||||
- Deduplication using HashMaps
|
|
||||||
- Deep cloning for safe ownership
|
|
||||||
- Selective extraction (only types needed)
|
|
||||||
|
|
||||||
### 3. Code Generator (`src/codegen.zig`)
|
|
||||||
|
|
||||||
**Purpose**: Convert C declarations to idiomatic Zig code
|
|
||||||
|
|
||||||
**Process**:
|
|
||||||
1. Groups functions by first parameter type (method categorization)
|
|
||||||
2. Generates type declarations
|
|
||||||
3. Generates function wrappers
|
|
||||||
4. Applies naming conventions
|
|
||||||
5. Performs type conversion
|
|
||||||
|
|
||||||
**Features**:
|
|
||||||
- Method organization for opaque types
|
|
||||||
- Inline function wrappers
|
|
||||||
- Automatic type conversion
|
|
||||||
- Doc comment preservation
|
|
||||||
|
|
||||||
### 4. Type Converter (`src/types.zig`)
|
|
||||||
|
|
||||||
**Purpose**: Convert C types to Zig equivalents
|
|
||||||
|
|
||||||
**Conversions**:
|
|
||||||
```zig
|
|
||||||
"bool" → "bool"
|
|
||||||
"Uint32" → "u32"
|
|
||||||
"int" → "c_int"
|
|
||||||
"SDL_Type *" → "?*Type"
|
|
||||||
"const SDL_Type *" → "*const Type"
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Naming Convention Handler (`src/naming.zig`)
|
|
||||||
|
|
||||||
**Purpose**: Convert C names to idiomatic Zig
|
|
||||||
|
|
||||||
**Rules**:
|
|
||||||
- Strip `SDL_` prefix: `SDL_GPUDevice` → `GPUDevice`
|
|
||||||
- Remove first underscore: `SDL_GPU_TYPE` → `GPUType`
|
|
||||||
- CamelCase functions: `SDL_CreateDevice` → `createDevice`
|
|
||||||
- Lowercase first letter for values
|
|
||||||
|
|
||||||
## Data Flow
|
|
||||||
|
|
||||||
### 1. Parsing Phase
|
|
||||||
|
|
||||||
```
|
|
||||||
C Header File
|
|
||||||
↓
|
|
||||||
Scanner.scan()
|
|
||||||
↓
|
|
||||||
[]Declaration {
|
|
||||||
.opaque_type,
|
|
||||||
.typedef_decl,
|
|
||||||
.enum_decl,
|
|
||||||
.struct_decl,
|
|
||||||
.flag_decl,
|
|
||||||
.function_decl,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Dependency Analysis Phase
|
|
||||||
|
|
||||||
```
|
|
||||||
[]Declaration
|
|
||||||
↓
|
|
||||||
DependencyResolver.analyze()
|
|
||||||
├─ collectDefinedTypes() → defined_types HashMap
|
|
||||||
└─ collectReferencedTypes() → referenced_types HashMap
|
|
||||||
↓
|
|
||||||
getMissingTypes()
|
|
||||||
↓
|
|
||||||
missing_types = referenced - defined
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Dependency Resolution Phase
|
|
||||||
|
|
||||||
```
|
|
||||||
For each missing_type:
|
|
||||||
Parse #include directives
|
|
||||||
↓
|
|
||||||
For each included header:
|
|
||||||
Read header file
|
|
||||||
↓
|
|
||||||
Scanner.scan()
|
|
||||||
↓
|
|
||||||
Search for matching type
|
|
||||||
↓
|
|
||||||
If found: cloneDeclaration()
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. Code Generation Phase
|
|
||||||
|
|
||||||
```
|
|
||||||
[]Declaration (primary + dependencies)
|
|
||||||
↓
|
|
||||||
CodeGen.generate()
|
|
||||||
├─ categorizeDeclarations() (group methods)
|
|
||||||
├─ writeHeader()
|
|
||||||
└─ writeDeclarations()
|
|
||||||
├─ writeOpaqueWithMethods()
|
|
||||||
├─ writeTypedef()
|
|
||||||
├─ writeEnum()
|
|
||||||
├─ writeStruct()
|
|
||||||
├─ writeFlags()
|
|
||||||
└─ writeFunction()
|
|
||||||
↓
|
|
||||||
Zig source code (string)
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. Validation Phase
|
|
||||||
|
|
||||||
```
|
|
||||||
Generated Zig code
|
|
||||||
↓
|
|
||||||
std.zig.Ast.parse()
|
|
||||||
↓
|
|
||||||
Check for syntax errors
|
|
||||||
↓
|
|
||||||
ast.renderAlloc() (format)
|
|
||||||
↓
|
|
||||||
Write to file or stdout
|
|
||||||
```
|
|
||||||
|
|
||||||
## Key Algorithms
|
|
||||||
|
|
||||||
### Type Extraction
|
|
||||||
|
|
||||||
**Purpose**: Strip pointer/const decorators to get base type
|
|
||||||
|
|
||||||
```zig
|
|
||||||
"SDL_Window *" → "SDL_Window"
|
|
||||||
"?*const SDL_Rect" → "SDL_Rect"
|
|
||||||
"SDL_Buffer *const *" → "SDL_Buffer"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Algorithm**:
|
|
||||||
1. Trim whitespace
|
|
||||||
2. Remove leading qualifiers (`const`, `*`, `?`)
|
|
||||||
3. Remove trailing qualifiers (`*`, `*const`, ` const`)
|
|
||||||
4. Handle special patterns (`[*c]`)
|
|
||||||
5. Return base type string
|
|
||||||
|
|
||||||
### Multi-Field Parsing
|
|
||||||
|
|
||||||
**Purpose**: Handle C compact syntax like `int x, y;`
|
|
||||||
|
|
||||||
**Algorithm**:
|
|
||||||
1. Detect comma in field declaration
|
|
||||||
2. Extract common type (before first field name)
|
|
||||||
3. Split remaining part on commas
|
|
||||||
4. Create separate `FieldDecl` for each name
|
|
||||||
5. Return array of fields
|
|
||||||
|
|
||||||
**Example**:
|
|
||||||
```c
|
|
||||||
int x, y; → [FieldDecl{.name="x", .type="int"},
|
|
||||||
FieldDecl{.name="y", .type="int"}]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Method Categorization
|
|
||||||
|
|
||||||
**Purpose**: Determine if function should be a method
|
|
||||||
|
|
||||||
**Algorithm**:
|
|
||||||
1. Check if function has parameters
|
|
||||||
2. Get type of first parameter
|
|
||||||
3. Check if type is an opaque type pointer
|
|
||||||
4. If yes, add to opaque type's methods
|
|
||||||
5. If no, write as standalone function
|
|
||||||
|
|
||||||
**Example**:
|
|
||||||
```c
|
|
||||||
void SDL_Destroy(SDL_Device *d) → Method of GPUDevice
|
|
||||||
void SDL_Init(void) → Standalone function
|
|
||||||
```
|
|
||||||
|
|
||||||
## Memory Management
|
|
||||||
|
|
||||||
### Ownership Rules
|
|
||||||
|
|
||||||
1. **Scanner owns strings** during parsing (allocated from its allocator)
|
|
||||||
2. **Parser owns declarations** after scanning (freed at end of main)
|
|
||||||
3. **Resolver owns HashMap keys** (duped when inserted, freed in deinit)
|
|
||||||
4. **Cloned declarations own strings** (allocated explicitly, freed by caller)
|
|
||||||
|
|
||||||
### Allocation Strategy
|
|
||||||
|
|
||||||
```
|
|
||||||
GPA (General Purpose Allocator)
|
|
||||||
├─ Primary header source (freed at end)
|
|
||||||
├─ Primary declarations (freed with deep free)
|
|
||||||
├─ DependencyResolver
|
|
||||||
│ ├─ referenced_types HashMap (keys owned)
|
|
||||||
│ └─ defined_types HashMap (keys borrowed)
|
|
||||||
├─ Missing types array (freed explicitly)
|
|
||||||
├─ Includes array (freed explicitly)
|
|
||||||
├─ Dependency declarations (freed with deep free)
|
|
||||||
└─ Generated output (freed after writing)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Cleanup Pattern
|
|
||||||
|
|
||||||
```zig
|
|
||||||
defer {
|
|
||||||
for (decls) |decl| {
|
|
||||||
freeDeclDeep(allocator, decl);
|
|
||||||
}
|
|
||||||
allocator.free(decls);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
### Fatal Errors (Exit Immediately)
|
|
||||||
|
|
||||||
- File not found (primary header)
|
|
||||||
- Out of memory
|
|
||||||
- Cannot write output file
|
|
||||||
|
|
||||||
### Non-Fatal Errors (Continue with Warnings)
|
|
||||||
|
|
||||||
- Dependency header not readable → Skip, try next
|
|
||||||
- Type not found in any header → Print warning, continue
|
|
||||||
- Struct parsing error → Generate partial, continue
|
|
||||||
- Syntax errors in output → Print errors, write anyway
|
|
||||||
|
|
||||||
### Error Recovery
|
|
||||||
|
|
||||||
The parser uses graceful degradation:
|
|
||||||
1. Try to extract as much as possible
|
|
||||||
2. Warn about issues
|
|
||||||
3. Continue processing
|
|
||||||
4. Generate best-effort output
|
|
||||||
|
|
||||||
This allows partial success even with problematic headers.
|
|
||||||
|
|
||||||
## Extension Points
|
|
||||||
|
|
||||||
### Adding New Pattern Support
|
|
||||||
|
|
||||||
1. Add new variant to `Declaration` union in `patterns.zig`
|
|
||||||
2. Implement `scan*()` function to match pattern
|
|
||||||
3. Add to pattern matching chain in `Scanner.scan()`
|
|
||||||
4. Update all switch statements:
|
|
||||||
- Cleanup code in `parser.zig`
|
|
||||||
- `cloneDeclaration()` in `dependency_resolver.zig`
|
|
||||||
- `freeDeclaration()` in `dependency_resolver.zig`
|
|
||||||
5. Implement `write*()` in `codegen.zig`
|
|
||||||
|
|
||||||
### Adding Type Conversions
|
|
||||||
|
|
||||||
Edit `src/types.zig`:
|
|
||||||
```zig
|
|
||||||
pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 {
|
|
||||||
// Add new conversion here
|
|
||||||
if (std.mem.eql(u8, c_type, "MyType")) {
|
|
||||||
return try allocator.dupe(u8, "MyZigType");
|
|
||||||
}
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding Naming Rules
|
|
||||||
|
|
||||||
Edit `src/naming.zig`:
|
|
||||||
```zig
|
|
||||||
pub fn typeNameToZig(c_name: []const u8) []const u8 {
|
|
||||||
// Add custom naming logic
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Performance Characteristics
|
|
||||||
|
|
||||||
### Time Complexity
|
|
||||||
|
|
||||||
- **Primary parsing**: O(n) where n = source lines
|
|
||||||
- **Dependency analysis**: O(d) where d = declarations
|
|
||||||
- **Type extraction**: O(h × d) where h = headers, d = declarations per header
|
|
||||||
- **Code generation**: O(d) where d = total declarations
|
|
||||||
|
|
||||||
**Overall**: O(n + h×d) - Linear for typical use
|
|
||||||
|
|
||||||
### Space Complexity
|
|
||||||
|
|
||||||
- **Declarations**: O(d) where d = declaration count
|
|
||||||
- **HashMaps**: O(t) where t = unique type names
|
|
||||||
- **Output**: O(d) where d = declaration count
|
|
||||||
|
|
||||||
**Peak memory**: ~2-5MB for SDL_gpu.h (169 declarations)
|
|
||||||
|
|
||||||
### Optimization Points
|
|
||||||
|
|
||||||
Current optimizations:
|
|
||||||
- HashMap-based deduplication
|
|
||||||
- Early exit when type found
|
|
||||||
- Selective parsing (only missing types)
|
|
||||||
- String interning for type names
|
|
||||||
|
|
||||||
Potential improvements:
|
|
||||||
- Cache parsed headers (avoid re-parsing)
|
|
||||||
- Parallel header processing
|
|
||||||
- Lazy header loading
|
|
||||||
|
|
||||||
## Testing Strategy
|
|
||||||
|
|
||||||
### Unit Tests (`test/`)
|
|
||||||
|
|
||||||
- Pattern matching tests (each C pattern)
|
|
||||||
- Type conversion tests
|
|
||||||
- Naming convention tests
|
|
||||||
- Dependency resolution tests
|
|
||||||
- Multi-field parsing tests
|
|
||||||
|
|
||||||
### Integration Tests
|
|
||||||
|
|
||||||
- Real SDL headers (SDL_gpu.h)
|
|
||||||
- Dependency chain resolution
|
|
||||||
- End-to-end parsing and generation
|
|
||||||
|
|
||||||
### Validation
|
|
||||||
|
|
||||||
- AST parsing of generated code
|
|
||||||
- Memory leak detection (GPA)
|
|
||||||
- No regressions (all tests must pass)
|
|
||||||
|
|
||||||
## Code Organization
|
|
||||||
|
|
||||||
```
|
|
||||||
src/
|
|
||||||
├── parser.zig # Main entry point, CLI handling
|
|
||||||
├── patterns.zig # Pattern matching and scanning
|
|
||||||
├── types.zig # C to Zig type conversion
|
|
||||||
├── naming.zig # Naming convention handling
|
|
||||||
├── codegen.zig # Zig code generation
|
|
||||||
├── mock_codegen.zig # C mock generation
|
|
||||||
└── dependency_resolver.zig # Dependency analysis and extraction
|
|
||||||
|
|
||||||
test/
|
|
||||||
└── (various test files)
|
|
||||||
|
|
||||||
docs/
|
|
||||||
├── GETTING_STARTED.md # This file
|
|
||||||
├── ARCHITECTURE.md # Architecture overview
|
|
||||||
├── DEPENDENCY_RESOLUTION.md # Dependency system details
|
|
||||||
└── ...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
- Read [Dependency Resolution](DEPENDENCY_RESOLUTION.md) for details on automatic type extraction
|
|
||||||
- See [API Reference](API_REFERENCE.md) for all command-line options
|
|
||||||
- Check [Known Issues](KNOWN_ISSUES.md) for current limitations
|
|
||||||
- Review [Development](DEVELOPMENT.md) to contribute
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Related Documents**:
|
|
||||||
- Technical deep dive: [docs/DEPENDENCY_FLOW.md](DEPENDENCY_FLOW.md)
|
|
||||||
- Visual diagrams: [docs/VISUAL_FLOW.md](VISUAL_FLOW.md)
|
|
||||||
|
|
@ -1,283 +0,0 @@
|
||||||
# Dependency Resolution System
|
|
||||||
|
|
||||||
The parser automatically detects and resolves type dependencies from SDL headers.
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
When parsing a header like SDL_gpu.h, functions often reference types defined in other headers (SDL_Window, SDL_Rect, etc.). The dependency resolver automatically finds and includes these types.
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
### Step 1: Detect Missing Types
|
|
||||||
|
|
||||||
After parsing the primary header, the system:
|
|
||||||
1. Scans all function signatures and struct fields
|
|
||||||
2. Extracts all referenced type names
|
|
||||||
3. Compares against types defined in the header
|
|
||||||
4. Identifies missing types
|
|
||||||
|
|
||||||
**Example**:
|
|
||||||
```c
|
|
||||||
// SDL_gpu.h
|
|
||||||
extern void SDL_ClaimWindow(SDL_GPUDevice *device, SDL_Window *window);
|
|
||||||
```
|
|
||||||
|
|
||||||
- `SDL_GPUDevice` is defined in SDL_gpu.h ✓
|
|
||||||
- `SDL_Window` is NOT defined in SDL_gpu.h ✗
|
|
||||||
|
|
||||||
**Result**: SDL_Window added to missing types list
|
|
||||||
|
|
||||||
### Step 2: Parse Include Directives
|
|
||||||
|
|
||||||
Extracts `#include` directives from the header:
|
|
||||||
```c
|
|
||||||
#include <SDL3/SDL_stdinc.h>
|
|
||||||
#include <SDL3/SDL_video.h>
|
|
||||||
#include <SDL3/SDL_rect.h>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Result**: List of headers to search: [`SDL_stdinc.h`, `SDL_video.h`, `SDL_rect.h`]
|
|
||||||
|
|
||||||
### Step 3: Search for Missing Types
|
|
||||||
|
|
||||||
For each missing type:
|
|
||||||
1. Try each included header in order
|
|
||||||
2. Parse the header completely
|
|
||||||
3. Search for matching type definition
|
|
||||||
4. If found, clone the declaration and stop searching
|
|
||||||
5. If not found, continue to next header
|
|
||||||
|
|
||||||
**Example Search for SDL_Window**:
|
|
||||||
```
|
|
||||||
Try SDL_stdinc.h → Not found
|
|
||||||
Try SDL_video.h → Found! ✓
|
|
||||||
└─ Extract SDL_Window definition
|
|
||||||
└─ Stop searching
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: Combine Declarations
|
|
||||||
|
|
||||||
```zig
|
|
||||||
final_declarations = [
|
|
||||||
// Dependencies FIRST (so types are defined before use)
|
|
||||||
SDL_Window,
|
|
||||||
SDL_Rect,
|
|
||||||
SDL_FColor,
|
|
||||||
|
|
||||||
// Primary declarations
|
|
||||||
SDL_GPUDevice,
|
|
||||||
SDL_GPUTexture,
|
|
||||||
...
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 5: Generate Unified Output
|
|
||||||
|
|
||||||
```zig
|
|
||||||
pub const c = @import("c.zig").c;
|
|
||||||
|
|
||||||
// Dependencies (automatically included)
|
|
||||||
pub const Window = opaque {};
|
|
||||||
pub const Rect = extern struct { x: c_int, y: c_int, w: c_int, h: c_int };
|
|
||||||
|
|
||||||
// Primary declarations
|
|
||||||
pub const GPUDevice = opaque {
|
|
||||||
pub fn claimWindow(device: *GPUDevice, window: ?*Window) bool {
|
|
||||||
return c.SDL_ClaimWindowForGPUDevice(device, window);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Type Extraction Details
|
|
||||||
|
|
||||||
### Type String Normalization
|
|
||||||
|
|
||||||
C type strings often have pointer and const decorators that need to be stripped:
|
|
||||||
|
|
||||||
```
|
|
||||||
"SDL_Window *" → "SDL_Window"
|
|
||||||
"?*SDL_GPUDevice" → "SDL_GPUDevice"
|
|
||||||
"*const SDL_Rect" → "SDL_Rect"
|
|
||||||
"SDL_Buffer *const *" → "SDL_Buffer"
|
|
||||||
"[*c]const u8" → "u8"
|
|
||||||
```
|
|
||||||
|
|
||||||
**Algorithm**:
|
|
||||||
1. Remove leading: `const`, `struct`, `?`, `*`
|
|
||||||
2. Handle C arrays: `[*c]T` → `T`
|
|
||||||
3. Remove trailing: `*`, `*const`, ` const`
|
|
||||||
4. Repeat until no changes
|
|
||||||
|
|
||||||
### SDL Type Detection
|
|
||||||
|
|
||||||
A type is considered "SDL" if:
|
|
||||||
- Name starts with `SDL_` prefix, OR
|
|
||||||
- Name is in known SDL types list (Window, Rect, etc.)
|
|
||||||
|
|
||||||
Non-SDL types (primitives) are ignored:
|
|
||||||
- `bool`, `int`, `float`, `void`, etc.
|
|
||||||
|
|
||||||
### Declaration Cloning
|
|
||||||
|
|
||||||
When extracting types from dependency headers, we must clone them because:
|
|
||||||
1. The temporary scanner will be freed
|
|
||||||
2. Original strings will be deallocated
|
|
||||||
3. We need owned copies with stable lifetime
|
|
||||||
|
|
||||||
**Cloning Process**:
|
|
||||||
```zig
|
|
||||||
fn cloneDeclaration(allocator: Allocator, decl: Declaration) !Declaration {
|
|
||||||
return switch (decl) {
|
|
||||||
.struct_decl => |s| .{
|
|
||||||
.struct_decl = .{
|
|
||||||
.name = try allocator.dupe(u8, s.name),
|
|
||||||
.fields = try cloneFields(allocator, s.fields),
|
|
||||||
.doc_comment = if (s.doc_comment) |doc|
|
|
||||||
try allocator.dupe(u8, doc) else null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
// ... similar for other types
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
All strings are duplicated so the cloned declaration owns them.
|
|
||||||
|
|
||||||
## Success Metrics
|
|
||||||
|
|
||||||
### SDL_gpu.h Results
|
|
||||||
|
|
||||||
**Missing Types Detected**: 5
|
|
||||||
1. SDL_FColor
|
|
||||||
2. SDL_PropertiesID
|
|
||||||
3. SDL_Rect
|
|
||||||
4. SDL_Window
|
|
||||||
5. SDL_FlipMode
|
|
||||||
|
|
||||||
**Resolution Results**: 5/5 (100%) ✅
|
|
||||||
|
|
||||||
**Where Found**:
|
|
||||||
- SDL_FColor → SDL_pixels.h (struct)
|
|
||||||
- SDL_PropertiesID → SDL_properties.h (typedef)
|
|
||||||
- SDL_Rect → SDL_rect.h (struct)
|
|
||||||
- SDL_Window → SDL_video.h (opaque)
|
|
||||||
- SDL_FlipMode → SDL_surface.h (enum)
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
|
|
||||||
### Behavior
|
|
||||||
|
|
||||||
The dependency resolver is **always enabled** - no configuration needed.
|
|
||||||
|
|
||||||
When missing types are detected, it automatically:
|
|
||||||
- ✅ Searches included headers
|
|
||||||
- ✅ Extracts matching types
|
|
||||||
- ✅ Combines into output
|
|
||||||
- ✅ Reports progress
|
|
||||||
|
|
||||||
### Error Handling
|
|
||||||
|
|
||||||
**Warnings** (non-fatal):
|
|
||||||
- Type not found in any header
|
|
||||||
- Dependency header not readable
|
|
||||||
- Parsing errors in dependency
|
|
||||||
|
|
||||||
**Result**: Partial output with warnings
|
|
||||||
|
|
||||||
## Performance
|
|
||||||
|
|
||||||
### Timing Breakdown (SDL_gpu.h)
|
|
||||||
|
|
||||||
| Phase | Time | Notes |
|
|
||||||
|-------|------|-------|
|
|
||||||
| Primary parsing | 50ms | Parse SDL_gpu.h |
|
|
||||||
| Dependency analysis | 10ms | Build HashMaps |
|
|
||||||
| Include parsing | 1ms | Extract #includes |
|
|
||||||
| Type extraction | 300ms | Parse 5 dependency headers |
|
|
||||||
| Code generation | 150ms | Generate + validate |
|
|
||||||
| **Total** | **~520ms** | Acceptable |
|
|
||||||
|
|
||||||
### Optimization
|
|
||||||
|
|
||||||
**Current**:
|
|
||||||
- Selective parsing (only types needed)
|
|
||||||
- Early exit (stop when found)
|
|
||||||
- HashMap deduplication
|
|
||||||
|
|
||||||
**Future**:
|
|
||||||
- Cache parsed headers
|
|
||||||
- Parallel header parsing
|
|
||||||
- Header dependency graph
|
|
||||||
|
|
||||||
## Limitations
|
|
||||||
|
|
||||||
### Not Resolved
|
|
||||||
|
|
||||||
1. **Function pointer typedefs** - Not yet supported
|
|
||||||
```c
|
|
||||||
typedef void (*SDL_Callback)(void *userdata);
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **#define-based types** - Requires preprocessor
|
|
||||||
```c
|
|
||||||
#define SDL_VALUE (1u << 0)
|
|
||||||
typedef Uint32 SDL_Type; // Not found by scanner
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **External library types** - Expected
|
|
||||||
```c
|
|
||||||
SDL_EGLConfig // From EGL, not SDL
|
|
||||||
```
|
|
||||||
|
|
||||||
### Workarounds
|
|
||||||
|
|
||||||
**Manual Definitions**: Add missing types to a separate file
|
|
||||||
```zig
|
|
||||||
// manual_types.zig
|
|
||||||
pub const Callback = *const fn(?*anyopaque) void;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Preprocessor**: Use clang to preprocess before parsing
|
|
||||||
```bash
|
|
||||||
clang -E -I/path/to/SDL3 header.h | zig build run --
|
|
||||||
```
|
|
||||||
|
|
||||||
## Debugging
|
|
||||||
|
|
||||||
### Enable Verbose Output
|
|
||||||
|
|
||||||
The parser already prints detailed progress:
|
|
||||||
```
|
|
||||||
Analyzing dependencies...
|
|
||||||
Found 5 missing types:
|
|
||||||
- SDL_FColor
|
|
||||||
- SDL_Rect
|
|
||||||
...
|
|
||||||
|
|
||||||
Resolving dependencies from included headers...
|
|
||||||
✓ Found SDL_FColor in SDL_pixels.h
|
|
||||||
✓ Found SDL_Rect in SDL_rect.h
|
|
||||||
⚠ Warning: Could not find definition for type: SDL_Unknown
|
|
||||||
```
|
|
||||||
|
|
||||||
### Common Issues
|
|
||||||
|
|
||||||
**"Could not find definition for type"**
|
|
||||||
- Type might be typedef (check if recently added)
|
|
||||||
- Type might be in different include
|
|
||||||
- Type might be external (EGL, GL, etc.)
|
|
||||||
|
|
||||||
**"Syntax errors in generated code"**
|
|
||||||
- Check generated file line numbers
|
|
||||||
- Usually struct/enum parsing issues
|
|
||||||
- See [Known Issues](KNOWN_ISSUES.md)
|
|
||||||
|
|
||||||
## Technical Details
|
|
||||||
|
|
||||||
For implementation details, see:
|
|
||||||
- [Technical Flow](DEPENDENCY_FLOW.md) - Step-by-step walkthrough
|
|
||||||
- [Visual Guide](VISUAL_FLOW.md) - Diagrams and quick reference
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Next**: See [API Reference](API_REFERENCE.md) for command-line options.
|
|
||||||
|
|
@ -1,634 +0,0 @@
|
||||||
# Development Guide
|
|
||||||
|
|
||||||
Guide for contributing to and extending the SDL3 header parser.
|
|
||||||
|
|
||||||
## Quick Start for Developers
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Clone and build
|
|
||||||
cd lib/sdl3/parser
|
|
||||||
zig build
|
|
||||||
|
|
||||||
# Run tests
|
|
||||||
zig build test
|
|
||||||
|
|
||||||
# Make changes
|
|
||||||
# ... edit src/*.zig ...
|
|
||||||
|
|
||||||
# Test your changes
|
|
||||||
zig build test
|
|
||||||
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=test.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
parser/
|
|
||||||
├── src/
|
|
||||||
│ ├── parser.zig # Main entry point, CLI
|
|
||||||
│ ├── patterns.zig # Pattern matching & scanning
|
|
||||||
│ ├── types.zig # C to Zig type conversion
|
|
||||||
│ ├── naming.zig # Naming conventions
|
|
||||||
│ ├── codegen.zig # Zig code generation
|
|
||||||
│ ├── mock_codegen.zig # C mock generation
|
|
||||||
│ └── dependency_resolver.zig # Dependency analysis
|
|
||||||
├── test/
|
|
||||||
│ └── (test files)
|
|
||||||
├── docs/
|
|
||||||
│ └── (documentation)
|
|
||||||
└── build.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
## Zig 0.15 API Changes - CRITICAL
|
|
||||||
|
|
||||||
**This project uses Zig 0.15**. Key API changes from 0.14:
|
|
||||||
|
|
||||||
### ArrayList Changes
|
|
||||||
|
|
||||||
**Old (0.14)**:
|
|
||||||
```zig
|
|
||||||
var list = std.ArrayList(T).init(allocator);
|
|
||||||
defer list.deinit();
|
|
||||||
try list.append(item);
|
|
||||||
```
|
|
||||||
|
|
||||||
**New (0.15)** - REQUIRED:
|
|
||||||
```zig
|
|
||||||
var list = std.ArrayList(T){};
|
|
||||||
defer list.deinit(allocator);
|
|
||||||
try list.append(allocator, item);
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Points**:
|
|
||||||
- Initialize with `{}` or `initCapacity()`
|
|
||||||
- All methods take allocator: `append(allocator, item)`
|
|
||||||
- Deinit takes allocator: `deinit(allocator)`
|
|
||||||
|
|
||||||
### AST Rendering
|
|
||||||
|
|
||||||
**Old**: `ast.render(allocator)`
|
|
||||||
**New**: `ast.renderAlloc(allocator)`
|
|
||||||
|
|
||||||
## Adding New Pattern Support
|
|
||||||
|
|
||||||
### Example: Adding Union Support
|
|
||||||
|
|
||||||
1. **Add to Declaration union** (patterns.zig):
|
|
||||||
```zig
|
|
||||||
pub const Declaration = union(enum) {
|
|
||||||
// ... existing variants
|
|
||||||
union_decl: UnionDecl, // NEW
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const UnionDecl = struct {
|
|
||||||
name: []const u8,
|
|
||||||
fields: []FieldDecl,
|
|
||||||
doc_comment: ?[]const u8,
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Add scanner function** (patterns.zig):
|
|
||||||
```zig
|
|
||||||
fn scanUnion(self: *Scanner) !?UnionDecl {
|
|
||||||
// Pattern matching logic
|
|
||||||
// Return UnionDecl or null
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Add to scan chain** (patterns.zig):
|
|
||||||
```zig
|
|
||||||
if (try self.scanOpaque()) |opaque_decl| {
|
|
||||||
// ...
|
|
||||||
} else if (try self.scanUnion()) |union_decl| {
|
|
||||||
try decls.append(self.allocator, .{ .union_decl = union_decl });
|
|
||||||
} else if (try self.scanEnum()) |enum_decl| {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Update cleanup code** (parser.zig):
|
|
||||||
```zig
|
|
||||||
defer {
|
|
||||||
for (decls) |decl| {
|
|
||||||
switch (decl) {
|
|
||||||
// ... existing cases
|
|
||||||
.union_decl => |u| {
|
|
||||||
allocator.free(u.name);
|
|
||||||
if (u.doc_comment) |doc| allocator.free(doc);
|
|
||||||
for (u.fields) |field| {
|
|
||||||
allocator.free(field.name);
|
|
||||||
allocator.free(field.type_name);
|
|
||||||
if (field.comment) |c| allocator.free(c);
|
|
||||||
}
|
|
||||||
allocator.free(u.fields);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
5. **Update dependency resolver** (dependency_resolver.zig):
|
|
||||||
```zig
|
|
||||||
// In collectDefinedTypes:
|
|
||||||
.union_decl => |u| u.name,
|
|
||||||
|
|
||||||
// In cloneDeclaration:
|
|
||||||
.union_decl => |u| .{
|
|
||||||
.union_decl = .{
|
|
||||||
.name = try allocator.dupe(u8, u.name),
|
|
||||||
.fields = try cloneFields(allocator, u.fields),
|
|
||||||
.doc_comment = if (u.doc_comment) |doc|
|
|
||||||
try allocator.dupe(u8, doc) else null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// In freeDeclaration:
|
|
||||||
.union_decl => |u| {
|
|
||||||
allocator.free(u.name);
|
|
||||||
if (u.doc_comment) |doc| allocator.free(doc);
|
|
||||||
for (u.fields) |field| {
|
|
||||||
allocator.free(field.name);
|
|
||||||
allocator.free(field.type_name);
|
|
||||||
if (field.comment) |c| allocator.free(c);
|
|
||||||
}
|
|
||||||
allocator.free(u.fields);
|
|
||||||
},
|
|
||||||
```
|
|
||||||
|
|
||||||
6. **Add code generator** (codegen.zig):
|
|
||||||
```zig
|
|
||||||
fn writeUnion(self: *CodeGen, union_decl: patterns.UnionDecl) !void {
|
|
||||||
const zig_name = naming.typeNameToZig(union_decl.name);
|
|
||||||
|
|
||||||
if (union_decl.doc_comment) |doc| {
|
|
||||||
try self.writeDocComment(doc);
|
|
||||||
}
|
|
||||||
|
|
||||||
try self.output.writer(self.allocator).print(
|
|
||||||
"pub const {s} = extern union {{\n",
|
|
||||||
.{zig_name}
|
|
||||||
);
|
|
||||||
|
|
||||||
for (union_decl.fields) |field| {
|
|
||||||
const zig_type = try types.convertType(field.type_name, self.allocator);
|
|
||||||
defer self.allocator.free(zig_type);
|
|
||||||
|
|
||||||
try self.output.writer(self.allocator).print(
|
|
||||||
" {s}: {s},\n",
|
|
||||||
.{field.name, zig_type}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
try self.output.appendSlice(self.allocator, "};\n\n");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
7. **Update writeDeclarations** (codegen.zig):
|
|
||||||
```zig
|
|
||||||
switch (decl) {
|
|
||||||
// ... existing cases
|
|
||||||
.union_decl => |union_decl| try self.writeUnion(union_decl),
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
8. **Add tests**:
|
|
||||||
```zig
|
|
||||||
test "parse union" {
|
|
||||||
const source =
|
|
||||||
\\typedef union SDL_Color {
|
|
||||||
\\ Uint32 rgba;
|
|
||||||
\\ struct { Uint8 r, g, b, a; };
|
|
||||||
\\} SDL_Color;
|
|
||||||
;
|
|
||||||
|
|
||||||
var scanner = patterns.Scanner.init(allocator, source);
|
|
||||||
const decls = try scanner.scan();
|
|
||||||
// ... test expectations
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing Guidelines
|
|
||||||
|
|
||||||
### Unit Tests
|
|
||||||
|
|
||||||
Place tests in `test/` or at bottom of source files:
|
|
||||||
|
|
||||||
```zig
|
|
||||||
test "descriptive test name" {
|
|
||||||
const allocator = std.testing.allocator;
|
|
||||||
|
|
||||||
// Setup
|
|
||||||
const source = "...";
|
|
||||||
var scanner = patterns.Scanner.init(allocator, source);
|
|
||||||
|
|
||||||
// Execute
|
|
||||||
const result = try scanner.scan();
|
|
||||||
defer allocator.free(result);
|
|
||||||
|
|
||||||
// Assert
|
|
||||||
try std.testing.expectEqual(expected, actual);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Integration Tests
|
|
||||||
|
|
||||||
Test with real SDL headers:
|
|
||||||
```bash
|
|
||||||
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=test.zig
|
|
||||||
zig ast-check test.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
### Memory Testing
|
|
||||||
|
|
||||||
Always run tests with GPA to detect leaks:
|
|
||||||
```zig
|
|
||||||
test "my test" {
|
|
||||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
|
||||||
defer _ = gpa.deinit();
|
|
||||||
const allocator = gpa.allocator();
|
|
||||||
|
|
||||||
// Test code using allocator
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Code Style
|
|
||||||
|
|
||||||
### Naming
|
|
||||||
|
|
||||||
- **Functions**: camelCase (`parseStructField`)
|
|
||||||
- **Types**: PascalCase (`FieldDecl`)
|
|
||||||
- **Constants**: PascalCase (`Declaration`)
|
|
||||||
- **Variables**: camelCase (`decl_name`)
|
|
||||||
|
|
||||||
### Comments
|
|
||||||
|
|
||||||
Only comment code that needs clarification:
|
|
||||||
```zig
|
|
||||||
// Good: Explains WHY
|
|
||||||
// Must check flags before typedefs - pattern order matters
|
|
||||||
if (try self.scanFlagTypedef()) |flag_decl| { ... }
|
|
||||||
|
|
||||||
// Bad: Explains WHAT (obvious from code)
|
|
||||||
// Append to list
|
|
||||||
try list.append(allocator, item);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Error Handling
|
|
||||||
|
|
||||||
Use graceful degradation:
|
|
||||||
```zig
|
|
||||||
// Good: Continue on error
|
|
||||||
const decl = extractType(source, name) catch |err| {
|
|
||||||
std.debug.print("Warning: {}\n", .{err});
|
|
||||||
continue;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Bad: Fail immediately (unless truly fatal)
|
|
||||||
const decl = try extractType(source, name);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Memory Management Rules
|
|
||||||
|
|
||||||
### Ownership
|
|
||||||
|
|
||||||
1. **Scanner owns strings** during parsing
|
|
||||||
2. **Caller owns result** of scan()
|
|
||||||
3. **HashMap owns keys** when they're duped
|
|
||||||
4. **Cloned declarations own strings** after cloning
|
|
||||||
|
|
||||||
### Cleanup Pattern
|
|
||||||
|
|
||||||
Always use defer for cleanup:
|
|
||||||
```zig
|
|
||||||
const decls = try scanner.scan();
|
|
||||||
defer {
|
|
||||||
for (decls) |decl| {
|
|
||||||
freeDeclDeep(allocator, decl);
|
|
||||||
}
|
|
||||||
allocator.free(decls);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### HashMap Keys
|
|
||||||
|
|
||||||
Must be owned (not slices into temporary data):
|
|
||||||
```zig
|
|
||||||
// Wrong:
|
|
||||||
try map.put(type_str, {}); // type_str might be freed!
|
|
||||||
|
|
||||||
// Right:
|
|
||||||
if (!map.contains(type_str)) {
|
|
||||||
const owned = try allocator.dupe(u8, type_str);
|
|
||||||
try map.put(owned, {});
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Patterns
|
|
||||||
|
|
||||||
### Pattern Matching
|
|
||||||
|
|
||||||
```zig
|
|
||||||
fn scanSomething(self: *Scanner) !?SomeDecl {
|
|
||||||
const start = self.pos;
|
|
||||||
const line = try self.readLine();
|
|
||||||
defer self.allocator.free(line);
|
|
||||||
|
|
||||||
// Check pattern
|
|
||||||
if (!std.mem.startsWith(u8, line, "expected_start")) {
|
|
||||||
self.pos = start; // Reset position
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse and return
|
|
||||||
return SomeDecl{ ... };
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### String Building
|
|
||||||
|
|
||||||
```zig
|
|
||||||
var buf = std.ArrayList(u8){};
|
|
||||||
defer buf.deinit(allocator);
|
|
||||||
|
|
||||||
try buf.appendSlice(allocator, "pub const ");
|
|
||||||
try buf.appendSlice(allocator, name);
|
|
||||||
try buf.appendSlice(allocator, " = ");
|
|
||||||
|
|
||||||
return try buf.toOwnedSlice(allocator);
|
|
||||||
```
|
|
||||||
|
|
||||||
### HashMap Usage
|
|
||||||
|
|
||||||
```zig
|
|
||||||
var map = std.StringHashMap(void).init(allocator);
|
|
||||||
defer {
|
|
||||||
var it = map.keyIterator();
|
|
||||||
while (it.next()) |key| {
|
|
||||||
allocator.free(key.*); // Free owned keys
|
|
||||||
}
|
|
||||||
map.deinit();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add items
|
|
||||||
const owned_key = try allocator.dupe(u8, key);
|
|
||||||
try map.put(owned_key, {});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Debugging Tips
|
|
||||||
|
|
||||||
### Print Debugging
|
|
||||||
|
|
||||||
```zig
|
|
||||||
std.debug.print("Debug: value = {s}\n", .{value});
|
|
||||||
std.debug.print("Type: {}\n", .{@TypeOf(variable)});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Memory Leak Detection
|
|
||||||
|
|
||||||
Run with GPA and check output:
|
|
||||||
```bash
|
|
||||||
zig build run -- header.h 2>&1 | grep "memory address"
|
|
||||||
```
|
|
||||||
|
|
||||||
### AST Debugging
|
|
||||||
|
|
||||||
Check what Zig thinks is wrong:
|
|
||||||
```bash
|
|
||||||
zig ast-check generated.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
## Performance Optimization
|
|
||||||
|
|
||||||
### Guidelines
|
|
||||||
|
|
||||||
1. **Avoid allocations in hot paths** - Use stack when possible
|
|
||||||
2. **Reuse buffers** - Clear and reuse instead of allocating new
|
|
||||||
3. **Early exit** - Return as soon as answer is known
|
|
||||||
4. **HashMap for lookups** - O(1) instead of O(n) searches
|
|
||||||
|
|
||||||
### Profiling
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build with profiling
|
|
||||||
zig build -Drelease-safe
|
|
||||||
|
|
||||||
# Run with timing
|
|
||||||
time zig build run -- large_header.h --output=out.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contributing Workflow
|
|
||||||
|
|
||||||
1. **Create branch** from `dev/sdl3-parser`
|
|
||||||
2. **Make changes** in focused commits
|
|
||||||
3. **Run tests** - All must pass
|
|
||||||
4. **Update docs** if behavior changes
|
|
||||||
5. **Commit** with descriptive message
|
|
||||||
6. **Push** and create PR
|
|
||||||
|
|
||||||
### Commit Message Format
|
|
||||||
|
|
||||||
```
|
|
||||||
feat: Add union type support
|
|
||||||
|
|
||||||
Implements parsing and code generation for C union types.
|
|
||||||
|
|
||||||
- Added UnionDecl to Declaration union
|
|
||||||
- Implemented scanUnion() pattern matcher
|
|
||||||
- Added writeUnion() code generator
|
|
||||||
- Created comprehensive test suite (5 tests)
|
|
||||||
|
|
||||||
Results:
|
|
||||||
- Successfully parses SDL union types
|
|
||||||
- Generates proper extern unions
|
|
||||||
- All tests passing
|
|
||||||
|
|
||||||
Closes: #123
|
|
||||||
```
|
|
||||||
|
|
||||||
## Test-Driven Development
|
|
||||||
|
|
||||||
Recommended workflow:
|
|
||||||
|
|
||||||
1. **Write test first**:
|
|
||||||
```zig
|
|
||||||
test "parse union type" {
|
|
||||||
const source = "typedef union { int x; float y; } SDL_Union;";
|
|
||||||
var scanner = patterns.Scanner.init(allocator, source);
|
|
||||||
const decls = try scanner.scan();
|
|
||||||
|
|
||||||
try testing.expectEqual(@as(usize, 1), decls.len);
|
|
||||||
try testing.expect(decls[0] == .union_decl);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Run test** (it will fail)
|
|
||||||
3. **Implement feature** until test passes
|
|
||||||
4. **Add more tests** for edge cases
|
|
||||||
5. **Refactor** if needed
|
|
||||||
|
|
||||||
## Architecture Decisions
|
|
||||||
|
|
||||||
### Why Single-File Output?
|
|
||||||
|
|
||||||
**Alternative**: Generate separate file per type
|
|
||||||
|
|
||||||
**Decision**: Single file with dependencies first
|
|
||||||
|
|
||||||
**Reasons**:
|
|
||||||
- Simpler for users (one import)
|
|
||||||
- Zig's structural typing handles it
|
|
||||||
- Type ordering guaranteed
|
|
||||||
- Less build system complexity
|
|
||||||
|
|
||||||
### Why On-Demand Resolution?
|
|
||||||
|
|
||||||
**Alternative**: Always parse all includes
|
|
||||||
|
|
||||||
**Decision**: Only parse when missing types detected
|
|
||||||
|
|
||||||
**Reasons**:
|
|
||||||
- Better performance
|
|
||||||
- Minimal overhead for self-contained headers
|
|
||||||
- Users see only relevant dependencies
|
|
||||||
|
|
||||||
### Why Conservative Error Handling?
|
|
||||||
|
|
||||||
**Alternative**: Fail on any error
|
|
||||||
|
|
||||||
**Decision**: Warn and continue
|
|
||||||
|
|
||||||
**Reasons**:
|
|
||||||
- Partial success is better than no success
|
|
||||||
- Users can manually fix issues
|
|
||||||
- Allows incremental improvement
|
|
||||||
|
|
||||||
## Extending the Parser
|
|
||||||
|
|
||||||
### Adding Type Conversions
|
|
||||||
|
|
||||||
Edit `src/types.zig`:
|
|
||||||
```zig
|
|
||||||
pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 {
|
|
||||||
// Check for your pattern first
|
|
||||||
if (std.mem.eql(u8, c_type, "MyCustomType")) {
|
|
||||||
return try allocator.dupe(u8, "MyZigType");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fall through to existing logic
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding Naming Rules
|
|
||||||
|
|
||||||
Edit `src/naming.zig`:
|
|
||||||
```zig
|
|
||||||
pub fn typeNameToZig(c_name: []const u8) []const u8 {
|
|
||||||
// Handle special cases
|
|
||||||
if (std.mem.eql(u8, c_name, "SDL_bool")) {
|
|
||||||
return "Bool"; // Custom mapping
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default logic
|
|
||||||
return stripSDLPrefix(c_name);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding Pattern Matchers
|
|
||||||
|
|
||||||
1. Implement `scan*()` function in `patterns.zig`
|
|
||||||
2. Add to scan chain with proper ordering
|
|
||||||
3. Update all switch statements
|
|
||||||
4. Add code generator
|
|
||||||
5. Write tests
|
|
||||||
|
|
||||||
See "Adding New Pattern Support" section above for full example.
|
|
||||||
|
|
||||||
## Common Issues When Developing
|
|
||||||
|
|
||||||
### Issue: ArrayList API Changed
|
|
||||||
|
|
||||||
**Error**: `error: no field named 'init' in struct 'ArrayList'`
|
|
||||||
|
|
||||||
**Solution**: Use Zig 0.15 API (see above)
|
|
||||||
|
|
||||||
### Issue: HashMap Key Lifetime
|
|
||||||
|
|
||||||
**Error**: Memory corruption or use-after-free
|
|
||||||
|
|
||||||
**Solution**: Always dupe keys before inserting:
|
|
||||||
```zig
|
|
||||||
const owned = try allocator.dupe(u8, key);
|
|
||||||
try map.put(owned, {});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Issue: Pattern Matching Order
|
|
||||||
|
|
||||||
**Error**: Wrong scanner function matches
|
|
||||||
|
|
||||||
**Solution**: Order matters! More specific patterns first:
|
|
||||||
```zig
|
|
||||||
// Correct order:
|
|
||||||
if (try self.scanFlagTypedef()) { ... } // Specific
|
|
||||||
else if (try self.scanTypedef()) { ... } // General
|
|
||||||
|
|
||||||
// Wrong order:
|
|
||||||
if (try self.scanTypedef()) { ... } // Too general - catches flags!
|
|
||||||
else if (try self.scanFlagTypedef()) { ... } // Never reached
|
|
||||||
```
|
|
||||||
|
|
||||||
## Performance Considerations
|
|
||||||
|
|
||||||
### Current Performance
|
|
||||||
|
|
||||||
- Small headers: ~100ms
|
|
||||||
- Large headers (SDL_gpu.h): ~520ms
|
|
||||||
- Memory: ~2-5MB peak
|
|
||||||
|
|
||||||
### Bottlenecks
|
|
||||||
|
|
||||||
1. **Dependency extraction**: 300ms (58% of time)
|
|
||||||
- Parsing multiple headers
|
|
||||||
- Could cache parsed headers
|
|
||||||
|
|
||||||
2. **String allocations**: Many small allocations
|
|
||||||
- Could use arena allocator
|
|
||||||
- String interning would help
|
|
||||||
|
|
||||||
### Optimization Ideas
|
|
||||||
|
|
||||||
```zig
|
|
||||||
// Cache parsed headers
|
|
||||||
var header_cache = std.StringHashMap([]Declaration).init(allocator);
|
|
||||||
|
|
||||||
// Use arena for temporary allocations
|
|
||||||
var arena = std.heap.ArenaAllocator.init(allocator);
|
|
||||||
defer arena.deinit();
|
|
||||||
const temp_alloc = arena.allocator();
|
|
||||||
```
|
|
||||||
|
|
||||||
## Resources
|
|
||||||
|
|
||||||
### Zig Documentation
|
|
||||||
- [Zig Language Reference](https://ziglang.org/documentation/master/)
|
|
||||||
- [Zig Standard Library](https://ziglang.org/documentation/master/std/)
|
|
||||||
|
|
||||||
### SDL Documentation
|
|
||||||
- [SDL3 API](https://wiki.libsdl.org/SDL3/)
|
|
||||||
- [SDL3 Headers](https://github.com/libsdl-org/SDL)
|
|
||||||
|
|
||||||
### Project Documentation
|
|
||||||
- [Architecture](ARCHITECTURE.md) - How the parser works
|
|
||||||
- [Dependency Flow](DEPENDENCY_FLOW.md) - Detailed flow
|
|
||||||
- [Visual Flow](VISUAL_FLOW.md) - Diagrams
|
|
||||||
|
|
||||||
## Getting Help
|
|
||||||
|
|
||||||
- Check existing tests for examples
|
|
||||||
- Read [Architecture](ARCHITECTURE.md) for design
|
|
||||||
- See [Dependency Flow](DEPENDENCY_FLOW.md) for details
|
|
||||||
- Review git history for patterns
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Ready to contribute?** Start with the tests, understand the existing patterns, then extend!
|
|
||||||
|
|
@ -1,278 +0,0 @@
|
||||||
# Getting Started with SDL3 Parser
|
|
||||||
|
|
||||||
This guide will help you get up and running with the SDL3 header parser.
|
|
||||||
|
|
||||||
## Prerequisites
|
|
||||||
|
|
||||||
- Zig 0.15 or later
|
|
||||||
- SDL3 headers (included in `../SDL/include/SDL3/`)
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
1. Navigate to the parser directory:
|
|
||||||
```bash
|
|
||||||
cd lib/sdl3/parser
|
|
||||||
```
|
|
||||||
|
|
||||||
2. Build the parser:
|
|
||||||
```bash
|
|
||||||
zig build
|
|
||||||
```
|
|
||||||
|
|
||||||
3. Run tests to verify installation:
|
|
||||||
```bash
|
|
||||||
zig build test
|
|
||||||
```
|
|
||||||
|
|
||||||
You should see: `All tests passed.`
|
|
||||||
|
|
||||||
## Your First Parse
|
|
||||||
|
|
||||||
### Step 1: Parse SDL_gpu.h
|
|
||||||
|
|
||||||
```bash
|
|
||||||
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=my_gpu.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
You'll see output like:
|
|
||||||
```
|
|
||||||
SDL3 Header Parser
|
|
||||||
==================
|
|
||||||
|
|
||||||
Parsing: ../SDL/include/SDL3/SDL_gpu.h
|
|
||||||
|
|
||||||
Found 169 declarations
|
|
||||||
- Opaque types: 13
|
|
||||||
- Typedefs: 6
|
|
||||||
- Enums: 24
|
|
||||||
- Structs: 35
|
|
||||||
- Flags: 3
|
|
||||||
- Functions: 94
|
|
||||||
|
|
||||||
Analyzing dependencies...
|
|
||||||
Found 5 missing types:
|
|
||||||
- SDL_FColor
|
|
||||||
- SDL_PropertiesID
|
|
||||||
- SDL_Rect
|
|
||||||
- SDL_Window
|
|
||||||
- SDL_FlipMode
|
|
||||||
|
|
||||||
Resolving dependencies from included headers...
|
|
||||||
✓ Found SDL_FColor in SDL_pixels.h
|
|
||||||
✓ Found SDL_PropertiesID in SDL_properties.h
|
|
||||||
✓ Found SDL_Rect in SDL_rect.h
|
|
||||||
✓ Found SDL_Window in SDL_video.h
|
|
||||||
✓ Found SDL_FlipMode in SDL_surface.h
|
|
||||||
|
|
||||||
Combining 5 dependency declarations with primary declarations...
|
|
||||||
Generated: my_gpu.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Examine the Output
|
|
||||||
|
|
||||||
```bash
|
|
||||||
head -50 my_gpu.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
You'll see clean Zig bindings:
|
|
||||||
```zig
|
|
||||||
pub const c = @import("c.zig").c;
|
|
||||||
|
|
||||||
// Dependencies (automatically included)
|
|
||||||
pub const FColor = extern struct {
|
|
||||||
r: f32,
|
|
||||||
g: f32,
|
|
||||||
b: f32,
|
|
||||||
a: f32,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const PropertiesID = u32;
|
|
||||||
|
|
||||||
pub const Rect = extern struct {
|
|
||||||
x: c_int,
|
|
||||||
y: c_int,
|
|
||||||
w: c_int,
|
|
||||||
h: c_int,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const Window = opaque {};
|
|
||||||
|
|
||||||
// Primary declarations
|
|
||||||
pub const GPUDevice = opaque {
|
|
||||||
pub inline fn destroyGPUDevice(gpudevice: *GPUDevice) void {
|
|
||||||
return c.SDL_DestroyGPUDevice(gpudevice);
|
|
||||||
}
|
|
||||||
// ... 93 more methods
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Create c.zig Wrapper
|
|
||||||
|
|
||||||
Create a file `c.zig` that imports SDL:
|
|
||||||
```zig
|
|
||||||
pub const c = @cImport({
|
|
||||||
@cInclude("SDL3/SDL.h");
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: Use in Your Project
|
|
||||||
|
|
||||||
```zig
|
|
||||||
const std = @import("std");
|
|
||||||
const gpu = @import("my_gpu.zig");
|
|
||||||
|
|
||||||
pub fn main() !void {
|
|
||||||
const device = gpu.createGPUDevice(true);
|
|
||||||
if (device) |d| {
|
|
||||||
defer d.destroyGPUDevice();
|
|
||||||
|
|
||||||
const driver = d.getGPUDeviceDriver();
|
|
||||||
std.debug.print("GPU Driver: {s}\n", .{driver});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Command-Line Options
|
|
||||||
|
|
||||||
### Basic Options
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Output to file
|
|
||||||
zig build run -- header.h --output=output.zig
|
|
||||||
|
|
||||||
# Output to stdout
|
|
||||||
zig build run -- header.h
|
|
||||||
```
|
|
||||||
|
|
||||||
### Mock Generation
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Generate C mocks for testing
|
|
||||||
zig build run -- header.h --output=bindings.zig --mocks=mocks.c
|
|
||||||
```
|
|
||||||
|
|
||||||
The mock file contains stub implementations that return zero/null:
|
|
||||||
```c
|
|
||||||
void SDL_DestroyGPUDevice(SDL_GPUDevice *device) {
|
|
||||||
// Mock implementation
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Understanding the Output
|
|
||||||
|
|
||||||
### Type Name Conversion
|
|
||||||
|
|
||||||
The parser follows consistent naming rules:
|
|
||||||
|
|
||||||
| C Name | Zig Name | Rule |
|
|
||||||
|--------|----------|------|
|
|
||||||
| `SDL_GPUDevice` | `GPUDevice` | Strip `SDL_` prefix |
|
|
||||||
| `SDL_GPU_PRIMITIVE_TYPE_TRIANGLELIST` | `primitiveTypeTrianglelist` | Strip prefix, camelCase |
|
|
||||||
| `SDL_CreateGPUDevice` | `createGPUDevice` | Strip `SDL_`, camelCase |
|
|
||||||
|
|
||||||
### Method Grouping
|
|
||||||
|
|
||||||
Functions are organized as methods when possible:
|
|
||||||
|
|
||||||
**C API**:
|
|
||||||
```c
|
|
||||||
void SDL_DestroyGPUDevice(SDL_GPUDevice *device);
|
|
||||||
const char* SDL_GetGPUDeviceDriver(SDL_GPUDevice *device);
|
|
||||||
```
|
|
||||||
|
|
||||||
**Generated Zig**:
|
|
||||||
```zig
|
|
||||||
pub const GPUDevice = opaque {
|
|
||||||
pub inline fn destroyGPUDevice(self: *GPUDevice) void { ... }
|
|
||||||
pub inline fn getGPUDeviceDriver(self: *GPUDevice) [*c]const u8 { ... }
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
Usage becomes:
|
|
||||||
```zig
|
|
||||||
device.destroyGPUDevice(); // Instead of SDL_DestroyGPUDevice(device)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Dependency Inclusion
|
|
||||||
|
|
||||||
Dependencies are automatically detected and included at the top of the file:
|
|
||||||
|
|
||||||
```zig
|
|
||||||
// Dependencies from included headers
|
|
||||||
pub const FColor = extern struct { ... };
|
|
||||||
pub const Rect = extern struct { ... };
|
|
||||||
pub const Window = opaque {};
|
|
||||||
|
|
||||||
// Primary declarations from SDL_gpu.h
|
|
||||||
pub const GPUDevice = opaque { ... };
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Workflows
|
|
||||||
|
|
||||||
### Generate Bindings for a Module
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# From lib/sdl3 directory
|
|
||||||
zig build regenerate-zig
|
|
||||||
```
|
|
||||||
|
|
||||||
This generates bindings for configured headers in `v2/` directory.
|
|
||||||
|
|
||||||
### Test Your Changes
|
|
||||||
|
|
||||||
After modifying the parser:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run unit tests
|
|
||||||
zig build test
|
|
||||||
|
|
||||||
# Test with a real header
|
|
||||||
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=test.zig
|
|
||||||
|
|
||||||
# Verify output compiles
|
|
||||||
zig ast-check test.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
### Debug Issues
|
|
||||||
|
|
||||||
If you encounter errors:
|
|
||||||
|
|
||||||
1. Check the console output for warnings about missing types
|
|
||||||
2. Look at the generated file for syntax errors
|
|
||||||
3. See [Known Issues](docs/KNOWN_ISSUES.md) for common problems
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
- Read [Architecture](docs/ARCHITECTURE.md) to understand how it works
|
|
||||||
- See [Dependency Resolution](docs/DEPENDENCY_RESOLUTION.md) for details on automatic type extraction
|
|
||||||
- Check [Known Issues](docs/KNOWN_ISSUES.md) for current limitations
|
|
||||||
- Review [Development](docs/DEVELOPMENT.md) to contribute
|
|
||||||
|
|
||||||
## Quick Reference
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Build
|
|
||||||
zig build
|
|
||||||
|
|
||||||
# Test
|
|
||||||
zig build test
|
|
||||||
|
|
||||||
# Generate bindings
|
|
||||||
zig build run -- <header> --output=<output>
|
|
||||||
|
|
||||||
# Generate with mocks
|
|
||||||
zig build run -- <header> --output=<output> --mocks=<mocks>
|
|
||||||
|
|
||||||
# Generate all configured headers
|
|
||||||
cd .. && zig build regenerate-zig
|
|
||||||
```
|
|
||||||
|
|
||||||
## Getting Help
|
|
||||||
|
|
||||||
- **Documentation**: See `docs/` directory
|
|
||||||
- **Examples**: Check `test/` directory for usage examples
|
|
||||||
- **Issues**: See `docs/KNOWN_ISSUES.md`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Next**: Read [Architecture](docs/ARCHITECTURE.md) to understand the parser internals.
|
|
||||||
112
docs/INDEX.md
112
docs/INDEX.md
|
|
@ -1,112 +0,0 @@
|
||||||
# SDL3 Parser Documentation
|
|
||||||
|
|
||||||
Complete documentation for the SDL3 C header to Zig bindings generator.
|
|
||||||
|
|
||||||
## Quick Links
|
|
||||||
|
|
||||||
- **[README](../README.md)** - Start here for project overview
|
|
||||||
- **[Getting Started](GETTING_STARTED.md)** - Installation and first use
|
|
||||||
- **[API Reference](API_REFERENCE.md)** - Command-line options
|
|
||||||
|
|
||||||
## User Guides
|
|
||||||
|
|
||||||
### Essential
|
|
||||||
|
|
||||||
1. **[Getting Started](GETTING_STARTED.md)** - Installation, first parse, basic usage
|
|
||||||
2. **[Quickstart Guide](QUICKSTART.md)** - Quick reference for common tasks
|
|
||||||
3. **[API Reference](API_REFERENCE.md)** - Complete command-line reference
|
|
||||||
|
|
||||||
### Features
|
|
||||||
|
|
||||||
4. **[Dependency Resolution](DEPENDENCY_RESOLUTION.md)** - How automatic type extraction works
|
|
||||||
5. **[Known Issues](KNOWN_ISSUES.md)** - Current limitations and workarounds
|
|
||||||
|
|
||||||
## Technical Documentation
|
|
||||||
|
|
||||||
### Architecture
|
|
||||||
|
|
||||||
6. **[Architecture Overview](ARCHITECTURE.md)** - System design and components
|
|
||||||
7. **[Dependency Flow](DEPENDENCY_FLOW.md)** - Complete technical walkthrough (845 lines)
|
|
||||||
8. **[Visual Flow Diagrams](VISUAL_FLOW.md)** - Quick reference diagrams
|
|
||||||
|
|
||||||
### Implementation Details
|
|
||||||
|
|
||||||
9. **[Multi-Field Structs](MULTI_FIELD_IMPLEMENTATION.md)** - How `int x, y;` parsing works
|
|
||||||
10. **[Typedef Support](TYPEDEF_IMPLEMENTATION.md)** - Simple typedef implementation
|
|
||||||
11. **[Multi-Header Testing](MULTI_HEADER_TEST_RESULTS.md)** - Test results across SDL headers
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
12. **[Development Guide](DEVELOPMENT.md)** - Contributing, extending, Zig 0.15 guidelines
|
|
||||||
13. **[Roadmap](ROADMAP.md)** - Future plans and priorities
|
|
||||||
|
|
||||||
## Quick Start
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Install
|
|
||||||
cd parser/
|
|
||||||
zig build
|
|
||||||
zig build test
|
|
||||||
|
|
||||||
# Generate bindings
|
|
||||||
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig
|
|
||||||
|
|
||||||
# Use in code
|
|
||||||
const gpu = @import("gpu.zig");
|
|
||||||
```
|
|
||||||
|
|
||||||
## Documentation by Use Case
|
|
||||||
|
|
||||||
### "I want to generate Zig bindings"
|
|
||||||
→ Start with [Getting Started](GETTING_STARTED.md)
|
|
||||||
|
|
||||||
### "I want to understand how it works"
|
|
||||||
→ Read [Architecture](ARCHITECTURE.md)
|
|
||||||
|
|
||||||
### "I'm hitting an error"
|
|
||||||
→ Check [Known Issues](KNOWN_ISSUES.md)
|
|
||||||
|
|
||||||
### "I want to extend the parser"
|
|
||||||
→ See [Development Guide](DEVELOPMENT.md)
|
|
||||||
|
|
||||||
### "I need technical details"
|
|
||||||
→ Deep dive: [Dependency Flow](DEPENDENCY_FLOW.md)
|
|
||||||
|
|
||||||
## Project Status
|
|
||||||
|
|
||||||
**Version**: 2.1
|
|
||||||
**Status**: Production ready for SDL_gpu.h
|
|
||||||
**Last Updated**: 2026-01-22
|
|
||||||
|
|
||||||
### Supported Headers
|
|
||||||
|
|
||||||
| Header | Status | Notes |
|
|
||||||
|--------|--------|-------|
|
|
||||||
| SDL_gpu.h | ✅ Complete | 100% dependency resolution |
|
|
||||||
| SDL_keyboard.h | ⚠️ Partial | Large enum issues |
|
|
||||||
| SDL_video.h | ⚠️ Partial | Some types not found |
|
|
||||||
| SDL_events.h | ⚠️ Partial | Parse errors |
|
|
||||||
|
|
||||||
See [Known Issues](KNOWN_ISSUES.md) for details.
|
|
||||||
|
|
||||||
## Key Features
|
|
||||||
|
|
||||||
✅ Automatic dependency resolution (100% for SDL_gpu.h)
|
|
||||||
✅ Multi-field struct parsing (`int x, y;`)
|
|
||||||
✅ Typedef support (`typedef Uint32 SDL_Type;`)
|
|
||||||
✅ Method organization (functions → methods)
|
|
||||||
✅ Mock generation for testing
|
|
||||||
✅ Comprehensive error reporting
|
|
||||||
|
|
||||||
## Statistics
|
|
||||||
|
|
||||||
- **Code**: ~900 lines (production)
|
|
||||||
- **Tests**: 26+ unit tests (100% passing)
|
|
||||||
- **Documentation**: 5,500+ lines
|
|
||||||
- **Success Rate**: 100% for SDL_gpu.h
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Archive
|
|
||||||
|
|
||||||
Historical planning and session documents are in `archive/` for reference.
|
|
||||||
|
|
@ -1,299 +0,0 @@
|
||||||
# Known Issues and Limitations
|
|
||||||
|
|
||||||
This document lists current limitations and remaining issues in the SDL3 header parser.
|
|
||||||
|
|
||||||
## Current Status
|
|
||||||
|
|
||||||
**45+ SDL3 headers** successfully generated with automatic dependency resolution and JSON export.
|
|
||||||
|
|
||||||
### Successfully Generated APIs
|
|
||||||
|
|
||||||
All major SDL3 APIs parse and generate correctly, including:
|
|
||||||
- Core: audio, camera, clipboard, dialog, events, filesystem, gamepad, gpu, haptic, hints, init, joystick, keyboard, log, mouse, pen, power, properties, rect, render, sensor, storage, surface, time, timer, touch, video
|
|
||||||
- Platform: iostream, loadso, locale, messagebox, misc, process, stdinc, system, vulkan
|
|
||||||
- Specialized: blendmode, error, guid, metal, pixels, scancode
|
|
||||||
|
|
||||||
### Intentionally Skipped
|
|
||||||
|
|
||||||
- **assert**: Macro-only header (no types to parse)
|
|
||||||
- **mutex**: Low-level unsafe primitives (use std.Thread.Mutex instead)
|
|
||||||
- **thread**: Complex concurrency primitives (use std.Thread instead)
|
|
||||||
- **hidapi**: Low-level USB/HID interface (specialized use)
|
|
||||||
- **tray**: Platform-specific system tray (incomplete API)
|
|
||||||
|
|
||||||
## Known Limitations
|
|
||||||
|
|
||||||
### 1. Field Names That Shadow Zig Keywords
|
|
||||||
|
|
||||||
**Issue**: Fields named `type`, `error`, `async`, etc. cause compilation errors
|
|
||||||
|
|
||||||
**Status**: ✅ **FIXED** - Automatic escaping implemented
|
|
||||||
|
|
||||||
**Example**:
|
|
||||||
```c
|
|
||||||
typedef struct {
|
|
||||||
int type; // Automatically escaped now
|
|
||||||
} SDL_Something;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Generated**:
|
|
||||||
```zig
|
|
||||||
pub const Something = extern struct {
|
|
||||||
@"type": c_int, // Auto-escaped!
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Keywords Handled**: type, error, async, await, suspend, resume, try, catch, if, else, for, while, switch, return, break, continue, defer, unreachable, noreturn, comptime, inline, export, extern, packed, const, var, fn, pub, test, struct, enum, union, opaque
|
|
||||||
|
|
||||||
### 2. Function Pointer Typedefs
|
|
||||||
|
|
||||||
**Issue**: Function pointer types generate as opaque types instead of function pointers
|
|
||||||
|
|
||||||
**Status**: ✅ **FIXED** - Proper function pointer typedef support implemented
|
|
||||||
|
|
||||||
**Example**:
|
|
||||||
```c
|
|
||||||
typedef void (*SDL_HitTest)(SDL_Window *window, const SDL_Point *pt, void *data);
|
|
||||||
```
|
|
||||||
|
|
||||||
**Generated**:
|
|
||||||
```zig
|
|
||||||
pub const HitTest = *const fn (?*Window, *const Point, ?*anyopaque) callconv(.C) void;
|
|
||||||
```
|
|
||||||
|
|
||||||
**Support**: Full function pointer parsing with parameters, return types, and proper Zig calling convention
|
|
||||||
|
|
||||||
### 3. SDL_UINT64_C Macro in Bit Positions
|
|
||||||
|
|
||||||
**Issue**: Some 64-bit flag patterns may not parse correctly
|
|
||||||
|
|
||||||
**Example**:
|
|
||||||
```c
|
|
||||||
#define SDL_WINDOW_FULLSCREEN SDL_UINT64_C(0x0000000000000001)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Status**: Enhanced support added, but not fully tested
|
|
||||||
|
|
||||||
**Workaround**: Manual flag definitions if needed
|
|
||||||
|
|
||||||
**Priority**: Medium
|
|
||||||
**Effort**: ~30 minutes validation
|
|
||||||
**Affected**: SDL_video.h WindowFlags
|
|
||||||
|
|
||||||
### 4. External Library Types
|
|
||||||
|
|
||||||
**Issue**: Types from external libraries (EGL, OpenGL) not found
|
|
||||||
|
|
||||||
**Example**:
|
|
||||||
```c
|
|
||||||
SDL_EGLConfig
|
|
||||||
SDL_EGLDisplay
|
|
||||||
SDL_GLContext
|
|
||||||
```
|
|
||||||
|
|
||||||
**Status**: Expected behavior (not SDL types)
|
|
||||||
|
|
||||||
**Workaround**: Use C imports or manual definitions
|
|
||||||
|
|
||||||
**Priority**: N/A (expected)
|
|
||||||
|
|
||||||
### 5. Memory Leaks in Comment Handling
|
|
||||||
|
|
||||||
**Issue**: Small memory leaks in struct comment parsing
|
|
||||||
|
|
||||||
**Status**: ✅ **FIXED** - Proper memory cleanup implemented
|
|
||||||
|
|
||||||
**Impact**: None - all allocations properly freed
|
|
||||||
|
|
||||||
### 6. Array Field Declarations
|
|
||||||
|
|
||||||
**Issue**: Array fields in multi-field syntax not supported
|
|
||||||
|
|
||||||
**Example**:
|
|
||||||
```c
|
|
||||||
int array1[10], array2[20]; // Not handled
|
|
||||||
```
|
|
||||||
|
|
||||||
**Workaround**: Rare in SDL, can be manually defined
|
|
||||||
|
|
||||||
**Priority**: Low
|
|
||||||
**Effort**: ~1 hour
|
|
||||||
|
|
||||||
### 7. Bit Field Declarations
|
|
||||||
|
|
||||||
**Issue**: Bit fields not supported
|
|
||||||
|
|
||||||
**Example**:
|
|
||||||
```c
|
|
||||||
struct {
|
|
||||||
unsigned a : 4;
|
|
||||||
unsigned b : 4;
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
**Status**: Not used in SDL public API
|
|
||||||
|
|
||||||
**Priority**: Very Low
|
|
||||||
|
|
||||||
## Workaround Strategies
|
|
||||||
|
|
||||||
### Strategy 1: Manual Type Definitions
|
|
||||||
|
|
||||||
Create a supplementary file with missing types:
|
|
||||||
```zig
|
|
||||||
// manual_types.zig
|
|
||||||
pub const HitTest = *const fn(?*Window, *const Point, ?*anyopaque) callconv(.C) void;
|
|
||||||
pub const Scancode = c_int; // Simplified if full enum not needed
|
|
||||||
```
|
|
||||||
|
|
||||||
### Strategy 2: Direct C Import
|
|
||||||
|
|
||||||
For problematic types, use C directly:
|
|
||||||
```zig
|
|
||||||
const c = @cImport(@cInclude("SDL3/SDL.h"));
|
|
||||||
pub const Scancode = c.SDL_Scancode;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Strategy 3: Selective Generation
|
|
||||||
|
|
||||||
Only generate for headers that work:
|
|
||||||
```bash
|
|
||||||
# These work well:
|
|
||||||
zig build run -- SDL_gpu.h --output=gpu.zig
|
|
||||||
zig build run -- SDL_properties.h --output=properties.zig
|
|
||||||
|
|
||||||
# These need work:
|
|
||||||
# SDL_keyboard.h, SDL_events.h (use C import for now)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing Results
|
|
||||||
|
|
||||||
### ✅ Successfully Generated (45+ headers)
|
|
||||||
|
|
||||||
All major SDL3 APIs successfully parse and generate working Zig bindings:
|
|
||||||
|
|
||||||
**Core**: audio, camera, clipboard, dialog, events, filesystem, gamepad, gpu, haptic, hints, init, joystick, keyboard, log, mouse, pen, power, properties, rect, render, sensor, storage, surface, time, timer, touch, video
|
|
||||||
|
|
||||||
**Platform**: iostream, loadso, locale, messagebox, misc, process, stdinc, system, vulkan
|
|
||||||
|
|
||||||
**Specialized**: blendmode, error, guid, metal, pixels, scancode
|
|
||||||
|
|
||||||
**Coverage**: ~95% of SDL3 public API
|
|
||||||
|
|
||||||
## Error Messages Explained
|
|
||||||
|
|
||||||
### "Could not find definition for type: X"
|
|
||||||
|
|
||||||
**Meaning**: Type referenced but not found in any included header
|
|
||||||
|
|
||||||
**Possible Causes**:
|
|
||||||
1. Type is a function pointer (not supported)
|
|
||||||
2. Type is external (EGL, GL) (expected)
|
|
||||||
3. Type is in a header not included
|
|
||||||
4. Type uses unsupported pattern
|
|
||||||
|
|
||||||
**Action**: Check if type is needed, add manually if so
|
|
||||||
|
|
||||||
### "Syntax errors detected in generated code"
|
|
||||||
|
|
||||||
**Meaning**: Generated Zig code doesn't parse
|
|
||||||
|
|
||||||
**Possible Causes**:
|
|
||||||
1. Large enum parsing issue
|
|
||||||
2. Field name shadows keyword
|
|
||||||
3. Unsupported C pattern
|
|
||||||
|
|
||||||
**Action**: Check line numbers in error, see if manual fix needed
|
|
||||||
|
|
||||||
### "InvalidBitPosition"
|
|
||||||
|
|
||||||
**Meaning**: Flag value pattern not recognized
|
|
||||||
|
|
||||||
**Possible Causes**:
|
|
||||||
1. Uses SDL_UINT64_C macro (partially supported)
|
|
||||||
2. Complex bit expression
|
|
||||||
3. Non-standard format
|
|
||||||
|
|
||||||
**Action**: May need to manually define flags
|
|
||||||
|
|
||||||
### Memory Leak Warnings
|
|
||||||
|
|
||||||
**Meaning**: Small allocations not freed
|
|
||||||
|
|
||||||
**Impact**: Minimal (1-2KB per run)
|
|
||||||
|
|
||||||
**Status**: Known issue in comment handling, functional
|
|
||||||
|
|
||||||
**Action**: None required (will be fixed in future)
|
|
||||||
|
|
||||||
## Supported vs Unsupported
|
|
||||||
|
|
||||||
### ✅ Fully Supported
|
|
||||||
|
|
||||||
- Opaque types
|
|
||||||
- Simple structs
|
|
||||||
- Multi-field structs (`int x, y;`)
|
|
||||||
- Enums (up to ~100 values)
|
|
||||||
- Flags (with standard patterns)
|
|
||||||
- Typedefs (simple type aliases)
|
|
||||||
- Functions (extern declarations)
|
|
||||||
- Dependency resolution
|
|
||||||
- Type conversion
|
|
||||||
- Method grouping
|
|
||||||
|
|
||||||
### ⚠️ Partially Supported
|
|
||||||
|
|
||||||
- Large enums (300+ values) - needs work
|
|
||||||
- SDL_UINT64_C flags - enhanced but not fully tested
|
|
||||||
- Some bit position patterns
|
|
||||||
|
|
||||||
### ❌ Not Supported
|
|
||||||
|
|
||||||
- Function pointer typedefs
|
|
||||||
- #define-based type definitions (without typedef)
|
|
||||||
- Union types
|
|
||||||
- Bit field structs
|
|
||||||
- Complex macro expressions
|
|
||||||
- Non-SDL types
|
|
||||||
|
|
||||||
## Reporting Issues
|
|
||||||
|
|
||||||
When encountering a new issue:
|
|
||||||
|
|
||||||
1. **Check this document** - May already be known
|
|
||||||
2. **Test with simple case** - Isolate the problem
|
|
||||||
3. **Check generated output** - Look at line numbers in errors
|
|
||||||
4. **Document the pattern** - Save example for future reference
|
|
||||||
|
|
||||||
## Future Improvements
|
|
||||||
|
|
||||||
### Possible Enhancements
|
|
||||||
|
|
||||||
1. **Union support** - Rarely used in SDL (low priority)
|
|
||||||
2. **Bit field support** - Not in SDL public API (very low priority)
|
|
||||||
3. **Array field improvements** - Handle complex array patterns (low priority)
|
|
||||||
4. **Better error messages** - More detailed diagnostics (medium priority)
|
|
||||||
|
|
||||||
## Comparison with Manual Approach
|
|
||||||
|
|
||||||
### Manual Binding Creation
|
|
||||||
|
|
||||||
**Time**: ~30 minutes per header
|
|
||||||
**Error Rate**: High (missing fields, wrong types)
|
|
||||||
**Maintenance**: Manual updates needed
|
|
||||||
**Consistency**: Varies by developer
|
|
||||||
|
|
||||||
### Parser Approach
|
|
||||||
|
|
||||||
**Time**: ~0.5 seconds
|
|
||||||
**Error Rate**: Low (for supported patterns)
|
|
||||||
**Maintenance**: Automatic with SDL updates
|
|
||||||
**Consistency**: Perfect (deterministic)
|
|
||||||
|
|
||||||
**Conclusion**: Parser is vastly superior for supported patterns, with clear workarounds for unsupported cases.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Status**: Production ready - 45+ SDL3 headers successfully generated
|
|
||||||
**Recommendation**: Use generated bindings for all supported headers
|
|
||||||
**Next**: See [Development](DEVELOPMENT.md) for extending the parser
|
|
||||||
|
|
@ -1,203 +0,0 @@
|
||||||
# SDL3 Parser - Quick Start Guide
|
|
||||||
|
|
||||||
## What It Does
|
|
||||||
|
|
||||||
Automatically generates Zig bindings from SDL3 C headers with automatic dependency resolution.
|
|
||||||
|
|
||||||
## Installation & Build
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd parser/
|
|
||||||
zig build # Build parser executable
|
|
||||||
zig build test # Run all tests
|
|
||||||
```
|
|
||||||
|
|
||||||
## Basic Usage
|
|
||||||
|
|
||||||
### Parse a Header
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Output to stdout
|
|
||||||
zig build run -- ../SDL/include/SDL3/SDL_gpu.h
|
|
||||||
|
|
||||||
# Output to file
|
|
||||||
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig
|
|
||||||
|
|
||||||
# Generate with C mocks
|
|
||||||
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig --mocks=gpu_mock.c
|
|
||||||
```
|
|
||||||
|
|
||||||
### What It Generates
|
|
||||||
|
|
||||||
**Input** (`SDL_gpu.h` excerpt):
|
|
||||||
```c
|
|
||||||
typedef struct SDL_GPUDevice SDL_GPUDevice;
|
|
||||||
extern SDL_DECLSPEC void SDLCALL SDL_DestroyGPUDevice(SDL_GPUDevice *device);
|
|
||||||
```
|
|
||||||
|
|
||||||
**Output** (`gpu.zig`):
|
|
||||||
```zig
|
|
||||||
pub const GPUDevice = opaque {
|
|
||||||
pub inline fn destroyGPUDevice(gpudevice: *GPUDevice) void {
|
|
||||||
return c.SDL_DestroyGPUDevice(gpudevice);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
```
|
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
### ✅ Supported C Patterns
|
|
||||||
|
|
||||||
- **Opaque types**: `typedef struct SDL_Type SDL_Type;`
|
|
||||||
- **Enums**: `typedef enum { VALUE1, VALUE2 } SDL_Type;`
|
|
||||||
- **Structs**: `typedef struct { int field; } SDL_Type;`
|
|
||||||
- **Flags**: Packed bitfield enums
|
|
||||||
- **Functions**: `extern SDL_DECLSPEC RetType SDLCALL SDL_Func(...);`
|
|
||||||
|
|
||||||
### ✅ Automatic Dependency Resolution
|
|
||||||
|
|
||||||
- Detects types referenced but not defined
|
|
||||||
- Searches included headers for definitions
|
|
||||||
- Automatically includes needed types in output
|
|
||||||
- Handles: `SDL_FColor`, `SDL_Rect`, `SDL_Window`, `SDL_FlipMode`, etc.
|
|
||||||
|
|
||||||
### ✅ Type Conversion
|
|
||||||
|
|
||||||
| C Type | Zig Type |
|
|
||||||
|--------|----------|
|
|
||||||
| `bool` | `bool` |
|
|
||||||
| `Uint32` | `u32` |
|
|
||||||
| `SDL_Type*` | `?*Type` (nullable) |
|
|
||||||
| `const SDL_Type*` | `*const Type` |
|
|
||||||
| `void*` | `?*anyopaque` |
|
|
||||||
| `const char*` | `[*c]const u8` |
|
|
||||||
|
|
||||||
### ✅ Naming Conventions
|
|
||||||
|
|
||||||
- Strip `SDL_` prefix: `SDL_GPUDevice` → `GPUDevice`
|
|
||||||
- Remove first underscore: `SDL_GPU_Type` → `GPUType`
|
|
||||||
- camelCase functions: `SDL_CreateDevice` → `createDevice`
|
|
||||||
|
|
||||||
## Current Limitations
|
|
||||||
|
|
||||||
### ⚠️ Not Yet Supported
|
|
||||||
|
|
||||||
1. **Multi-field structs**: `int x, y;` (parsed as single field)
|
|
||||||
- **Workaround**: Manually expand or wait for next version
|
|
||||||
|
|
||||||
2. **Simple typedefs**: `typedef Uint32 SDL_Type;`
|
|
||||||
- **Workaround**: Add manually to output
|
|
||||||
|
|
||||||
3. **#define constants**: `#define VALUE (1u << 0)`
|
|
||||||
- **Workaround**: Use clang preprocessor or manual definitions
|
|
||||||
|
|
||||||
## Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
parser/
|
|
||||||
├── src/
|
|
||||||
│ ├── parser.zig # Main entry point
|
|
||||||
│ ├── patterns.zig # Pattern matching & scanning
|
|
||||||
│ ├── types.zig # C to Zig type conversion
|
|
||||||
│ ├── naming.zig # Naming conventions
|
|
||||||
│ ├── codegen.zig # Zig code generation
|
|
||||||
│ ├── mock_codegen.zig # C mock generation
|
|
||||||
│ └── dependency_resolver.zig # Dependency analysis [NEW]
|
|
||||||
├── test/ # Test files
|
|
||||||
├── docs/ # Documentation
|
|
||||||
├── build.zig # Build configuration
|
|
||||||
└── README.md # Full documentation
|
|
||||||
```
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
- `PARSER_OVERVIEW.md` - How the parser works
|
|
||||||
- `DEPENDENCY_PLAN.md` - Original dependency design
|
|
||||||
- `DEPENDENCY_IMPLEMENTATION_STATUS.md` - Current status
|
|
||||||
- `IMPLEMENTATION_SUMMARY.md` - Session summary
|
|
||||||
- `AGENTS.md` - Zig 0.15 guidelines for AI agents
|
|
||||||
- `TODO.md` - Next steps
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Run all tests
|
|
||||||
zig build test
|
|
||||||
|
|
||||||
# Test with specific header
|
|
||||||
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=test_output.zig
|
|
||||||
|
|
||||||
# Verify output compiles (requires c.zig)
|
|
||||||
zig ast-check test_output.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
## Example Workflow
|
|
||||||
|
|
||||||
1. **Parse header with dependencies**:
|
|
||||||
```bash
|
|
||||||
zig build run -- ../SDL/include/SDL3/SDL_gpu.h --output=gpu.zig
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Check the output**:
|
|
||||||
```bash
|
|
||||||
cat gpu.zig | head -50
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Create c.zig wrapper**:
|
|
||||||
```zig
|
|
||||||
pub const c = @cImport({
|
|
||||||
@cInclude("SDL3/SDL.h");
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Use in your project**:
|
|
||||||
```zig
|
|
||||||
const gpu = @import("gpu.zig");
|
|
||||||
|
|
||||||
pub fn main() !void {
|
|
||||||
const device = gpu.createGPUDevice(true);
|
|
||||||
defer device.?.destroyGPUDevice();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Issues
|
|
||||||
|
|
||||||
### "FileNotFound" error
|
|
||||||
- Check header path is correct relative to working directory
|
|
||||||
- Use absolute path: `/full/path/to/SDL/include/SDL3/SDL_gpu.h`
|
|
||||||
|
|
||||||
### "Syntax errors detected"
|
|
||||||
- Usually multi-field struct issue (known limitation)
|
|
||||||
- Check output file for specific line numbers
|
|
||||||
- Manually fix or wait for parser update
|
|
||||||
|
|
||||||
### "Warning: Could not find definition for type"
|
|
||||||
- Type might be typedef (not yet supported)
|
|
||||||
- Type might be in different include (check manually)
|
|
||||||
- Type might be #define-based (use manual definition)
|
|
||||||
|
|
||||||
## Performance
|
|
||||||
|
|
||||||
- Small headers (<100 decls): ~100ms
|
|
||||||
- Large headers (SDL_gpu.h, 169 decls): ~500ms with dependencies
|
|
||||||
- Memory usage: ~2-5MB peak
|
|
||||||
- Output size: ~1KB per declaration
|
|
||||||
|
|
||||||
## Getting Help
|
|
||||||
|
|
||||||
1. Check `DEPENDENCY_IMPLEMENTATION_STATUS.md` for known issues
|
|
||||||
2. Look at `TODO.md` for planned improvements
|
|
||||||
3. Read `AGENTS.md` if you're an AI agent working on this
|
|
||||||
4. Check test files in `test/` for usage examples
|
|
||||||
|
|
||||||
## Version Info
|
|
||||||
|
|
||||||
- **Parser Version**: 2.0 (with dependency resolution)
|
|
||||||
- **Zig Version**: 0.15.2
|
|
||||||
- **SDL Version**: 3.2.0
|
|
||||||
- **Status**: Operational with known limitations ✅
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Last Updated**: 2026-01-22
|
|
||||||
**Next Milestone**: Fix multi-field struct parsing
|
|
||||||
Loading…
Reference in New Issue