commit c78365ba35656a6efb422077bed76f9c8c7059fa
parent a985ef99872f458e3eacbb1eb1674e1dec098d11
Author: Christian Ermann <christianermann@gmail.com>
Date: Sun, 1 Mar 2026 12:35:09 -0800
Render zig code
Diffstat:
| M | src/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);
+ }
}