diff --git a/generator/generator.zig b/generator/generator.zig index 7bd7ec0..cb9caec 100644 --- a/generator/generator.zig +++ b/generator/generator.zig @@ -24,12 +24,14 @@ fn cmpFeatureLevels(a: FeatureLevel, b: FeatureLevel) std.math.Order { const DeclarationResolver = struct { const DeclarationSet = std.StringHashMap(void); const EnumExtensionMap = std.StringHashMap(std.ArrayList(reg.Enum.Field)); + const FieldMap = std.StringHashMap(reg.Enum.Value); allocator: *Allocator, reg_arena: *Allocator, registry: *reg.Registry, declarations: DeclarationSet, enum_extensions: EnumExtensionMap, + field_map: FieldMap, fn init(allocator: *Allocator, reg_arena: *Allocator, registry: *reg.Registry) DeclarationResolver { return .{ @@ -38,6 +40,7 @@ const DeclarationResolver = struct { .registry = registry, .declarations = DeclarationSet.init(allocator), .enum_extensions = EnumExtensionMap.init(allocator), + .field_map = FieldMap.init(allocator), }; } @@ -47,6 +50,7 @@ const DeclarationResolver = struct { kv.value.deinit(); } + self.field_map.deinit(); self.enum_extensions.deinit(); self.declarations.deinit(); } @@ -78,22 +82,20 @@ const DeclarationResolver = struct { // If there are no extensions for this enum, assume its valid. const extensions = self.enum_extensions.get(name) orelse return; - // Todo: cache this in DeclarationResolver - var field_map = std.StringHashMap(reg.Enum.Value).init(self.allocator); - defer field_map.deinit(); + self.field_map.clear(); for (base_enum.fields) |field| { - _ = try field_map.put(field.name, field.value); + _ = try self.field_map.put(field.name, field.value); } // Assume that if a field name clobbers, the value is the same for (extensions.value.items) |field| { - _ = try field_map.put(field.name, field.value); + _ = try self.field_map.put(field.name, field.value); } - const new_fields = try self.reg_arena.alloc(reg.Enum.Field, field_map.count()); + const new_fields = try self.reg_arena.alloc(reg.Enum.Field, self.field_map.count()); - var it = field_map.iterator(); + var it = self.field_map.iterator(); for (new_fields) |*field| { const kv = it.next().?; field.* = .{ diff --git a/generator/registry.zig b/generator/registry.zig index 0d5bbd3..1ed1cdc 100644 --- a/generator/registry.zig +++ b/generator/registry.zig @@ -8,7 +8,28 @@ pub const Registry = struct { pub const Declaration = struct { name: []const u8, - decl_type: TypeInfo, + decl_type: DeclarationType, +}; + +pub const DeclarationType = union(enum) { + container: Container, + enumeration: Enum, + bitmask: Bitmask, + handle: Handle, + command: Command, + alias: Alias, + foreign: Foreign, + typedef: TypeInfo, +}; + +pub const Alias = struct { + pub const Target = enum { + other_command, + other_type, + }; + + name: []const u8, + target: Target, }; pub const ApiConstant = struct { @@ -27,16 +48,11 @@ pub const Tag = struct { }; pub const TypeInfo = union(enum) { - container: Container, - enumeration: Enum, - bitmask: Bitmask, - handle: Handle, - command: Command, - alias: []const u8, // Alias of another declaration + name: []const u8, + command_ptr: Command, pointer: Pointer, array: Array, opaque, - foreign: Foreign }; pub const Container = struct { diff --git a/generator/registry/c-parse.zig b/generator/registry/c-parse.zig index 91fad1c..3dc0143 100644 --- a/generator/registry/c-parse.zig +++ b/generator/registry/c-parse.zig @@ -229,7 +229,7 @@ pub fn parseTypedef(allocator: *Allocator, xctok: *XmlCTokenizer) !registry.Decl return registry.Declaration{ .name = decl.name orelse return error.MissingTypeIdentifier, - .decl_type = decl.decl_type, + .decl_type = .{.typedef = decl.decl_type}, }; } @@ -268,7 +268,7 @@ pub fn parseParamOrProto(allocator: *Allocator, xctok: *XmlCTokenizer) !registry } return registry.Declaration{ .name = decl.name orelse return error.MissingTypeIdentifier, - .decl_type = decl.decl_type, + .decl_type = .{.typedef = decl.decl_type}, }; } @@ -307,7 +307,7 @@ fn parseDeclaration(allocator: *Allocator, xctok: *XmlCTokenizer) ParseError!Dec if (tok.id != .type_name and tok.id != .id) return error.InvalidSyntax; const type_name = tok.text; - var type_info = TypeInfo{.alias = type_name}; + var type_info = TypeInfo{.name = type_name}; // Parse pointers type_info = try parsePointers(allocator, xctok, inner_is_const, type_info); @@ -366,32 +366,24 @@ fn parseFnPtrSuffix(allocator: *Allocator, xctok: *XmlCTokenizer, return_type: T _ = try xctok.expect(.rparen); _ = try xctok.expect(.lparen); - const command = try allocator.create(registry.TypeInfo); - command.* = .{ - .command = .{ - .params = &[_]registry.Command.Param{}, - .return_type = try allocator.create(TypeInfo), - .success_codes = &[_][]const u8{}, - .error_codes = &[_][]const u8{}, - } - }; + const return_type_heap = try allocator.create(TypeInfo); + return_type_heap.* = return_type; - command.command.return_type.* = return_type; - const command_ptr = Declaration{ + var command_ptr = Declaration{ .name = name.text, .decl_type = .{ - .pointer = .{ - .is_const = true, - .is_optional = false, - .size = .one, - .child = command, + .command_ptr = .{ + .params = &[_]registry.Command.Param{}, + .return_type = return_type_heap, + .success_codes = &[_][]const u8{}, + .error_codes = &[_][]const u8{}, } - }, + } }; const first_param = try parseDeclaration(allocator, xctok); if (first_param.name == null) { - if (first_param.decl_type != .alias or !mem.eql(u8, first_param.decl_type.alias, "void")) { + if (first_param.decl_type != .name or !mem.eql(u8, first_param.decl_type.name, "void")) { return error.InvalidSyntax; } @@ -423,7 +415,7 @@ fn parseFnPtrSuffix(allocator: *Allocator, xctok: *XmlCTokenizer, return_type: T } _ = try xctok.nextNoEof(); - command.command.params = params.toOwnedSlice(); + command_ptr.decl_type.command_ptr.params = params.toOwnedSlice(); return command_ptr; } diff --git a/generator/registry/parse.zig b/generator/registry/parse.zig index a3a2a8c..6904512 100644 --- a/generator/registry/parse.zig +++ b/generator/registry/parse.zig @@ -103,7 +103,7 @@ fn parseBitmaskType(ty: *xml.Element) !registry.Declaration { const alias = ty.getAttribute("alias") orelse return error.InvalidRegistry; return registry.Declaration{ .name = name, - .decl_type = .{.alias = alias}, + .decl_type = .{.alias = .{.name = alias, .target = .other_type}}, }; } else { return registry.Declaration{ @@ -119,7 +119,7 @@ fn parseHandleType(ty: *xml.Element) !registry.Declaration { const alias = ty.getAttribute("alias") orelse return error.InvalidRegistry; return registry.Declaration{ .name = name, - .decl_type = .{.alias = alias}, + .decl_type = .{.alias = .{.name = alias, .target = .other_type}}, }; } else { const name = ty.getCharData("name") orelse return error.InvalidRegistry; @@ -151,7 +151,7 @@ fn parseBaseType(allocator: *Allocator, ty: *xml.Element) !registry.Declaration // macros, which is why this part is not built into the xml/c parser. return registry.Declaration{ .name = name, - .decl_type = .{.opaque = {}}, + .decl_type = .{.typedef = .{.opaque = {}}}, }; } } @@ -162,7 +162,7 @@ fn parseContainer(allocator: *Allocator, ty: *xml.Element, is_union: bool) !regi if (ty.getAttribute("alias")) |alias| { return registry.Declaration{ .name = name, - .decl_type = .{.alias = alias}, + .decl_type = .{.alias = .{.name = alias, .target = .other_type}}, }; } @@ -345,7 +345,7 @@ fn parseCommand(allocator: *Allocator, elem: *xml.Element) !registry.Declaration const name = elem.getAttribute("name") orelse return error.InvalidRegistry; return registry.Declaration{ .name = name, - .decl_type = .{.alias = alias} + .decl_type = .{.alias = .{.name = alias, .target = .other_command}} }; } @@ -360,13 +360,13 @@ fn parseCommand(allocator: *Allocator, elem: *xml.Element) !registry.Declaration while (it.next()) |param| { var xctok = xmlc.XmlCTokenizer.init(param); const decl = try xmlc.parseParamOrProto(allocator, &xctok); - params[i] = .{.name = decl.name, .param_type = decl.decl_type}; + params[i] = .{.name = decl.name, .param_type = decl.decl_type.typedef}; try parsePointerMeta(¶ms[i].param_type, param); i += 1; } const return_type = try allocator.create(registry.TypeInfo); - return_type.* = command_decl.decl_type; + return_type.* = command_decl.decl_type.typedef; const success_codes = if (elem.getAttribute("successcodes")) |codes| try splitCommaAlloc(allocator, codes)