const std = @import("std"); const patterns = @import("patterns.zig"); pub const JsonSerializer = struct { allocator: std.mem.Allocator, output: std.ArrayList(u8), header_name: []const u8, opaque_types: std.ArrayList(patterns.OpaqueType), typedefs: std.ArrayList(patterns.TypedefDecl), function_pointers: std.ArrayList(patterns.FunctionPointerDecl), enums: std.ArrayList(patterns.EnumDecl), structs: std.ArrayList(patterns.StructDecl), unions: std.ArrayList(patterns.UnionDecl), flags: std.ArrayList(patterns.FlagDecl), functions: std.ArrayList(patterns.FunctionDecl), pub fn init(allocator: std.mem.Allocator, header_name: []const u8) JsonSerializer { return .{ .allocator = allocator, .output = .{}, .header_name = header_name, .opaque_types = .{}, .typedefs = .{}, .function_pointers = .{}, .enums = .{}, .structs = .{}, .unions = .{}, .flags = .{}, .functions = .{}, }; } pub fn deinit(self: *JsonSerializer) void { self.output.deinit(self.allocator); self.opaque_types.deinit(self.allocator); self.typedefs.deinit(self.allocator); self.function_pointers.deinit(self.allocator); self.enums.deinit(self.allocator); self.structs.deinit(self.allocator); self.unions.deinit(self.allocator); self.flags.deinit(self.allocator); self.functions.deinit(self.allocator); } pub fn addDeclarations(self: *JsonSerializer, decls: []const patterns.Declaration) !void { for (decls) |decl| { switch (decl) { .opaque_type => |o| try self.opaque_types.append(self.allocator, o), .typedef_decl => |t| try self.typedefs.append(self.allocator, t), .function_pointer_decl => |fp| try self.function_pointers.append(self.allocator, fp), .enum_decl => |e| try self.enums.append(self.allocator, e), .struct_decl => |s| try self.structs.append(self.allocator, s), .union_decl => |u| try self.unions.append(self.allocator, u), .flag_decl => |f| try self.flags.append(self.allocator, f), .function_decl => |fn_decl| try self.functions.append(self.allocator, fn_decl), } } } pub fn finalize(self: *JsonSerializer) ![]const u8 { var writer = self.output.writer(self.allocator); try writer.writeAll("{\n"); try writer.writeAll(" \"header\": "); try self.writeString(writer, self.header_name); try writer.writeAll(",\n"); // Serialize opaque types try writer.writeAll(" \"opaque_types\": [\n"); for (self.opaque_types.items, 0..) |opaque_type, i| { try writer.writeAll(" "); try self.serializeOpaqueType(writer, opaque_type); if (i < self.opaque_types.items.len - 1) try writer.writeAll(","); try writer.writeAll("\n"); } try writer.writeAll(" ],\n"); // Serialize typedefs try writer.writeAll(" \"typedefs\": [\n"); for (self.typedefs.items, 0..) |typedef, i| { try writer.writeAll(" "); try self.serializeTypedef(writer, typedef); if (i < self.typedefs.items.len - 1) try writer.writeAll(","); try writer.writeAll("\n"); } try writer.writeAll(" ],\n"); // Serialize function pointers try writer.writeAll(" \"function_pointers\": [\n"); for (self.function_pointers.items, 0..) |fp, i| { try writer.writeAll(" "); try self.serializeFunctionPointer(writer, fp); if (i < self.function_pointers.items.len - 1) try writer.writeAll(","); try writer.writeAll("\n"); } try writer.writeAll(" ],\n"); // Serialize enums try writer.writeAll(" \"enums\": [\n"); for (self.enums.items, 0..) |enum_decl, i| { try writer.writeAll(" "); try self.serializeEnum(writer, enum_decl); if (i < self.enums.items.len - 1) try writer.writeAll(","); try writer.writeAll("\n"); } try writer.writeAll(" ],\n"); // Serialize structs try writer.writeAll(" \"structs\": [\n"); for (self.structs.items, 0..) |struct_decl, i| { try writer.writeAll(" "); try self.serializeStruct(writer, struct_decl); if (i < self.structs.items.len - 1) try writer.writeAll(","); try writer.writeAll("\n"); } try writer.writeAll(" ],\n"); // Serialize unions try writer.writeAll(" \"unions\": [\n"); for (self.unions.items, 0..) |union_decl, i| { try writer.writeAll(" "); try self.serializeUnion(writer, union_decl); if (i < self.unions.items.len - 1) try writer.writeAll(","); try writer.writeAll("\n"); } try writer.writeAll(" ],\n"); // Serialize flags try writer.writeAll(" \"flags\": [\n"); for (self.flags.items, 0..) |flag, i| { try writer.writeAll(" "); try self.serializeFlag(writer, flag); if (i < self.flags.items.len - 1) try writer.writeAll(","); try writer.writeAll("\n"); } try writer.writeAll(" ],\n"); // Serialize functions try writer.writeAll(" \"functions\": [\n"); for (self.functions.items, 0..) |func, i| { try writer.writeAll(" "); try self.serializeFunction(writer, func); if (i < self.functions.items.len - 1) try writer.writeAll(","); try writer.writeAll("\n"); } try writer.writeAll(" ]\n"); try writer.writeAll("}\n"); return self.output.items; } fn serializeOpaqueType(self: *JsonSerializer, writer: anytype, opaque_type: patterns.OpaqueType) !void { try writer.writeAll("{\"name\": "); try self.writeString(writer, opaque_type.name); if (opaque_type.doc_comment) |doc| { try writer.writeAll(", \"doc\": "); try self.writeString(writer, doc); } try writer.writeAll("}"); } fn serializeTypedef(self: *JsonSerializer, writer: anytype, typedef: patterns.TypedefDecl) !void { try writer.writeAll("{\"name\": "); try self.writeString(writer, typedef.name); try writer.writeAll(", \"underlying_type\": "); try self.writeString(writer, typedef.underlying_type); if (typedef.doc_comment) |doc| { try writer.writeAll(", \"doc\": "); try self.writeString(writer, doc); } try writer.writeAll("}"); } fn serializeFunctionPointer(self: *JsonSerializer, writer: anytype, fp: patterns.FunctionPointerDecl) !void { try writer.writeAll("{\"name\": "); try self.writeString(writer, fp.name); try writer.writeAll(", \"return_type\": "); try self.writeString(writer, fp.return_type); try writer.writeAll(", \"parameters\": ["); for (fp.params, 0..) |param, i| { try writer.writeAll("{\"name\": "); try self.writeString(writer, param.name); try writer.writeAll(", \"type\": "); try self.writeString(writer, param.type_name); try writer.writeAll("}"); if (i < fp.params.len - 1) try writer.writeAll(", "); } try writer.writeAll("]"); if (fp.doc_comment) |doc| { try writer.writeAll(", \"doc\": "); try self.writeString(writer, doc); } try writer.writeAll("}"); } fn serializeEnum(self: *JsonSerializer, writer: anytype, enum_decl: patterns.EnumDecl) !void { try writer.writeAll("{\"name\": "); try self.writeString(writer, enum_decl.name); try writer.writeAll(", \"values\": ["); for (enum_decl.values, 0..) |value, i| { try writer.writeAll("{\"name\": "); try self.writeString(writer, value.name); if (value.value) |val| { try writer.writeAll(", \"value\": "); try self.writeString(writer, val); } if (value.comment) |comment| { try writer.writeAll(", \"comment\": "); try self.writeString(writer, comment); } try writer.writeAll("}"); if (i < enum_decl.values.len - 1) try writer.writeAll(", "); } try writer.writeAll("]"); if (enum_decl.doc_comment) |doc| { try writer.writeAll(", \"doc\": "); try self.writeString(writer, doc); } try writer.writeAll("}"); } fn serializeStruct(self: *JsonSerializer, writer: anytype, struct_decl: patterns.StructDecl) !void { try writer.writeAll("{\"name\": "); try self.writeString(writer, struct_decl.name); try writer.writeAll(", \"fields\": ["); for (struct_decl.fields, 0..) |field, i| { try writer.writeAll("{\"name\": "); try self.writeString(writer, field.name); try writer.writeAll(", \"type\": "); try self.writeString(writer, field.type_name); if (field.comment) |comment| { try writer.writeAll(", \"comment\": "); try self.writeString(writer, comment); } try writer.writeAll("}"); if (i < struct_decl.fields.len - 1) try writer.writeAll(", "); } try writer.writeAll("]"); if (struct_decl.doc_comment) |doc| { try writer.writeAll(", \"doc\": "); try self.writeString(writer, doc); } try writer.writeAll("}"); } fn serializeUnion(self: *JsonSerializer, writer: anytype, union_decl: patterns.UnionDecl) !void { try writer.writeAll("{\"name\": "); try self.writeString(writer, union_decl.name); try writer.writeAll(", \"fields\": ["); for (union_decl.fields, 0..) |field, i| { try writer.writeAll("{\"name\": "); try self.writeString(writer, field.name); try writer.writeAll(", \"type\": "); try self.writeString(writer, field.type_name); if (field.comment) |comment| { try writer.writeAll(", \"comment\": "); try self.writeString(writer, comment); } try writer.writeAll("}"); if (i < union_decl.fields.len - 1) try writer.writeAll(", "); } try writer.writeAll("]"); if (union_decl.doc_comment) |doc| { try writer.writeAll(", \"doc\": "); try self.writeString(writer, doc); } try writer.writeAll("}"); } fn serializeFlag(self: *JsonSerializer, writer: anytype, flag: patterns.FlagDecl) !void { try writer.writeAll("{\"name\": "); try self.writeString(writer, flag.name); try writer.writeAll(", \"underlying_type\": "); try self.writeString(writer, flag.underlying_type); try writer.writeAll(", \"values\": ["); for (flag.flags, 0..) |value, i| { try writer.writeAll("{\"name\": "); try self.writeString(writer, value.name); try writer.writeAll(", \"value\": "); try self.writeString(writer, value.value); if (value.comment) |comment| { try writer.writeAll(", \"comment\": "); try self.writeString(writer, comment); } try writer.writeAll("}"); if (i < flag.flags.len - 1) try writer.writeAll(", "); } try writer.writeAll("]"); if (flag.doc_comment) |doc| { try writer.writeAll(", \"doc\": "); try self.writeString(writer, doc); } try writer.writeAll("}"); } fn serializeFunction(self: *JsonSerializer, writer: anytype, func: patterns.FunctionDecl) !void { try writer.writeAll("{\"name\": "); try self.writeString(writer, func.name); try writer.writeAll(", \"return_type\": "); try self.writeString(writer, func.return_type); try writer.writeAll(", \"parameters\": ["); for (func.params, 0..) |param, i| { try writer.writeAll("{\"name\": "); try self.writeString(writer, param.name); try writer.writeAll(", \"type\": "); try self.writeString(writer, param.type_name); try writer.writeAll("}"); if (i < func.params.len - 1) try writer.writeAll(", "); } try writer.writeAll("]"); if (func.doc_comment) |doc| { try writer.writeAll(", \"doc\": "); try self.writeString(writer, doc); } try writer.writeAll("}"); } fn writeString(self: *JsonSerializer, writer: anytype, str: []const u8) !void { _ = self; try writer.writeAll("\""); for (str) |c| { switch (c) { '"' => try writer.writeAll("\\\""), '\\' => try writer.writeAll("\\\\"), '\n' => try writer.writeAll("\\n"), '\r' => try writer.writeAll("\\r"), '\t' => try writer.writeAll("\\t"), else => try writer.writeByte(c), } } try writer.writeAll("\""); } };