feat: Add array field and multi-line comment support - +3 more APIs!
Implemented two critical parser enhancements that unlock 3 more perfect APIs and fix issues across multiple headers. ## Features Added ### 1. Array Field Parsing Support for C array fields in structs: ```c Uint8 padding[2]; // C → padding: [2]u8, // Zig ``` **Implementation (patterns.zig)**: - Detect array syntax with `[` bracket - Parse pattern: `Type name[size]` - Extract base type, field name, and array notation - Reconstruct as Zig array type: `Type[size]` **Type Conversion (types.zig)**: - Handle array types in `convertType()` - Pattern: `Uint8[2]` → `[2]u8` - Recursively convert base type - Reorder to Zig syntax: `[size]BaseType` ### 2. Multi-Line Comment Handling Fixed enum parsing to skip multi-line `/* ... */` comments: - Previously only handled `/** ... */` documentation comments - SDL uses `/* ... */` for macro expansion examples - Comments were leaking into enum values causing syntax errors **Before**: ```zig chromaLocationNone), // Stray ) from comment! ``` **After**: ```zig chromaLocationNone, // Clean! ``` **Implementation**: - Changed comment detection from `/**` to `/*` - Tracks `in_multiline_comment` state - Skips ALL lines within comment blocks ## Results ### Before - 19/43 APIs perfect (44%) - Array fields: NOT SUPPORTED - Multi-line comments: BROKEN ### After - **22/43 APIs perfect (51%)** ✅ - Array fields: FULLY SUPPORTED - Multi-line comments: FIXED **Progress: +7% (+3 APIs)** ### New Perfect APIs ✅ **SDL_pixels.h** (288 lines) - Pixel format definitions - Color management (palettes, colorspaces) - Had 4 errors: array fields + multi-line comments - Now perfect! ✅ **SDL_surface.h** (495 lines) - Surface creation and manipulation - Largest perfect API so far! - Had 2 errors: array fields + multi-line comments - Now perfect! ✅ **SDL_guid.h** (13 lines) - GUID utilities - Was 1 error, now perfect! ## Technical Details ### Array Field Parsing Algorithm 1. Detect `[` in field declaration 2. Split at bracket: `Uint8 padding[2]` → before: `Uint8 padding`, array: `[2]` 3. Tokenize before bracket by spaces 4. Last token is field name, rest is type 5. Combine type + array notation: `Uint8[2]` 6. Generate Zig: `padding: [2]u8,` ### Multi-Line Comment Fix Changed detection in enum scanning from: ```zig if (std.mem.indexOf(u8, trimmed, "/**")) |_| { ``` To: ```zig if (std.mem.indexOf(u8, trimmed, "/*")) |_| { ``` This catches ALL multi-line comments, not just doc comments. ## Impact **Immediate**: +3 perfect APIs (7% improvement) **Unlocked**: Array fields now work everywhere **Fixed**: Enum parsing more robust ## Code Changes ### src/patterns.zig (+40 lines) - `parseStructField()`: Array field detection and parsing - `scanEnum()`: Fixed multi-line comment detection - Uses fixed buffers (no allocations) for performance ### src/types.zig (+15 lines) - `convertType()`: Array type conversion - Recursive base type conversion - Reorders to Zig syntax: `[size]Type` ## Testing Tested against all 43 SDL3 headers: - 22 compile perfectly (0 errors) ✅ - 21 have 1-13 errors (edge cases) - 0 complete failures **Cumulative Progress**: - Session start: 15 APIs (35%) - After function pointers: 19 APIs (44%) - After arrays & comments: **22 APIs (51%)** 🎉 **More than half of SDL3 APIs now generate perfectly!** ## Example Output **Input** (SDL_pixels.h): ```c typedef struct SDL_PixelFormatDetails { SDL_PixelFormat format; Uint8 bits_per_pixel; Uint8 bytes_per_pixel; Uint8 padding[2]; Uint32 Rmask; ... } SDL_PixelFormatDetails; ``` **Output** (pixels.zig): ```zig pub const PixelFormatDetails = extern struct { format: PixelFormat, bits_per_pixel: u8, bytes_per_pixel: u8, padding: [2]u8, Rmask: u32, ... }; ``` --- Arrays are now fully supported - critical for many SDL structs!
This commit is contained in:
parent
6474e26ee3
commit
92b497fdba
|
|
@ -376,8 +376,8 @@ pub const Scanner = struct {
|
|||
const trimmed = std.mem.trim(u8, line, " \t\r");
|
||||
if (trimmed.len == 0) continue;
|
||||
|
||||
// Track multi-line comments
|
||||
if (std.mem.indexOf(u8, trimmed, "/**")) |_| {
|
||||
// Track multi-line comments (both /** and /* styles)
|
||||
if (std.mem.indexOf(u8, trimmed, "/*")) |_| {
|
||||
in_multiline_comment = true;
|
||||
}
|
||||
if (in_multiline_comment) {
|
||||
|
|
@ -389,7 +389,6 @@ pub const Scanner = struct {
|
|||
|
||||
// Skip various comment/bracket/preprocessor lines
|
||||
if (std.mem.startsWith(u8, trimmed, "//")) continue;
|
||||
if (std.mem.startsWith(u8, trimmed, "/*")) continue;
|
||||
if (std.mem.startsWith(u8, trimmed, "*")) continue; // Lines inside comments
|
||||
if (std.mem.startsWith(u8, trimmed, "#")) continue; // Preprocessor directives
|
||||
if (std.mem.startsWith(u8, trimmed, "{")) continue;
|
||||
|
|
@ -581,10 +580,54 @@ pub const Scanner = struct {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Parse "type name" - handle pointer types correctly
|
||||
// Parse "type name" or "type name[size]" - handle pointer types and arrays correctly
|
||||
// Examples:
|
||||
// "SDL_GPUTransferBuffer *transfer_buffer" -> type:"SDL_GPUTransferBuffer *" name:"transfer_buffer"
|
||||
// "Uint32 offset" -> type:"Uint32" name:"offset"
|
||||
// "Uint8 padding[2]" -> type:"Uint8[2]" name:"padding"
|
||||
|
||||
// Check if this is an array field (has brackets)
|
||||
if (std.mem.indexOf(u8, field_trimmed, "[")) |bracket_pos| {
|
||||
// Extract array size and append to type
|
||||
// Pattern: "Uint8 padding[2]" -> parse as type="Uint8[2]" name="padding"
|
||||
const before_bracket = std.mem.trimRight(u8, field_trimmed[0..bracket_pos], " \t");
|
||||
const bracket_part = field_trimmed[bracket_pos..]; // "[2]"
|
||||
|
||||
// Split before_bracket into type and name
|
||||
var tokens = std.mem.tokenizeScalar(u8, before_bracket, ' ');
|
||||
var parts_list: [8][]const u8 = undefined;
|
||||
var parts_count: usize = 0;
|
||||
while (tokens.next()) |token| {
|
||||
if (token.len > 0 and !std.mem.eql(u8, token, "const")) {
|
||||
if (parts_count >= 8) return null;
|
||||
parts_list[parts_count] = token;
|
||||
parts_count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (parts_count < 2) return null; // Need at least type and name
|
||||
|
||||
const name = parts_list[parts_count - 1];
|
||||
const type_parts = parts_list[0..parts_count - 1];
|
||||
|
||||
// Reconstruct type with array notation
|
||||
var type_buf: [128]u8 = undefined;
|
||||
var fbs = std.io.fixedBufferStream(&type_buf);
|
||||
const writer = fbs.writer();
|
||||
for (type_parts, 0..) |part, i| {
|
||||
if (i > 0) writer.writeByte(' ') catch return null;
|
||||
writer.writeAll(part) catch return null;
|
||||
}
|
||||
writer.writeAll(bracket_part) catch return null;
|
||||
|
||||
const type_str = fbs.getWritten();
|
||||
|
||||
return FieldDecl{
|
||||
.name = try self.allocator.dupe(u8, name),
|
||||
.type_name = try self.allocator.dupe(u8, type_str),
|
||||
.comment = comment,
|
||||
};
|
||||
}
|
||||
|
||||
// Find last identifier by scanning backwards for alphanumeric/_
|
||||
// The field name is the last contiguous sequence of [a-zA-Z0-9_]
|
||||
|
|
|
|||
|
|
@ -6,6 +6,19 @@ const Allocator = std.mem.Allocator;
|
|||
pub fn convertType(c_type: []const u8, allocator: Allocator) ![]const u8 {
|
||||
const trimmed = std.mem.trim(u8, c_type, " \t");
|
||||
|
||||
// Handle array types: "Uint8[2]" -> "[2]u8"
|
||||
if (std.mem.indexOf(u8, trimmed, "[")) |bracket_pos| {
|
||||
const base_type = std.mem.trim(u8, trimmed[0..bracket_pos], " \t");
|
||||
const array_part = trimmed[bracket_pos..]; // "[2]"
|
||||
|
||||
// Recursively convert the base type
|
||||
const zig_base = try convertType(base_type, allocator);
|
||||
defer allocator.free(zig_base);
|
||||
|
||||
// Return Zig array notation: [size]Type
|
||||
return try std.fmt.allocPrint(allocator, "{s}{s}", .{array_part, zig_base});
|
||||
}
|
||||
|
||||
// Primitives
|
||||
if (std.mem.eql(u8, trimmed, "void")) return try allocator.dupe(u8, "void");
|
||||
if (std.mem.eql(u8, trimmed, "bool")) return try allocator.dupe(u8, "bool");
|
||||
|
|
|
|||
Loading…
Reference in New Issue