From dee6a07f3b1c6be9d91cea92f44be4734f938fee Mon Sep 17 00:00:00 2001 From: sin-ack Date: Sat, 14 Sep 2024 12:57:19 +0000 Subject: [PATCH 1/3] Update std.builtin.Type field names for new conventions --- extensions/glib2.zig | 42 +++++++++++----------- extensions/gobject2.zig | 80 ++++++++++++++++++++--------------------- extensions/gtk4.zig | 8 ++--- src/main.zig | 2 +- src/translate.zig | 4 +-- src/zig_writer.zig | 4 +-- 6 files changed, 70 insertions(+), 70 deletions(-) diff --git a/extensions/glib2.zig b/extensions/glib2.zig index fb2ee1b..13436a3 100644 --- a/extensions/glib2.zig +++ b/extensions/glib2.zig @@ -20,8 +20,8 @@ pub inline fn new(comptime T: type, value: T) *T { /// Destroys a value created using `create`. pub fn destroy(ptr: anytype) void { const type_info = @typeInfo(@TypeOf(ptr)); - if (type_info != .Pointer or type_info.Pointer.size != .One) @compileError("must be a single-item pointer"); - glib.freeSized(@ptrCast(ptr), @sizeOf(type_info.Pointer.child)); + if (type_info != .pointer or type_info.pointer.size != .One) @compileError("must be a single-item pointer"); + glib.freeSized(@ptrCast(ptr), @sizeOf(type_info.pointer.child)); } /// Heap allocates a slice of `n` values of type `T` using `glib.mallocN`. `T` @@ -36,8 +36,8 @@ pub fn alloc(comptime T: type, n: usize) []T { /// Frees a slice created using `alloc`. pub fn free(ptr: anytype) void { const type_info = @typeInfo(@TypeOf(ptr)); - if (type_info != .Pointer or type_info.Pointer.size != .Slice) @compileError("must be a slice"); - glib.freeSized(@ptrCast(ptr.ptr), @sizeOf(type_info.Pointer.child) * ptr.len); + if (type_info != .pointer or type_info.pointer.size != .Slice) @compileError("must be a slice"); + glib.freeSized(@ptrCast(ptr.ptr), @sizeOf(type_info.pointer.child) * ptr.len); } pub const Bytes = struct { @@ -91,8 +91,8 @@ pub const Variant = struct { child.* = newFrom(item); } return glib.Variant.newArray(child_type, &children, children.len); - } else if (type_info == .Pointer and type_info.Pointer.size == .Slice) { - const child_type = glib.ext.VariantType.newFor(type_info.Pointer.child); + } else if (type_info == .pointer and type_info.pointer.size == .Slice) { + const child_type = glib.ext.VariantType.newFor(type_info.pointer.child); defer child_type.free(); const children = alloc(*glib.Variant, contents.len); defer free(children); @@ -100,8 +100,8 @@ pub const Variant = struct { child.* = newFrom(item); } return glib.Variant.newArray(child_type, children.ptr, children.len); - } else if (type_info == .Optional) { - const child_type = glib.ext.VariantType.newFor(type_info.Optional.child); + } else if (type_info == .optional) { + const child_type = glib.ext.VariantType.newFor(type_info.optional.child); defer child_type.free(); if (contents) |value| { const child = newFrom(value); @@ -109,9 +109,9 @@ pub const Variant = struct { } else { return glib.Variant.newMaybe(child_type, null); } - } else if (type_info == .Struct and type_info.Struct.is_tuple) { - var children: [type_info.Struct.fields.len]*glib.Variant = undefined; - inline for (type_info.Struct.fields, &children) |field, *child| { + } else if (type_info == .@"struct" and type_info.@"struct".is_tuple) { + var children: [type_info.@"struct".fields.len]*glib.Variant = undefined; + inline for (type_info.@"struct".fields, &children) |field, *child| { child.* = newFrom(@field(contents, field.name)); } return glib.Variant.newTuple(&children, children.len); @@ -153,14 +153,14 @@ pub const VariantType = struct { } else if (T == *glib.Variant) { return "v"; } else if (type_info == .Array) { - return "a" ++ stringFor(type_info.Array.child); - } else if (type_info == .Pointer and type_info.Pointer.size == .Slice) { - return "a" ++ stringFor(type_info.Pointer.child); - } else if (type_info == .Optional) { - return "m" ++ stringFor(type_info.Optional.child); - } else if (type_info == .Struct and type_info.Struct.is_tuple) { + return "a" ++ stringFor(type_info.array.child); + } else if (type_info == .pointer and type_info.pointer.size == .Slice) { + return "a" ++ stringFor(type_info.pointer.child); + } else if (type_info == .optional) { + return "m" ++ stringFor(type_info.optional.child); + } else if (type_info == .@"struct" and type_info.@"struct".is_tuple) { comptime var str: [:0]const u8 = "("; - inline for (type_info.Struct.fields) |field| { + inline for (type_info.@"struct".fields) |field| { str = str ++ comptime stringFor(field.type); } return str ++ ")"; @@ -172,12 +172,12 @@ pub const VariantType = struct { fn isCString(comptime T: type) bool { return switch (@typeInfo(T)) { - .Pointer => |info| switch (info.size) { + .pointer => |info| switch (info.size) { .One => switch (@typeInfo(info.child)) { - .Array => |child| child.child == u8 and std.meta.sentinel(info.child) == @as(u8, 0), + .array => |child| child.child == u8 and std.meta.sentinel(info.child) == @as(u8, 0), else => false, }, - .Many, .Slice => info.child == u8 and std.meta.sentinel(T) == @as(u8, 0), + .many, .slice => info.child == u8 and std.meta.sentinel(T) == @as(u8, 0), else => false, }, else => false, diff --git a/extensions/gobject2.zig b/extensions/gobject2.zig index 90379a1..c83c1d2 100644 --- a/extensions/gobject2.zig +++ b/extensions/gobject2.zig @@ -173,7 +173,7 @@ pub fn defineClass( comptime options: DefineClassOptions(Instance), ) fn () callconv(.C) gobject.Type { const instance_info = @typeInfo(Instance); - if (instance_info != .Struct or instance_info.Struct.layout != .@"extern") { + if (instance_info != .@"struct" or instance_info.@"struct".layout != .@"extern") { @compileError("an instance type must be an extern struct"); } @@ -181,10 +181,10 @@ pub fn defineClass( @compileError("a class type must have a declaration named Parent pointing to the parent type"); } const parent_info = @typeInfo(Instance.Parent); - if (parent_info != .Struct or parent_info.Struct.layout != .@"extern" or !@hasDecl(Instance.Parent, "getGObjectType")) { + if (parent_info != .@"struct" or parent_info.@"struct".layout != .@"extern" or !@hasDecl(Instance.Parent, "getGObjectType")) { @compileError("the defined parent type " ++ @typeName(Instance.Parent) ++ " does not appear to be a GObject class type"); } - if (instance_info.Struct.fields.len == 0 or instance_info.Struct.fields[0].type != Instance.Parent) { + if (instance_info.@"struct".fields.len == 0 or instance_info.@"struct".fields[0].type != Instance.Parent) { @compileError("the first field of the instance struct must have type " ++ @typeName(Instance.Parent)); } @@ -192,13 +192,13 @@ pub fn defineClass( @compileError("a class type must have a member named Class pointing to the class record"); } const class_info = @typeInfo(Instance.Class); - if (class_info != .Struct or class_info.Struct.layout != .@"extern") { + if (class_info != .@"struct" or class_info.@"struct".layout != .@"extern") { @compileError("a class type must be an extern struct"); } if (!@hasDecl(Instance.Class, "Instance") or Instance.Class.Instance != Instance) { @compileError("a class type must have a declaration named Instance pointing to the instance type"); } - if (class_info.Struct.fields.len == 0 or class_info.Struct.fields[0].type != Instance.Parent.Class) { + if (class_info.@"struct".fields.len == 0 or class_info.@"struct".fields[0].type != Instance.Parent.Class) { @compileError("the first field of the class struct must have type " ++ @typeName(Instance.Parent.Class)); } @@ -338,16 +338,16 @@ pub fn defineEnum( comptime options: DefineEnumOptions, ) fn () callconv(.C) gobject.Type { const enum_info = @typeInfo(Enum); - if (enum_info != .Enum or enum_info.Enum.tag_type != c_int) { + if (enum_info != .@"enum" or enum_info.@"enum".tag_type != c_int) { @compileError("an enum type must have a tag type of c_int"); } - if (!enum_info.Enum.is_exhaustive) { + if (!enum_info.@"enum".is_exhaustive) { @compileError("an enum type must be exhaustive"); } - const n_values = enum_info.Enum.fields.len; - var enum_values: [n_values + 1]gobject.EnumValue = undefined; - for (enum_info.Enum.fields, enum_values[0..n_values]) |field, *value| { + const n_values = enum_info.@"enum".fields.len; + var enum_values: [n_values + 1]gobject.enum_value = undefined; + for (enum_info.@"enum".fields, enum_values[0..n_values]) |field, *value| { value.* = .{ .value = field.value, .value_name = field.name, @@ -394,12 +394,12 @@ pub fn defineFlags( comptime options: DefineFlagsOptions, ) fn () callconv(.C) gobject.Type { const flags_info = @typeInfo(Flags); - if (flags_info != .Struct or flags_info.Struct.layout != .@"packed" or flags_info.Struct.backing_integer != c_uint) { + if (flags_info != .@"struct" or flags_info.@"struct".layout != .@"packed" or flags_info.@"struct".backing_integer != c_uint) { @compileError("a flags type must have a backing integer type of c_uint"); } comptime var n_values = 0; - for (flags_info.Struct.fields) |field| { + for (flags_info.@"struct".fields) |field| { if (!std.mem.startsWith(u8, field.name, "_")) { if (@bitSizeOf(field.type) != 1) { @compileError("non-padding flags field " ++ field.name ++ " must be 1 bit"); @@ -409,7 +409,7 @@ pub fn defineFlags( } comptime var flags_values: [n_values + 1]gobject.FlagsValue = undefined; var current_value = 0; - for (flags_info.Struct.fields) |field| { + for (flags_info.@"struct".fields) |field| { if (!std.mem.startsWith(u8, field.name, "_")) { flags_values[current_value] = .{ .value = 1 << @bitOffsetOf(Flags, field.name), @@ -458,7 +458,7 @@ pub fn Accessor(comptime Owner: type, comptime Data: type) type { } fn FieldType(comptime T: type, comptime name: []const u8) type { - return for (@typeInfo(T).Struct.fields) |field| { + return for (@typeInfo(T).@"struct".fields) |field| { if (std.mem.eql(u8, field.name, name)) break field.type; } else @compileError("no field named " ++ name ++ " in " ++ @typeName(T)); } @@ -698,7 +698,7 @@ pub fn defineProperty( ); } else if (std.meta.hasFn(Data, "getGObjectType")) { return switch (@typeInfo(Data)) { - .Enum => gobject.paramSpecEnum( + .@"enum" => gobject.paramSpecEnum( name, options.nick orelse null, options.blurb orelse null, @@ -706,7 +706,7 @@ pub fn defineProperty( @intFromEnum(options.default), flags, ), - .Struct => gobject.paramSpecFlags( + .@"struct" => gobject.paramSpecFlags( name, options.nick orelse null, options.blurb orelse null, @@ -752,7 +752,7 @@ pub fn defineProperty( /// The properties passed in `properties` should be the structs returned by /// `defineProperty`. pub fn registerProperties(class: anytype, properties: []const type) void { - const Instance = @typeInfo(@TypeOf(class)).Pointer.child.Instance; + const Instance = @typeInfo(@TypeOf(class)).pointer.child.Instance; gobject.Object.virtual_methods.get_property.implement(class, struct { fn getProperty(object: *Instance, id: c_uint, value: *gobject.Value, _: *gobject.ParamSpec) callconv(.C) void { inline for (properties, 1..) |property, i| { @@ -810,10 +810,10 @@ pub fn defineSignal( comptime param_types: []const type, comptime ReturnType: type, ) type { - const EmitParams = @Type(.{ .Struct = .{ + const EmitParams = @Type(.{ .@"struct" = .{ .layout = .auto, .fields = fields: { - var fields: [param_types.len]std.builtin.Type.StructField = undefined; + var fields: [param_types.len]std.builtin.Type.struct_field = undefined; for (param_types, &fields, 0..) |ParamType, *field, i| { field.* = .{ .name = std.fmt.comptimePrint("{}", .{i}), @@ -878,7 +878,7 @@ pub fn defineSignal( pub fn connect( target: anytype, comptime T: type, - callback: SignalHandler(@typeInfo(@TypeOf(target)).Pointer.child, param_types, T, ReturnType), + callback: SignalHandler(@typeInfo(@TypeOf(target)).pointer.child, param_types, T, ReturnType), data: T, options: struct { after: bool = false, @@ -917,10 +917,10 @@ pub const impl_helpers = struct { /// guaranteed. pub inline fn as(comptime T: type, self: anytype) *T { const self_info = @typeInfo(@TypeOf(self)); - if (self_info != .Pointer or self_info.Pointer.size != .One) { + if (self_info != .pointer or self_info.pointer.size != .One) { @compileError("cannot cast a non-pointer type"); } - const Self = self_info.Pointer.child; + const Self = self_info.pointer.child; if (isAssignableFrom(T, Self)) { return @ptrCast(@alignCast(self)); @@ -979,7 +979,7 @@ pub fn isA(self: anytype, comptime T: type) bool { /// Creates a new instance of an object type with the given properties. pub fn newInstance(comptime T: type, properties: anytype) *T { - const typeInfo = @typeInfo(@TypeOf(properties)).Struct; + const typeInfo = @typeInfo(@TypeOf(properties)).@"struct"; const n_props = typeInfo.fields.len; var names: [n_props][*:0]const u8 = undefined; var values: [n_props]gobject.Value = undefined; @@ -1085,10 +1085,10 @@ pub const Value = struct { } else if (T == f64) { return value.getDouble(); } else if (isCString(T)) { - if (@typeInfo(T) != .Optional) { + if (@typeInfo(T) != .optional) { @compileError("cannot guarantee value is non-null"); } - const Pointer = @typeInfo(@typeInfo(T).Optional.child).Pointer; + const Pointer = @typeInfo(@typeInfo(T).optional.child).pointer; if (!Pointer.is_const) { @compileError("get does not take ownership; can only return const strings"); } @@ -1099,12 +1099,12 @@ pub const Value = struct { }; } else if (std.meta.hasFn(T, "getGObjectType")) { return switch (@typeInfo(T)) { - .Enum => @enumFromInt(value.getEnum()), - .Struct => @bitCast(value.getFlags()), + .@"enum" => @enumFromInt(value.getEnum()), + .@"struct" => @bitCast(value.getFlags()), else => @compileError("cannot extract " ++ @typeName(T) ++ " from Value"), }; } else if (singlePointerChild(T)) |Child| { - if (@typeInfo(T) != .Optional) { + if (@typeInfo(T) != .optional) { @compileError("cannot guarantee value is non-null"); } if (Child == gobject.ParamSpec) { @@ -1156,14 +1156,14 @@ pub const Value = struct { } else if (comptime isCString(T)) { // orelse null as temporary workaround for https://github.com/ziglang/zig/issues/12523 switch (@typeInfo(T)) { - .Pointer => value.setString(contents), - .Optional => value.setString(contents orelse null), + .pointer => value.setString(contents), + .optional => value.setString(contents orelse null), else => unreachable, } } else if (std.meta.hasFn(T, "getGObjectType")) { switch (@typeInfo(T)) { - .Enum => value.setEnum(@intFromEnum(contents)), - .Struct => value.setFlags(@bitCast(contents)), + .@"enum" => value.setEnum(@intFromEnum(contents)), + .@"struct" => value.setFlags(@bitCast(contents)), else => @compileError("cannot construct Value from " ++ @typeName(T)), } } else if (singlePointerChild(T)) |Child| { @@ -1192,18 +1192,18 @@ inline fn isObject(comptime T: type) bool { inline fn isCString(comptime T: type) bool { return switch (@typeInfo(T)) { - .Pointer => |pointer| switch (pointer.size) { + .pointer => |pointer| switch (pointer.size) { .One => switch (@typeInfo(pointer.child)) { - .Array => |child| child.child == u8 and std.meta.sentinel(pointer.child) == @as(u8, 0), + .array => |child| child.child == u8 and std.meta.sentinel(pointer.child) == @as(u8, 0), else => false, }, .Many, .Slice => pointer.child == u8 and std.meta.sentinel(T) == @as(u8, 0), .C => pointer.child == u8, }, - .Optional => |optional| switch (@typeInfo(optional.child)) { - .Pointer => |pointer| switch (pointer.size) { + .optional => |optional| switch (@typeInfo(optional.child)) { + .pointer => |pointer| switch (pointer.size) { .One => switch (@typeInfo(pointer.child)) { - .Array => |child| child.child == u8 and std.meta.sentinel(pointer.child) == @as(u8, 0), + .array => |child| child.child == u8 and std.meta.sentinel(pointer.child) == @as(u8, 0), else => false, }, .Many, .Slice => pointer.child == u8 and std.meta.sentinel(optional.child) == @as(u8, 0), @@ -1217,12 +1217,12 @@ inline fn isCString(comptime T: type) bool { inline fn singlePointerChild(comptime T: type) ?type { return switch (@typeInfo(T)) { - .Pointer => |pointer| switch (pointer.size) { + .pointer => |pointer| switch (pointer.size) { .One, .C => pointer.child, else => null, }, - .Optional => |optional| switch (@typeInfo(optional.child)) { - .Pointer => |pointer| switch (pointer.size) { + .optional => |optional| switch (@typeInfo(optional.child)) { + .pointer => |pointer| switch (pointer.size) { .One => pointer.child, else => null, }, diff --git a/extensions/gtk4.zig b/extensions/gtk4.zig index 10e6227..b46cea7 100644 --- a/extensions/gtk4.zig +++ b/extensions/gtk4.zig @@ -57,17 +57,17 @@ pub const impl_helpers = struct { } fn ensureWidgetType(comptime Container: type, comptime field_name: []const u8) void { - inline for (@typeInfo(Container).Struct.fields) |field| { + inline for (@typeInfo(Container).@"struct".fields) |field| { if (comptime std.mem.eql(u8, field.name, field_name)) { const WidgetType = switch (@typeInfo(field.type)) { - .Pointer => |pointer| widget_type: { + .pointer => |pointer| widget_type: { if (pointer.size != .One) { @compileError("bound child type must be a single pointer"); } break :widget_type pointer.child; }, - .Optional => |optional| switch (@typeInfo(optional.child)) { - .Pointer => |pointer| widget_type: { + .optional => |optional| switch (@typeInfo(optional.child)) { + .pointer => |pointer| widget_type: { if (pointer.size != .One) { @compileError("bound child type must be a single pointer"); } diff --git a/src/main.zig b/src/main.zig index 013bba4..77bd53e 100644 --- a/src/main.zig +++ b/src/main.zig @@ -31,7 +31,7 @@ pub const std_options: std.Options = .{ pub fn logImpl( comptime level: log.Level, - comptime scope: @Type(.EnumLiteral), + comptime scope: @Type(.enum_literal), comptime format: []const u8, args: anytype, ) void { diff --git a/src/translate.zig b/src/translate.zig index d211553..0bbf293 100644 --- a/src/translate.zig +++ b/src/translate.zig @@ -1180,7 +1180,7 @@ fn translateVirtualMethod(allocator: Allocator, virtual_method: gir.VirtualMetho try out.print("pub fn call(p_class: anytype, ", .{}); try translateParameters(allocator, virtual_method.parameters, .{ - .self_type = "@typeInfo(@TypeOf(p_class)).Pointer.child.Instance", + .self_type = "@typeInfo(@TypeOf(p_class)).pointer.child.Instance", .throws = virtual_method.throws, }, ctx, out); try out.print(") ", .{}); @@ -1198,7 +1198,7 @@ fn translateVirtualMethod(allocator: Allocator, virtual_method: gir.VirtualMetho try out.print("pub fn implement(p_class: anytype, p_implementation: ", .{}); try out.print("*const fn (", .{}); try translateParameters(allocator, virtual_method.parameters, .{ - .self_type = "@typeInfo(@TypeOf(p_class)).Pointer.child.Instance", + .self_type = "@typeInfo(@TypeOf(p_class)).pointer.child.Instance", .throws = virtual_method.throws, }, ctx, out); try out.print(") callconv(.C) ", .{}); diff --git a/src/zig_writer.zig b/src/zig_writer.zig index 1fa5ce1..f80e897 100644 --- a/src/zig_writer.zig +++ b/src/zig_writer.zig @@ -29,7 +29,7 @@ pub fn ZigWriter(comptime Writer: type) type { /// made into its own project. pub fn print(w: Self, comptime fmt: []const u8, args: anytype) Error!void { @setEvalBranchQuota(100_000); - const arg_fields = @typeInfo(@TypeOf(args)).Struct.fields; + const arg_fields = @typeInfo(@TypeOf(args)).@"struct".fields; comptime var current_arg = 0; comptime var i = 0; @@ -56,7 +56,7 @@ pub fn ZigWriter(comptime Writer: type) type { 'L' => { const arg = @field(args, arg_fields[current_arg].name); const arg_type_info = @typeInfo(@TypeOf(arg)); - if (arg_type_info == .Pointer and arg_type_info.Pointer.size == .Slice and arg_type_info.Pointer.child == u8) { + if (arg_type_info == .pointer and arg_type_info.pointer.size == .Slice and arg_type_info.pointer.child == u8) { try w.out.print("{s}", .{arg}); } else { try w.out.print("{}", .{arg}); From 2c3a7b88fa9502a341384be55e9fefe2cd568b33 Mon Sep 17 00:00:00 2001 From: sin-ack Date: Sat, 14 Sep 2024 15:52:05 +0000 Subject: [PATCH 2/3] zig_writer: Replace tabs with spaces when outputting Ref: https://github.com/ziglang/zig/pull/20885 --- src/zig_writer.zig | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/zig_writer.zig b/src/zig_writer.zig index f80e897..541760a 100644 --- a/src/zig_writer.zig +++ b/src/zig_writer.zig @@ -57,7 +57,14 @@ pub fn ZigWriter(comptime Writer: type) type { const arg = @field(args, arg_fields[current_arg].name); const arg_type_info = @typeInfo(@TypeOf(arg)); if (arg_type_info == .pointer and arg_type_info.pointer.size == .Slice and arg_type_info.pointer.child == u8) { - try w.out.print("{s}", .{arg}); + for (arg) |char| { + switch (char) { + // Zig is very tab-hostile, so we have to replace tabs with spaces. + // This is most relevant when translating documentation. + '\t' => try w.out.writeAll(" "), + else => try w.out.writeByte(char), + } + } } else { try w.out.print("{}", .{arg}); } From 2134122eb305bd5b19d47845b21483b7ab08f46b Mon Sep 17 00:00:00 2001 From: sin-ack Date: Sat, 14 Sep 2024 16:24:29 +0000 Subject: [PATCH 3/3] translate: Avoid duplicate field/decl names Zig no longer allows field and declaration names within the same decl scope to be the same. This mostly affects bit-fields, where the decls for individual values are now prefixed with "flag_", and classes/records where fields are prefixed with "field_". --- src/translate.zig | 65 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/src/translate.zig b/src/translate.zig index 0bbf293..55bf2d1 100644 --- a/src/translate.zig +++ b/src/translate.zig @@ -590,7 +590,19 @@ fn translateClass(allocator: Allocator, class: gir.Class, ctx: TranslationContex } if (!class.isOpaque()) { - try translateLayoutElements(allocator, class.layout_elements, ctx, out); + var decl_names = try std.ArrayList([]const u8).initCapacity(allocator, class.functions.len + class.constructors.len + class.methods.len); + defer decl_names.deinit(); + for (class.functions) |function| { + decl_names.appendAssumeCapacity(function.name); + } + for (class.constructors) |constructor| { + decl_names.appendAssumeCapacity(constructor.name); + } + for (class.methods) |method| { + decl_names.appendAssumeCapacity(method.name); + } + + try translateLayoutElements(allocator, class.layout_elements, decl_names.items, ctx, out); try out.print("\n", .{}); } @@ -787,7 +799,19 @@ fn translateRecord(allocator: Allocator, record: gir.Record, ctx: TranslationCon try out.print("\n", .{}); if (!record.isOpaque()) { - try translateLayoutElements(allocator, record.layout_elements, ctx, out); + var decl_names = try std.ArrayList([]const u8).initCapacity(allocator, record.functions.len + record.constructors.len + record.methods.len); + defer decl_names.deinit(); + for (record.functions) |function| { + decl_names.appendAssumeCapacity(function.name); + } + for (record.constructors) |constructor| { + decl_names.appendAssumeCapacity(constructor.name); + } + for (record.methods) |method| { + decl_names.appendAssumeCapacity(method.name); + } + + try translateLayoutElements(allocator, record.layout_elements, decl_names.items, ctx, out); try out.print("\n", .{}); } @@ -829,7 +853,19 @@ fn translateUnion(allocator: Allocator, @"union": gir.Union, ctx: TranslationCon try out.print("\n", .{}); if (!@"union".isOpaque()) { - try translateLayoutElements(allocator, @"union".layout_elements, ctx, out); + var decl_names = try std.ArrayList([]const u8).initCapacity(allocator, @"union".functions.len + @"union".constructors.len + @"union".methods.len); + defer decl_names.deinit(); + for (@"union".functions) |function| { + decl_names.appendAssumeCapacity(function.name); + } + for (@"union".constructors) |constructor| { + decl_names.appendAssumeCapacity(constructor.name); + } + for (@"union".methods) |method| { + decl_names.appendAssumeCapacity(method.name); + } + + try translateLayoutElements(allocator, @"union".layout_elements, decl_names.items, ctx, out); try out.print("\n", .{}); } @@ -850,7 +886,7 @@ fn translateUnion(allocator: Allocator, @"union": gir.Union, ctx: TranslationCon try out.print("};\n\n", .{}); } -fn translateLayoutElements(allocator: Allocator, layout_elements: []const gir.LayoutElement, ctx: TranslationContext, out: anytype) !void { +fn translateLayoutElements(allocator: Allocator, layout_elements: []const gir.LayoutElement, decl_names: [][]const u8, ctx: TranslationContext, out: anytype) !void { // This handling of bit fields makes no attempt to be general, so it can // avoid a lot of complexity present for bit fields in general. It only // handles bit fields backed by guint, and it assumes guint is 32 bits. @@ -892,19 +928,30 @@ fn translateLayoutElements(allocator: Allocator, layout_elements: []const gir.La switch (layout_element) { .field => |field| { try translateDocumentation(allocator, field.documentation, ctx, out); - try out.print("$I: ", .{field.name}); + + // NOTE: For duplicate field names, we prepend "field_" to the + // name to avoid name collision between fields and decls. + for (decl_names) |decl_name| { + if (mem.eql(u8, field.name, decl_name)) { + try out.print("field_$L: ", .{field.name}); + break; + } + } else { + try out.print("$I: ", .{field.name}); + } + try translateFieldType(allocator, field.type, ctx, out); try out.print(",\n", .{}); }, .record => |record| { try out.print("anon$L: extern struct {\n", .{n_anon_fields}); - try translateLayoutElements(allocator, record.layout_elements, ctx, out); + try translateLayoutElements(allocator, record.layout_elements, &.{}, ctx, out); try out.print("},\n", .{}); n_anon_fields += 1; }, .@"union" => |@"union"| { try out.print("anon$L: extern union {\n", .{n_anon_fields}); - try translateLayoutElements(allocator, @"union".layout_elements, ctx, out); + try translateLayoutElements(allocator, @"union".layout_elements, &.{}, ctx, out); try out.print("},\n", .{}); n_anon_fields += 1; }, @@ -986,7 +1033,9 @@ fn translateBitField(allocator: Allocator, bit_field: gir.BitField, ctx: Transla defer seen.deinit(); for (bit_field.members) |member| { if (!seen.contains(member.name)) { - try out.print("const $I: $I = @bitCast(@as($L, $L));\n", .{ member.name, name, backing_int, member.value }); + // NOTE: Type-level constants have a "flag_" prefix to avoid name + // collision between fields and decls. + try out.print("const flag_$L: $I = @bitCast(@as($L, $L));\n", .{ member.name, name, backing_int, member.value }); } try seen.put(member.name, {}); }