zig-webgpu-gen

git clone git://git.electrosoup.com/zig-webgpu-gen
Log | Files | Refs

commit c78365ba35656a6efb422077bed76f9c8c7059fa
parent a985ef99872f458e3eacbb1eb1674e1dec098d11
Author: Christian Ermann <christianermann@gmail.com>
Date:   Sun,  1 Mar 2026 12:35:09 -0800

Render zig code

Diffstat:
Msrc/main.zig | 271++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
1 file changed, 235 insertions(+), 36 deletions(-)

diff --git a/src/main.zig b/src/main.zig @@ -17,11 +17,17 @@ const Api = struct { objects: []Object, }; - const Value64 = union(enum) { int: u64, float: f64, + pub fn render(self: Value64, writer: anytype) !void { + switch (self) { + .int => |val| try writer.print("{d}", .{ val }), + .float => |val| try writer.print("{d}", .{ val }), + } + } + pub fn jsonParse( allocator: std.mem.Allocator, source: anytype, @@ -83,6 +89,40 @@ const PrimitiveType = enum { @"array<int32>", @"array<float32>", @"array<float64>", + + fn toString(self: PrimitiveType) []const u8 { + return switch (self) { + .c_void => "c_void", + .bool => "bool", + .nullable_string => "?[]const u8", + .string_with_default_empty => "[]const u8", + .out_string => "[]u8", + .uint16 => "u16", + .uint32 => "u32", + .uint64 => "u64", + .usize => "usize", + .int16 => "i16", + .int32 => "i32", + .float32 => "f32", + .nullable_float32 => "f32", + .float64 => "f64", + .float64_supertype => "f64", + .@"array<bool>" => "[]bool", + .@"array<string>" => "[][]const u8", + .@"array<uint16>" => "[]u16", + .@"array<uint32>" => "[]u32", + .@"array<uint64>" => "[]u64", + .@"array<usize>" => "[]usize", + .@"array<int16>" => "[]i16", + .@"array<int32>" => "[]i32", + .@"array<float32>" => "[]f32", + .@"array<float64>" => "[]f64", + }; + } + + pub fn render(self: PrimitiveType, writer: anytype) !void { + try writer.writeAll(self.toString()); + } }; const ComplexType = union(enum) { @@ -103,6 +143,18 @@ const ComplexType = union(enum) { name: []const u8, }; + pub fn render(self: ComplexType, writer: anytype) !void { + switch (self) { + .single => |single| { + try snakeToPascal(single.name, writer); + }, + .array => |array| { + try writer.writeAll("[]"); + try snakeToPascal(array.name, writer); + }, + } + } + pub fn parse(raw: []const u8) ?ComplexType { var array = false; var type_str = raw; @@ -154,6 +206,11 @@ const ComplexType = union(enum) { const CallbackType = struct { name: []const u8, + pub fn render(self: CallbackType, writer: anytype) !void { + try writer.writeAll("callback."); + try writer.writeAll(self.name); + } + pub fn parse(raw: []const u8) ?CallbackType { if (!std.mem.startsWith(u8, raw, "callback.")) { return null; @@ -189,29 +246,37 @@ const Type = union(enum) { complex: ComplexType, callback: CallbackType, + pub fn render(self: Type, writer: anytype) !void { + return switch (self) { + .primitive => |inner| inner.render(writer), + .complex => |inner| inner.render(writer), + .callback => |inner| inner.render(writer), + }; + } + pub fn jsonParse( allocator: std.mem.Allocator, source: anytype, options: std.json.ParseOptions, ) !Type { - _ = allocator; _ = options; - const token = try source.next(); - return switch (token) { - .string => |inner| { + const token = try source.nextAlloc(allocator, .alloc_if_needed); + switch (token) { + .string, .allocated_string => |inner| { if (std.meta.stringToEnum(PrimitiveType, inner)) |val| { return .{ .primitive = val }; } if (ComplexType.parse(inner)) |val| { return .{ .complex = val }; - } else {} + } if (CallbackType.parse(inner)) |val| { return .{ .callback = val }; } return error.UnexpectedToken; }, - else => error.UnexpectedToken, - }; + else => return error.UnexpectedToken, + } + return .{ .primitive = .c_void }; } }; @@ -260,11 +325,16 @@ const DefaultValue = union(enum) { const ParameterType = struct { name: []const u8, doc: []const u8, - type: []const u8, + type: Type, passed_with_ownership: ?bool = null, pointer: ?Pointer = null, optional: ?bool = null, default: ?DefaultValue = null, + + fn render(self: ParameterType, writer: anytype) !void { + try writer.print("{s}: ", .{ self.name }); + try self.type.render(writer); + } }; const TypeDef = struct { @@ -279,6 +349,12 @@ const Constant = struct { namespace: ?[]const u8 = null, value: Value64, doc: []const u8, + + pub fn render(self: Constant, writer: anytype) !void { + try writer.print("pub const {s} = ", .{ self.name }); + try self.value.render(writer); + try writer.writeAll(";\n"); + } }; const Enum = struct { @@ -287,6 +363,20 @@ const Enum = struct { doc: []const u8, extended: ?bool = null, entries: []const ?EnumEntry, + + fn render(self: Enum, writer: anytype) !void { + try writer.writeAll("pub const "); + try formatEnumName(self.name, writer); + try writer.writeAll(" = enum(u32) {\n"); + for (self.entries, 0..) |maybe_entry, i| { + if (maybe_entry) |entry| { + try writer.writeAll(" "); + try formatEnumField(entry.name, writer); + try writer.print(" = {d},\n", .{ i }); + } + } + try writer.writeAll("};\n"); + } }; const EnumEntry = struct { @@ -302,6 +392,18 @@ const BitFlag = struct { doc: []const u8, extended: ?bool = null, entries: []const ?BitFlagEntry, + + pub fn render(self: BitFlag, writer: anytype) !void { + try writer.writeAll("pub const "); + try formatEnumName(self.name, writer); + try writer.writeAll(" = packed struct(u64) {\n"); + for (self.entries) |maybe_entry| { + if (maybe_entry) |entry| { + try writer.print(" {s}: bool = false\n", .{ entry.name }); + } + } + try writer.writeAll("};\n"); + } }; const BitFlagEntry = struct { @@ -320,6 +422,20 @@ const Struct = struct { extends: ?[][]const u8 = null, free_members: ?bool = null, members: ?[]ParameterType = null, + + fn render(self: Struct, writer: anytype) !void { + try writer.writeAll("pub const "); + try formatEnumName(self.name, writer); + try writer.writeAll(" = extern struct {\n"); + if (self.members) |members| { + for (members) |member| { + try writer.writeAll(" "); + try member.render(writer); + try writer.writeAll(",\n"); + } + } + try writer.writeAll("};\n"); + } }; const Callback = struct { @@ -328,6 +444,20 @@ const Callback = struct { doc: []const u8, style: CallbackStyle, args: ?[]ParameterType = null, + + pub fn render(self: Callback, writer: anytype) !void { + try writer.writeAll("pub const "); + try snakeToPascal(self.name, writer); + try writer.writeAll("Callback = fn (\n"); + if (self.args) |args| { + for (args) |arg| { + try writer.writeAll(" "); + try arg.render(writer); + try writer.writeAll(",\n"); + } + } + try writer.writeAll(") callconv(.C) void;\n"); + } }; const ReturnType = struct { @@ -336,6 +466,10 @@ const ReturnType = struct { optional: ?bool = null, passed_with_ownership: ?bool = null, pointer: ?Pointer = null, + + pub fn render(self: ReturnType, writer: anytype) !void { + try self.type.render(writer); + } }; const Function = struct { @@ -345,6 +479,27 @@ const Function = struct { returns: ?ReturnType = null, callback: ?CallbackType = null, args: ?[]ParameterType = null, + + pub fn render(self: Function, writer: anytype) !void { + try writer.writeAll("pub fn "); + try snakeToCamel(self.name, writer); + try writer.writeAll("(\n"); + if (self.args) |args| { + for (args) |arg| { + try writer.writeAll(" "); + try arg.render(writer); + try writer.writeAll(",\n"); + } + } + try writer.writeAll(") "); + if (self.returns) |returns| { + try returns.render(writer); + } else { + try writer.writeAll("void"); + } + try writer.writeAll(" {\n"); + try writer.writeAll("}\n"); + } }; const Object = struct { @@ -353,8 +508,45 @@ const Object = struct { doc: []const u8, extended: ?bool = null, methods: []Function, + + pub fn render(self: Object, writer: anytype) !void { + for (self.methods) |method| { + try method.render(writer); + try writer.writeAll("\n"); + } + } }; +fn snakeToPascal(str: []const u8, writer: anytype) !void { + var it = std.mem.splitScalar(u8, str, '_'); + while (it.next()) |token| { + try writer.writeByte(std.ascii.toUpper(token[0])); + try writer.writeAll(token[1..]); + } +} + +fn snakeToCamel(str: []const u8, writer: anytype) !void { + var it = std.mem.splitScalar(u8, str, '_'); + if (it.next()) |token| { + try writer.writeAll(token); + } + while (it.next()) |token| { + try writer.writeByte(std.ascii.toUpper(token[0])); + try writer.writeAll(token[1..]); + } +} + +fn formatEnumName(str: []const u8, writer: anytype) !void { + return snakeToPascal(str, writer); +} + +fn formatEnumField(str: []const u8, writer: anytype) !void { + for (str) |anycase| { + const lowercase = std.ascii.toLower(anycase); + try writer.writeByte(lowercase); + } +} + pub fn main() !void { var gpa = std.heap.GeneralPurposeAllocator(.{}){}; const allocator = gpa.allocator(); @@ -375,33 +567,40 @@ pub fn main() !void { ); defer parsed.deinit(); - std.debug.print("{s}\n", .{"constants"}); - for (parsed.value.constants) |entry| { - std.debug.print(" {s}\n", .{entry.name}); - switch (entry.value) { - .int => |val| std.debug.print(" = {d}\n", .{val}), - .float => |val| std.debug.print(" = {d}\n", .{val}), - } - } + const stdout = std.io.getStdOut().writer(); - //std.debug.print("{s}\n", .{"enums"}); - //for (parsed.value.enums) |entry| { - // std.debug.print(" {s}\n", .{entry.name}); - // for (entry.entries) |value| { - // if (value) |val| { - // std.debug.print(" - {s}\n", .{val.name}); - // } else { - // std.debug.print(" - {s}\n", .{"null"}); - // } - // } - //} - - //std.debug.print("{s}\n", .{"bitflags"}); - //for (parsed.value.bitflags) |entry| { - // std.debug.print(" {s}\n", .{entry.name}); - // for (entry.entries) |flag| { - // std.debug.print(" - {s}\n", .{flag.name}); - // } - //} + try stdout.writeAll("// constants\n"); + for (parsed.value.constants) |constant| { + try constant.render(stdout); + } + try stdout.writeAll("// enums\n"); + for (parsed.value.enums) |entry| { + try entry.render(stdout); + try stdout.writeAll("\n"); + } + try stdout.writeAll("// bitflags\n"); + for (parsed.value.bitflags) |bitflag| { + try bitflag.render(stdout); + try stdout.writeAll("\n"); + } + try stdout.writeAll("// structs\n"); + for (parsed.value.structs) |obj| { + try obj.render(stdout); + try stdout.writeAll("\n"); + } + try stdout.writeAll("// callbacks\n"); + for (parsed.value.callbacks) |callback| { + try callback.render(stdout); + try stdout.writeAll("\n"); + } + try stdout.writeAll("// functions\n"); + for (parsed.value.functions) |function| { + try function.render(stdout); + try stdout.writeAll("\n"); + } + try stdout.writeAll("// methods\n"); + for (parsed.value.objects) |object| { + try object.render(stdout); + } }