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