# JSON Output Implementation Plan ## Goal Add a `--generate-json` flag to the parser that outputs all parsed declarations (types, enums, functions, etc.) as a structured JSON file for external tooling and analysis. ## Design Decisions ### 1. JSON Schema Design ```json { "header": "SDL_gpu.h", "parsed_at": "2026-01-22T23:23:35Z", "declarations": { "opaque_types": [ { "name": "SDL_GPUDevice", "doc_comment": "/**\n * Opaque handle to a GPU device\n */" } ], "typedefs": [ { "name": "SDL_PropertiesID", "underlying_type": "Uint32", "doc_comment": "..." } ], "function_pointers": [ { "name": "SDL_TimerCallback", "return_type": "Uint32", "params": [ {"name": "userdata", "type": "void *"}, {"name": "timerID", "type": "SDL_TimerID"} ], "doc_comment": "..." } ], "enums": [ { "name": "SDL_GPUPrimitiveType", "values": [ {"name": "SDL_GPU_PRIMITIVETYPE_TRIANGLELIST", "value": "0", "comment": "..."}, {"name": "SDL_GPU_PRIMITIVETYPE_TRIANGLESTRIP", "value": null, "comment": "..."} ], "doc_comment": "..." } ], "structs": [ { "name": "SDL_GPUViewport", "fields": [ {"name": "x", "type": "float", "comment": "..."}, {"name": "y", "type": "float", "comment": "..."} ], "doc_comment": "..." } ], "unions": [ { "name": "SDL_Event", "fields": [ {"name": "type", "type": "Uint32", "comment": "..."} ], "doc_comment": "..." } ], "flags": [ { "name": "SDL_GPUTextureUsageFlags", "underlying_type": "Uint32", "flags": [ {"name": "SDL_GPU_TEXTUREUSAGE_SAMPLER", "value": "(1u << 0)", "comment": "..."} ], "doc_comment": "..." } ], "functions": [ { "name": "SDL_CreateGPUDevice", "return_type": "SDL_GPUDevice *", "params": [ {"name": "format_flags", "type": "SDL_GPUShaderFormat"} ], "doc_comment": "..." } ] }, "statistics": { "total_declarations": 150, "opaque_types": 5, "typedefs": 10, "function_pointers": 3, "enums": 15, "structs": 25, "unions": 2, "flags": 10, "functions": 80 } } ``` ### 2. Command Line Interface ```bash # Output JSON to stdout parser SDL_gpu.h --generate-json # Output JSON to file parser SDL_gpu.h --generate-json=output.json # Combine with other outputs parser SDL_gpu.h --output=gpu.zig --generate-json=gpu.json ``` ### 3. Implementation Strategy #### Phase 1: Create JSON Serializer Module - Create `src/json_output.zig` - Implement serialization functions for each declaration type - Handle proper escaping of strings (especially doc comments with quotes/newlines) - Use `std.json.stringify` for structured output #### Phase 2: Update Command Line Parsing - Add `--generate-json` and `--generate-json=` flag parsing in `parser.zig` - Store flag in configuration structure #### Phase 3: Integrate with Main Parser Flow - After `scanner.scan()` and dependency resolution - Before or after Zig code generation - Call JSON serializer with full declaration list #### Phase 4: Testing - Test with multiple SDL headers - Verify JSON is valid and well-formed - Test edge cases: empty comments, special characters, null values - Validate against JSON schema ## Implementation Details ### Module Structure (`src/json_output.zig`) ```zig const std = @import("std"); const patterns = @import("patterns.zig"); const Allocator = std.mem.Allocator; pub fn writeJson( allocator: Allocator, writer: anytype, header_name: []const u8, decls: []const patterns.Declaration, ) !void { // Write JSON structure } fn writeOpaqueType(writer: anytype, opaque: patterns.OpaqueType) !void; fn writeTypedef(writer: anytype, typedef: patterns.TypedefDecl) !void; fn writeFunctionPointer(writer: anytype, func_ptr: patterns.FunctionPointerDecl) !void; fn writeEnum(writer: anytype, enum_decl: patterns.EnumDecl) !void; fn writeStruct(writer: anytype, struct_decl: patterns.StructDecl) !void; fn writeUnion(writer: anytype, union_decl: patterns.UnionDecl) !void; fn writeFlags(writer: anytype, flags: patterns.FlagDecl) !void; fn writeFunction(writer: anytype, func: patterns.FunctionDecl) !void; fn escapeString(allocator: Allocator, str: []const u8) ![]u8; ``` ### Updates to `parser.zig` ```zig // Add after argument parsing var json_output_file: ?[]const u8 = null; for (args[2..]) |arg| { // ... existing flags ... const json_prefix = "--generate-json"; if (std.mem.eql(u8, arg, json_prefix)) { json_output_file = ""; // stdout } else if (std.mem.startsWith(u8, arg, json_prefix ++ "=")) { json_output_file = arg[(json_prefix.len + 1)..]; } } // Add after dependency resolution if (json_output_file) |json_file| { std.debug.print("Generating JSON output...\n", .{}); if (json_file.len == 0) { // Write to stdout const stdout = std.io.getStdOut().writer(); try json_output.writeJson(allocator, stdout, header_path, decls); } else { // Write to file const file = try std.fs.cwd().createFile(json_file, .{}); defer file.close(); const writer = file.writer(); try json_output.writeJson(allocator, writer, header_path, decls); std.debug.print("JSON written to: {s}\n", .{json_file}); } } ``` ## Edge Cases to Handle 1. **Null/Optional Fields**: doc_comment, enum values, field comments 2. **String Escaping**: Quotes, newlines, backslashes in doc comments 3. **Special Characters**: Unicode in comments or identifiers 4. **Empty Arrays**: Structs with no fields, enums with no values 5. **Large Output**: Efficient writing without loading entire JSON in memory 6. **Mixed Output**: Ensure JSON doesn't interfere with stderr debug output ## Success Criteria - [ ] Can parse any SDL header and output valid JSON - [ ] JSON validates against standard JSON parsers (jq, Python json module) - [ ] All declaration types are represented - [ ] Doc comments are preserved with proper escaping - [ ] Statistics section is accurate - [ ] Can output to both stdout and file - [ ] Works alongside existing --output and --mocks flags - [ ] No memory leaks in JSON generation path ## Testing Plan ```bash # Test basic functionality ./parser ../SDL/include/SDL3/SDL_gpu.h --generate-json | jq . # Test with file output ./parser ../SDL/include/SDL3/SDL_gpu.h --generate-json=gpu.json cat gpu.json | jq '.statistics' # Test combined with Zig output ./parser ../SDL/include/SDL3/SDL_video.h --output=video.zig --generate-json=video.json # Validate JSON structure python3 -m json.tool gpu.json > /dev/null && echo "Valid JSON" # Test edge cases ./parser test_small.h --generate-json | jq '.declarations.functions[0].doc_comment' ``` ## Future Enhancements (Not in Scope) - JSON Schema file generation - Filtering by declaration type (e.g., only functions) - Dependency graph in JSON format - Diff mode between two JSON outputs - Machine-readable error format ## Iteration Notes ### Iteration 1 Considerations: - Should we include dependency information in JSON? - **Decision**: No, keep it simple. Focus on declarations only. - Should we include source location (line numbers)? - **Decision**: Future enhancement. Not in initial scope. - Should JSON output be pretty-printed or compact? - **Decision**: Pretty-printed with 2-space indentation for readability. - Error handling: What if JSON write fails partway through? - **Decision**: Write to temporary file first, rename on success. For stdout, fail fast. ### Iteration 2 Review: Looking at the plan again: **Strengths:** - Clear JSON schema design - Comprehensive edge case handling - Good testing plan - Realistic scope **Potential Issues:** - Need to handle timestamp generation (use std.time) - Should verify that nested JSON writing doesn't cause stack overflow - Consider buffering for large outputs - Add validation that string escaping handles all C comment styles **Refinements:** - Add buffered writer wrapper for performance - Use `std.json.writeStream` if available in Zig 0.14 - Add --json-pretty flag to control formatting - Document that all strings are UTF-8 encoded ### Final Confidence Assessment: ✅ **High Confidence Areas:** - JSON schema design is complete and covers all declaration types - Integration points are well-defined - Testing approach is thorough ⚠️ **Medium Confidence Areas:** - String escaping complexity (especially multi-line doc comments) - Performance with very large headers - Error recovery during JSON generation ✅ **Ready to Implement:** The plan is comprehensive and actionable. We should proceed with implementation. ## Implementation Order 1. Create `src/json_output.zig` with basic structure 2. Implement individual serialization functions 3. Add command line flag parsing 4. Integrate into main parser flow 5. Test with SDL_gpu.h (known good header) 6. Test with SDL_video.h (larger header) 7. Test edge cases and error conditions 8. Update documentation