Add union parsing support and fix comment handling in struct/union scanners
- Added UnionDecl type to patterns - Implemented scanUnion() function similar to scanStruct() - Added writeUnion() code generation - Updated all switch statements to handle union_decl - Fixed multi-line comment detection to handle both /* and /** - Skip empty enums during code generation - Update dependency resolver to track union field dependencies
This commit is contained in:
parent
79dd39e36a
commit
d270b3fc84
|
|
@ -1,52 +0,0 @@
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import json
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
class HeaderParser:
|
|
||||||
|
|
||||||
def __init__(self, headerList, target, headerName):
|
|
||||||
self.headerList = headerList
|
|
||||||
self.path = target
|
|
||||||
self.headerName = headerName
|
|
||||||
self.outputPrefix = "asts/" + headerName
|
|
||||||
self.astJsonFile = os.path.join(orig_dir, self.headerName + ".ast.json")
|
|
||||||
with open(self.astJsonFile) as f:
|
|
||||||
self.jsonRepr = json.load(f)
|
|
||||||
|
|
||||||
orig_dir = os.path.abspath(os.path.dirname(__file__))
|
|
||||||
inputList = []
|
|
||||||
|
|
||||||
def parseAll(sdl3IncludePath, headerList):
|
|
||||||
parsedList = []
|
|
||||||
for f in headerList:
|
|
||||||
if f.endswith(".h"):
|
|
||||||
headerName = f.split(".")[0]
|
|
||||||
if "_" in headerName:
|
|
||||||
headerName = headerName.split('_')[1]
|
|
||||||
|
|
||||||
print(headerName)
|
|
||||||
parsedList.append(os.path.join(sdl3IncludePath, f))
|
|
||||||
parsePath = os.path.join(sdl3IncludePath, 'SDL_gpu.h')
|
|
||||||
# os.system(f"cheader2json convert {f} --prefix={self.headerName}")
|
|
||||||
|
|
||||||
def parse():
|
|
||||||
global inputList
|
|
||||||
sdl3IncludePath = os.path.join(orig_dir, 'SDL/include/SDL3')
|
|
||||||
discoveredFiles = os.listdir(os.path.join(orig_dir, 'SDL/include/SDL3'))
|
|
||||||
|
|
||||||
parsedList = []
|
|
||||||
|
|
||||||
parseAll(sdl3IncludePath, discoveredFiles)
|
|
||||||
|
|
||||||
sdlHeaderList = []
|
|
||||||
for file in discoveredFiles:
|
|
||||||
sdlHeaderList.append(os.path.join(sdl3IncludePath, file))
|
|
||||||
|
|
||||||
parsed = HeaderParser(sdlHeaderList, os.path.join(sdl3IncludePath, 'SDL_gpu.h'), "gpu")
|
|
||||||
|
|
||||||
print("parsing list: ", inputList)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
while True:
|
|
||||||
parse()
|
|
||||||
|
|
@ -0,0 +1,135 @@
|
||||||
|
# SDL_video.h Parsing Analysis
|
||||||
|
|
||||||
|
## Current Status: ✅ MOSTLY WORKING
|
||||||
|
|
||||||
|
The SDL_video.h header parses successfully with only minor missing type warnings. All major functionality is captured.
|
||||||
|
|
||||||
|
## Statistics
|
||||||
|
|
||||||
|
- **Total declarations found**: 124
|
||||||
|
- Opaque types: 2
|
||||||
|
- Typedefs: 6
|
||||||
|
- Function pointers: 0
|
||||||
|
- Enums: 4
|
||||||
|
- Structs: 2
|
||||||
|
- Flags: 1
|
||||||
|
- Functions: 109
|
||||||
|
|
||||||
|
## Successfully Resolved Dependencies
|
||||||
|
|
||||||
|
The parser successfully resolves and imports these types from dependency headers:
|
||||||
|
|
||||||
|
✅ **SDL_PixelFormat** (from SDL_pixels.h)
|
||||||
|
✅ **SDL_Point** (from SDL_rect.h)
|
||||||
|
✅ **SDL_Rect** (from SDL_rect.h)
|
||||||
|
✅ **SDL_Surface** (from SDL_surface.h)
|
||||||
|
✅ **SDL_PropertiesID** (from SDL_properties.h)
|
||||||
|
|
||||||
|
## Missing Type Definitions (7 types)
|
||||||
|
|
||||||
|
These types are referenced but not found in the included headers:
|
||||||
|
|
||||||
|
### 1. EGL-Related Types (5 types)
|
||||||
|
|
||||||
|
These are OpenGL ES/EGL integration types defined within SDL_video.h itself:
|
||||||
|
|
||||||
|
- **SDL_EGLConfig** - `typedef void *SDL_EGLConfig;`
|
||||||
|
- **SDL_EGLDisplay** - `typedef void *SDL_EGLDisplay;`
|
||||||
|
- **SDL_EGLSurface** - `typedef void *SDL_EGLSurface;`
|
||||||
|
- **SDL_EGLAttribArrayCallback** - Function pointer typedef
|
||||||
|
- **SDL_EGLIntArrayCallback** - Function pointer typedef
|
||||||
|
|
||||||
|
**Root Cause**: These are defined in SDL_video.h but the parser's typedef scanner is not picking them up properly.
|
||||||
|
|
||||||
|
**Issue**: The typedef scanner currently only processes simple typedefs and doesn't handle:
|
||||||
|
- Pointer typedefs (`typedef void *Type;`)
|
||||||
|
- Function pointer typedefs with complex signatures
|
||||||
|
|
||||||
|
### 2. OpenGL Types (2 types)
|
||||||
|
|
||||||
|
- **SDL_GLAttr** - Enum type for GL attributes
|
||||||
|
- **SDL_GLContext** - `typedef struct SDL_GLContextState *SDL_GLContext;`
|
||||||
|
|
||||||
|
**Root Cause**: Similar to EGL types - these are typedef'd in SDL_video.h but not captured by the scanner.
|
||||||
|
|
||||||
|
### 3. Callback Types (1 type)
|
||||||
|
|
||||||
|
- **SDL_HitTest** - `typedef SDL_HitTestResult (SDLCALL *SDL_HitTest)(...);`
|
||||||
|
|
||||||
|
**Root Cause**: Function pointer typedef with calling convention modifier.
|
||||||
|
|
||||||
|
### 4. Generic Types (1 type)
|
||||||
|
|
||||||
|
- **SDL_FunctionPointer** - `typedef void (SDLCALL *SDL_FunctionPointer)(void);`
|
||||||
|
|
||||||
|
**Root Cause**: Function pointer typedef.
|
||||||
|
|
||||||
|
## Implementation Plan
|
||||||
|
|
||||||
|
### Phase 1: Enhance Typedef Scanner ✅ PRIORITY
|
||||||
|
|
||||||
|
**Goal**: Make the typedef scanner capture all typedef forms in the same file being parsed.
|
||||||
|
|
||||||
|
**Tasks**:
|
||||||
|
|
||||||
|
1. **Add pointer typedef support**
|
||||||
|
```c
|
||||||
|
typedef void *SDL_EGLConfig;
|
||||||
|
typedef struct SDL_GLContextState *SDL_GLContext;
|
||||||
|
```
|
||||||
|
- Pattern: `typedef <type> *<name>;`
|
||||||
|
- Store as opaque pointer type
|
||||||
|
|
||||||
|
2. **Add function pointer typedef support**
|
||||||
|
```c
|
||||||
|
typedef SDL_HitTestResult (SDLCALL *SDL_HitTest)(SDL_Window *win, const SDL_Point *area, void *data);
|
||||||
|
typedef void (SDLCALL *SDL_FunctionPointer)(void);
|
||||||
|
```
|
||||||
|
- Pattern: `typedef <return> (SDLCALL *<name>)(<params>);`
|
||||||
|
- Store as function pointer type with signature
|
||||||
|
|
||||||
|
3. **Add enum typedef support**
|
||||||
|
```c
|
||||||
|
typedef enum SDL_GLAttr { ... } SDL_GLAttr;
|
||||||
|
```
|
||||||
|
- Pattern: Already handled, but verify it works for GL types
|
||||||
|
|
||||||
|
**Implementation Location**: `src/dependency_resolver.zig` - `scanFileForTypedefs()`
|
||||||
|
|
||||||
|
**Expected Result**: After this phase, all 7 missing types should be found and properly typed.
|
||||||
|
|
||||||
|
### Phase 2: Test and Validate
|
||||||
|
|
||||||
|
1. Run parser on SDL_video.h
|
||||||
|
2. Verify all 14 originally missing types are now resolved (7 from deps, 7 from typedefs)
|
||||||
|
3. Verify generated Zig code compiles
|
||||||
|
4. Check that function signatures using these types are correct
|
||||||
|
|
||||||
|
### Phase 3: Apply to Other Headers
|
||||||
|
|
||||||
|
Once SDL_video.h parses completely clean, apply the same pattern to other headers with similar issues.
|
||||||
|
|
||||||
|
## Error Categories
|
||||||
|
|
||||||
|
### Category A: Typedef Scanner Limitations ⭐ PRIMARY ISSUE
|
||||||
|
- **Impact**: 7/14 missing types (50%)
|
||||||
|
- **Difficulty**: Medium
|
||||||
|
- **Files affected**: SDL_video.h, potentially others
|
||||||
|
- **Solution**: Enhance typedef scanner (Phase 1)
|
||||||
|
|
||||||
|
### Category B: Cross-header Dependencies ✅ SOLVED
|
||||||
|
- **Impact**: 7/14 missing types (50%) - but these work!
|
||||||
|
- **Difficulty**: N/A (already working)
|
||||||
|
- **Solution**: Existing dependency resolver handles this correctly
|
||||||
|
|
||||||
|
## Success Metrics
|
||||||
|
|
||||||
|
After implementing Phase 1:
|
||||||
|
- ⬜ Zero "Could not find definition" warnings for SDL_video.h
|
||||||
|
- ⬜ Generated code compiles without errors
|
||||||
|
- ⬜ All 124 declarations properly typed
|
||||||
|
- ⬜ Can use as template for other complex headers
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
The current parsing system is quite robust. The main gap is in the typedef scanner not recognizing all forms of typedef. This is a focused, solvable problem that will unlock SDL_video.h and similar headers.
|
||||||
|
|
@ -99,6 +99,7 @@ pub const CodeGen = struct {
|
||||||
.function_pointer_decl => |func_ptr_decl| try self.writeFunctionPointer(func_ptr_decl),
|
.function_pointer_decl => |func_ptr_decl| try self.writeFunctionPointer(func_ptr_decl),
|
||||||
.enum_decl => |enum_decl| try self.writeEnum(enum_decl),
|
.enum_decl => |enum_decl| try self.writeEnum(enum_decl),
|
||||||
.struct_decl => |struct_decl| try self.writeStruct(struct_decl),
|
.struct_decl => |struct_decl| try self.writeStruct(struct_decl),
|
||||||
|
.union_decl => |union_decl| try self.writeUnion(union_decl),
|
||||||
.flag_decl => |flag_decl| try self.writeFlags(flag_decl),
|
.flag_decl => |flag_decl| try self.writeFlags(flag_decl),
|
||||||
.function_decl => |func| {
|
.function_decl => |func| {
|
||||||
// Only write standalone functions (not methods)
|
// Only write standalone functions (not methods)
|
||||||
|
|
@ -206,6 +207,11 @@ pub const CodeGen = struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn writeEnum(self: *CodeGen, enum_decl: EnumDecl) !void {
|
fn writeEnum(self: *CodeGen, enum_decl: EnumDecl) !void {
|
||||||
|
// Skip empty enums
|
||||||
|
if (enum_decl.values.len == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const zig_name = naming.typeNameToZig(enum_decl.name);
|
const zig_name = naming.typeNameToZig(enum_decl.name);
|
||||||
|
|
||||||
// Write doc comment if present
|
// Write doc comment if present
|
||||||
|
|
@ -270,6 +276,36 @@ pub const CodeGen = struct {
|
||||||
try self.output.appendSlice(self.allocator, "};\n\n");
|
try self.output.appendSlice(self.allocator, "};\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn writeUnion(self: *CodeGen, union_decl: patterns.UnionDecl) !void {
|
||||||
|
const zig_name = naming.typeNameToZig(union_decl.name);
|
||||||
|
|
||||||
|
// Write doc comment if present
|
||||||
|
if (union_decl.doc_comment) |doc| {
|
||||||
|
try self.writeDocComment(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// pub const Event = extern union {
|
||||||
|
try self.output.writer(self.allocator).print("pub const {s} = extern union {{\n", .{zig_name});
|
||||||
|
|
||||||
|
// Write fields
|
||||||
|
for (union_decl.fields) |field| {
|
||||||
|
const zig_type = try types.convertType(field.type_name, self.allocator);
|
||||||
|
defer self.allocator.free(zig_type);
|
||||||
|
|
||||||
|
if (field.comment) |comment| {
|
||||||
|
try self.output.writer(self.allocator).print(" {s}: {s}, // {s}\n", .{
|
||||||
|
field.name,
|
||||||
|
zig_type,
|
||||||
|
comment,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
try self.output.writer(self.allocator).print(" {s}: {s},\n", .{ field.name, zig_type });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.output.appendSlice(self.allocator, "};\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
fn writeFlags(self: *CodeGen, flag_decl: FlagDecl) !void {
|
fn writeFlags(self: *CodeGen, flag_decl: FlagDecl) !void {
|
||||||
const zig_name = naming.typeNameToZig(flag_decl.name);
|
const zig_name = naming.typeNameToZig(flag_decl.name);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,7 @@ pub const DependencyResolver = struct {
|
||||||
.function_pointer_decl => |fp| fp.name,
|
.function_pointer_decl => |fp| fp.name,
|
||||||
.enum_decl => |e| e.name,
|
.enum_decl => |e| e.name,
|
||||||
.struct_decl => |s| s.name,
|
.struct_decl => |s| s.name,
|
||||||
|
.union_decl => |u| u.name,
|
||||||
.flag_decl => |f| f.name,
|
.flag_decl => |f| f.name,
|
||||||
.function_decl => continue,
|
.function_decl => continue,
|
||||||
};
|
};
|
||||||
|
|
@ -84,6 +85,11 @@ pub const DependencyResolver = struct {
|
||||||
try self.scanType(field.type_name);
|
try self.scanType(field.type_name);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
.union_decl => |union_decl| {
|
||||||
|
for (union_decl.fields) |field| {
|
||||||
|
try self.scanType(field.type_name);
|
||||||
|
}
|
||||||
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -251,6 +257,7 @@ pub fn extractTypeFromHeader(
|
||||||
.typedef_decl => |t| t.name,
|
.typedef_decl => |t| t.name,
|
||||||
.enum_decl => |e| e.name,
|
.enum_decl => |e| e.name,
|
||||||
.struct_decl => |s| s.name,
|
.struct_decl => |s| s.name,
|
||||||
|
.union_decl => |u| u.name,
|
||||||
.flag_decl => |f| f.name,
|
.flag_decl => |f| f.name,
|
||||||
else => continue,
|
else => continue,
|
||||||
};
|
};
|
||||||
|
|
@ -300,6 +307,13 @@ fn cloneDeclaration(allocator: Allocator, decl: Declaration) !Declaration {
|
||||||
.fields = try cloneFields(allocator, s.fields),
|
.fields = try cloneFields(allocator, s.fields),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
.union_decl => |u| .{
|
||||||
|
.union_decl = .{
|
||||||
|
.name = try allocator.dupe(u8, u.name),
|
||||||
|
.doc_comment = if (u.doc_comment) |doc| try allocator.dupe(u8, doc) else null,
|
||||||
|
.fields = try cloneFields(allocator, u.fields),
|
||||||
|
},
|
||||||
|
},
|
||||||
.flag_decl => |f| .{
|
.flag_decl => |f| .{
|
||||||
.flag_decl = .{
|
.flag_decl = .{
|
||||||
.name = try allocator.dupe(u8, f.name),
|
.name = try allocator.dupe(u8, f.name),
|
||||||
|
|
@ -407,6 +421,16 @@ fn freeDeclaration(allocator: Allocator, decl: Declaration) void {
|
||||||
}
|
}
|
||||||
allocator.free(s.fields);
|
allocator.free(s.fields);
|
||||||
},
|
},
|
||||||
|
.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);
|
||||||
|
},
|
||||||
.flag_decl => |f| {
|
.flag_decl => |f| {
|
||||||
allocator.free(f.name);
|
allocator.free(f.name);
|
||||||
allocator.free(f.underlying_type);
|
allocator.free(f.underlying_type);
|
||||||
|
|
|
||||||
|
|
@ -97,6 +97,16 @@ pub fn main() !void {
|
||||||
}
|
}
|
||||||
allocator.free(struct_decl.fields);
|
allocator.free(struct_decl.fields);
|
||||||
},
|
},
|
||||||
|
.union_decl => |union_decl| {
|
||||||
|
allocator.free(union_decl.name);
|
||||||
|
if (union_decl.doc_comment) |doc| allocator.free(doc);
|
||||||
|
for (union_decl.fields) |field| {
|
||||||
|
allocator.free(field.name);
|
||||||
|
allocator.free(field.type_name);
|
||||||
|
if (field.comment) |c| allocator.free(c);
|
||||||
|
}
|
||||||
|
allocator.free(union_decl.fields);
|
||||||
|
},
|
||||||
.flag_decl => |flag_decl| {
|
.flag_decl => |flag_decl| {
|
||||||
allocator.free(flag_decl.name);
|
allocator.free(flag_decl.name);
|
||||||
allocator.free(flag_decl.underlying_type);
|
allocator.free(flag_decl.underlying_type);
|
||||||
|
|
@ -131,6 +141,7 @@ pub fn main() !void {
|
||||||
var func_ptr_count: usize = 0;
|
var func_ptr_count: usize = 0;
|
||||||
var enum_count: usize = 0;
|
var enum_count: usize = 0;
|
||||||
var struct_count: usize = 0;
|
var struct_count: usize = 0;
|
||||||
|
var union_count: usize = 0;
|
||||||
var flag_count: usize = 0;
|
var flag_count: usize = 0;
|
||||||
var func_count: usize = 0;
|
var func_count: usize = 0;
|
||||||
|
|
||||||
|
|
@ -141,6 +152,7 @@ pub fn main() !void {
|
||||||
.function_pointer_decl => func_ptr_count += 1,
|
.function_pointer_decl => func_ptr_count += 1,
|
||||||
.enum_decl => enum_count += 1,
|
.enum_decl => enum_count += 1,
|
||||||
.struct_decl => struct_count += 1,
|
.struct_decl => struct_count += 1,
|
||||||
|
.union_decl => union_count += 1,
|
||||||
.flag_decl => flag_count += 1,
|
.flag_decl => flag_count += 1,
|
||||||
.function_decl => func_count += 1,
|
.function_decl => func_count += 1,
|
||||||
}
|
}
|
||||||
|
|
@ -151,6 +163,7 @@ pub fn main() !void {
|
||||||
std.debug.print(" - Function pointers: {d}\n", .{func_ptr_count});
|
std.debug.print(" - Function pointers: {d}\n", .{func_ptr_count});
|
||||||
std.debug.print(" - Enums: {d}\n", .{enum_count});
|
std.debug.print(" - Enums: {d}\n", .{enum_count});
|
||||||
std.debug.print(" - Structs: {d}\n", .{struct_count});
|
std.debug.print(" - Structs: {d}\n", .{struct_count});
|
||||||
|
std.debug.print(" - Unions: {d}\n", .{union_count});
|
||||||
std.debug.print(" - Flags: {d}\n", .{flag_count});
|
std.debug.print(" - Flags: {d}\n", .{flag_count});
|
||||||
std.debug.print(" - Functions: {d}\n\n", .{func_count});
|
std.debug.print(" - Functions: {d}\n\n", .{func_count});
|
||||||
|
|
||||||
|
|
@ -392,6 +405,16 @@ fn freeDeclDeep(allocator: std.mem.Allocator, decl: patterns.Declaration) void {
|
||||||
}
|
}
|
||||||
allocator.free(s.fields);
|
allocator.free(s.fields);
|
||||||
},
|
},
|
||||||
|
.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);
|
||||||
|
},
|
||||||
.flag_decl => |f| {
|
.flag_decl => |f| {
|
||||||
allocator.free(f.name);
|
allocator.free(f.name);
|
||||||
allocator.free(f.underlying_type);
|
allocator.free(f.underlying_type);
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ pub const Declaration = union(enum) {
|
||||||
opaque_type: OpaqueType,
|
opaque_type: OpaqueType,
|
||||||
enum_decl: EnumDecl,
|
enum_decl: EnumDecl,
|
||||||
struct_decl: StructDecl,
|
struct_decl: StructDecl,
|
||||||
|
union_decl: UnionDecl,
|
||||||
flag_decl: FlagDecl,
|
flag_decl: FlagDecl,
|
||||||
function_decl: FunctionDecl,
|
function_decl: FunctionDecl,
|
||||||
typedef_decl: TypedefDecl,
|
typedef_decl: TypedefDecl,
|
||||||
|
|
@ -35,6 +36,12 @@ pub const StructDecl = struct {
|
||||||
doc_comment: ?[]const u8,
|
doc_comment: ?[]const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const UnionDecl = struct {
|
||||||
|
name: []const u8, // SDL_Event
|
||||||
|
fields: []FieldDecl,
|
||||||
|
doc_comment: ?[]const u8,
|
||||||
|
};
|
||||||
|
|
||||||
pub const FieldDecl = struct {
|
pub const FieldDecl = struct {
|
||||||
name: []const u8, // x
|
name: []const u8, // x
|
||||||
type_name: []const u8, // float
|
type_name: []const u8, // float
|
||||||
|
|
@ -111,6 +118,8 @@ pub const Scanner = struct {
|
||||||
try decls.append(self.allocator, .{ .enum_decl = enum_decl });
|
try decls.append(self.allocator, .{ .enum_decl = enum_decl });
|
||||||
} else if (try self.scanStruct()) |struct_decl| {
|
} else if (try self.scanStruct()) |struct_decl| {
|
||||||
try decls.append(self.allocator, .{ .struct_decl = struct_decl });
|
try decls.append(self.allocator, .{ .struct_decl = struct_decl });
|
||||||
|
} else if (try self.scanUnion()) |union_decl| {
|
||||||
|
try decls.append(self.allocator, .{ .union_decl = union_decl });
|
||||||
} else if (try self.scanFlagTypedef()) |flag_decl| {
|
} else if (try self.scanFlagTypedef()) |flag_decl| {
|
||||||
// Flag typedef must come before simple typedef
|
// Flag typedef must come before simple typedef
|
||||||
try decls.append(self.allocator, .{ .flag_decl = flag_decl });
|
try decls.append(self.allocator, .{ .flag_decl = flag_decl });
|
||||||
|
|
@ -500,12 +509,12 @@ pub const Scanner = struct {
|
||||||
while (lines.next()) |line| {
|
while (lines.next()) |line| {
|
||||||
const trimmed = std.mem.trim(u8, line, " \t\r");
|
const trimmed = std.mem.trim(u8, line, " \t\r");
|
||||||
|
|
||||||
// Track multi-line comments
|
// Track multi-line comments (both /** and /*)
|
||||||
if (std.mem.indexOf(u8, trimmed, "/**")) |_| {
|
if (std.mem.indexOf(u8, trimmed, "/*") != null) {
|
||||||
in_multiline_comment = true;
|
in_multiline_comment = true;
|
||||||
}
|
}
|
||||||
if (in_multiline_comment) {
|
if (in_multiline_comment) {
|
||||||
if (std.mem.indexOf(u8, trimmed, "*/")) |_| {
|
if (std.mem.indexOf(u8, trimmed, "*/") != null) {
|
||||||
in_multiline_comment = false;
|
in_multiline_comment = false;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -514,7 +523,6 @@ pub const Scanner = struct {
|
||||||
// Skip comment/bracket/preprocessor lines
|
// Skip comment/bracket/preprocessor lines
|
||||||
if (trimmed.len == 0) continue;
|
if (trimmed.len == 0) continue;
|
||||||
if (std.mem.startsWith(u8, trimmed, "//")) continue;
|
if (std.mem.startsWith(u8, trimmed, "//")) continue;
|
||||||
if (std.mem.startsWith(u8, trimmed, "/*")) continue;
|
|
||||||
if (std.mem.startsWith(u8, trimmed, "*")) continue;
|
if (std.mem.startsWith(u8, trimmed, "*")) continue;
|
||||||
if (std.mem.startsWith(u8, trimmed, "#")) continue;
|
if (std.mem.startsWith(u8, trimmed, "#")) continue;
|
||||||
|
|
||||||
|
|
@ -542,6 +550,85 @@ pub const Scanner = struct {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn scanUnion(self: *Scanner) !?UnionDecl {
|
||||||
|
const start = self.pos;
|
||||||
|
|
||||||
|
if (!self.matchPrefix("typedef union ")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the opening brace and extract the name before it
|
||||||
|
const name_start = self.pos;
|
||||||
|
while (self.pos < self.source.len and self.source[self.pos] != '{') {
|
||||||
|
self.pos += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.pos >= self.source.len) {
|
||||||
|
// No opening brace found - this is an opaque type, not a union
|
||||||
|
self.pos = start;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract name from between "typedef union " and "{"
|
||||||
|
const name_slice = std.mem.trim(u8, self.source[name_start..self.pos], " \t\n\r");
|
||||||
|
var iter = std.mem.tokenizeScalar(u8, name_slice, ' ');
|
||||||
|
const name = iter.next() orelse {
|
||||||
|
self.pos = start;
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Now we're at the opening brace, read the braced block
|
||||||
|
const body = try self.readBracedBlock();
|
||||||
|
defer self.allocator.free(body);
|
||||||
|
|
||||||
|
// Parse fields
|
||||||
|
var fields = try std.ArrayList(FieldDecl).initCapacity(self.allocator, 20);
|
||||||
|
var lines = std.mem.splitScalar(u8, body, '\n');
|
||||||
|
var in_multiline_comment = false;
|
||||||
|
|
||||||
|
while (lines.next()) |line| {
|
||||||
|
const trimmed = std.mem.trim(u8, line, " \t\r");
|
||||||
|
|
||||||
|
// Track multi-line comments (both /** and /*)
|
||||||
|
if (std.mem.indexOf(u8, trimmed, "/*") != null) {
|
||||||
|
in_multiline_comment = true;
|
||||||
|
}
|
||||||
|
if (in_multiline_comment) {
|
||||||
|
if (std.mem.indexOf(u8, trimmed, "*/") != null) {
|
||||||
|
in_multiline_comment = false;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip comment/bracket/preprocessor lines
|
||||||
|
if (trimmed.len == 0) continue;
|
||||||
|
if (std.mem.startsWith(u8, trimmed, "//")) continue;
|
||||||
|
if (std.mem.startsWith(u8, trimmed, "*")) continue;
|
||||||
|
if (std.mem.startsWith(u8, trimmed, "#")) continue;
|
||||||
|
|
||||||
|
// Reuse struct field parsing since unions have same field syntax
|
||||||
|
if (try self.parseStructField(line)) |field| {
|
||||||
|
try fields.append(self.allocator, field);
|
||||||
|
} else {
|
||||||
|
const multi_fields = try self.parseMultiFieldLine(line);
|
||||||
|
if (multi_fields.len > 0) {
|
||||||
|
for (multi_fields) |field| {
|
||||||
|
try fields.append(self.allocator, field);
|
||||||
|
}
|
||||||
|
self.allocator.free(multi_fields);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const doc = self.consumePendingDocComment();
|
||||||
|
|
||||||
|
return UnionDecl{
|
||||||
|
.name = try self.allocator.dupe(u8, name),
|
||||||
|
.fields = try fields.toOwnedSlice(self.allocator),
|
||||||
|
.doc_comment = doc,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
fn parseStructField(self: *Scanner, line: []const u8) !?FieldDecl {
|
fn parseStructField(self: *Scanner, line: []const u8) !?FieldDecl {
|
||||||
const trimmed = std.mem.trim(u8, line, " \t\r");
|
const trimmed = std.mem.trim(u8, line, " \t\r");
|
||||||
if (trimmed.len == 0) return null;
|
if (trimmed.len == 0) return null;
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
const std = @import("std");
|
||||||
pub const c = @import("c.zig").c;
|
pub const c = @import("c.zig").c;
|
||||||
|
|
||||||
pub const Window = opaque {};
|
pub const Window = opaque {};
|
||||||
|
|
@ -240,11 +241,13 @@ pub inline fn pushEvent(event: ?*Event) bool {
|
||||||
return c.SDL_PushEvent(event);
|
return c.SDL_PushEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const EventFilter = *const fn(userdata: ?*anyopaque, event: ?*Event) callconv(.C) bool;
|
||||||
|
|
||||||
pub inline fn setEventFilter(filter: EventFilter, userdata: ?*anyopaque) void {
|
pub inline fn setEventFilter(filter: EventFilter, userdata: ?*anyopaque) void {
|
||||||
return c.SDL_SetEventFilter(filter, userdata);
|
return c.SDL_SetEventFilter(filter, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub inline fn getEventFilter(filter: ?*EventFilter, userdata: void **) bool {
|
pub inline fn getEventFilter(filter: ?*EventFilter, userdata: [*c]?*anyopaque) bool {
|
||||||
return c.SDL_GetEventFilter(filter, userdata);
|
return c.SDL_GetEventFilter(filter, userdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
const std = @import("std");
|
||||||
pub const c = @import("c.zig").c;
|
pub const c = @import("c.zig").c;
|
||||||
|
|
||||||
pub const FColor = extern struct {
|
pub const FColor = extern struct {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
const std = @import("std");
|
||||||
pub const c = @import("c.zig").c;
|
pub const c = @import("c.zig").c;
|
||||||
|
|
||||||
pub const Scancode = enum(c_int) {
|
pub const Scancode = enum(c_int) {
|
||||||
|
|
@ -180,7 +181,6 @@ pub const Scancode = enum(c_int) {
|
||||||
scancodeLshift,
|
scancodeLshift,
|
||||||
scancodeRctrl,
|
scancodeRctrl,
|
||||||
scancodeRshift,
|
scancodeRshift,
|
||||||
scancodeMediaSelect,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Window = opaque {
|
pub const Window = opaque {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
const std = @import("std");
|
||||||
pub const c = @import("c.zig").c;
|
pub const c = @import("c.zig").c;
|
||||||
|
|
||||||
pub const PixelFormat = enum(c_int) {
|
pub const PixelFormat = enum(c_int) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue