forked from mirror/vulkan-zig
Struct & union rendering
This commit is contained in:
@@ -152,7 +152,8 @@ pub const Declaration = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const Definition = union(enum) {
|
pub const Definition = union(enum) {
|
||||||
Struct: StructInfo,
|
Struct: ContainerInfo,
|
||||||
|
Union: ContainerInfo,
|
||||||
Enum: EnumInfo,
|
Enum: EnumInfo,
|
||||||
Bitmask: BitmaskInfo,
|
Bitmask: BitmaskInfo,
|
||||||
Handle: HandleInfo,
|
Handle: HandleInfo,
|
||||||
@@ -357,7 +358,7 @@ pub const TypeInfo = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const StructInfo = struct {
|
pub const ContainerInfo = struct {
|
||||||
const Member = struct {
|
const Member = struct {
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
type_info: TypeInfo
|
type_info: TypeInfo
|
||||||
@@ -365,14 +366,14 @@ pub const StructInfo = struct {
|
|||||||
|
|
||||||
members: SegmentedList(Member, 0),
|
members: SegmentedList(Member, 0),
|
||||||
|
|
||||||
fn init(allocator: *Allocator) StructInfo {
|
fn init(allocator: *Allocator) ContainerInfo {
|
||||||
return .{
|
return .{
|
||||||
.members = SegmentedList(Member, 0).init(allocator)
|
.members = SegmentedList(Member, 0).init(allocator)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fromXml(allocator: *Allocator, elem: *xml.Element) StructInfo {
|
fn fromXml(allocator: *Allocator, elem: *xml.Element) ContainerInfo {
|
||||||
var s = StructInfo.init(allocator);
|
var s = ContainerInfo.init(allocator);
|
||||||
|
|
||||||
var members = elem.findChildrenByTag("member");
|
var members = elem.findChildrenByTag("member");
|
||||||
while (members.next()) |member| {
|
while (members.next()) |member| {
|
||||||
@@ -385,7 +386,7 @@ pub const StructInfo = struct {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn addMember(self: *StructInfo, name: []const u8, type_info: TypeInfo) void {
|
fn addMember(self: *ContainerInfo, name: []const u8, type_info: TypeInfo) void {
|
||||||
self.members.push(.{.name = name, .type_info = type_info}) catch unreachable;
|
self.members.push(.{.name = name, .type_info = type_info}) catch unreachable;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -579,7 +580,7 @@ fn processTypes(registry: *Registry, root: *xml.Element) void {
|
|||||||
processEnumType(registry, ty);
|
processEnumType(registry, ty);
|
||||||
} else if (mem.eql(u8, category, "handle")) {
|
} else if (mem.eql(u8, category, "handle")) {
|
||||||
processHandleType(registry, ty);
|
processHandleType(registry, ty);
|
||||||
} else if (mem.eql(u8, category, "struct")) {
|
} else if (mem.eql(u8, category, "struct") or mem.eql(u8, category, "union")) {
|
||||||
processStructType(registry, ty);
|
processStructType(registry, ty);
|
||||||
} else if (mem.eql(u8, category, "funcpointer")) {
|
} else if (mem.eql(u8, category, "funcpointer")) {
|
||||||
processFuncPointerType(registry, ty);
|
processFuncPointerType(registry, ty);
|
||||||
@@ -632,10 +633,12 @@ fn processEnumType(registry: *Registry, ty: *xml.Element) void {
|
|||||||
|
|
||||||
fn processStructType(registry: *Registry, ty: *xml.Element) void {
|
fn processStructType(registry: *Registry, ty: *xml.Element) void {
|
||||||
const name = ty.getAttribute("name").?;
|
const name = ty.getAttribute("name").?;
|
||||||
const def: Definition = if (ty.getAttribute("alias")) |alias|
|
const def = if (ty.getAttribute("alias")) |alias|
|
||||||
.{.Alias = alias}
|
Definition{.Alias = alias}
|
||||||
|
else if (mem.eql(u8, ty.getAttribute("category").?, "union"))
|
||||||
|
Definition{.Union = ContainerInfo.fromXml(®istry.arena.allocator, ty)}
|
||||||
else
|
else
|
||||||
.{.Struct = StructInfo.fromXml(®istry.arena.allocator, ty)};
|
Definition{.Struct = ContainerInfo.fromXml(®istry.arena.allocator, ty)};
|
||||||
|
|
||||||
registry.addDefinition(name, def);
|
registry.addDefinition(name, def);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,9 @@ const foreign_types = [_]ForeignType{
|
|||||||
.{.name = "zx_handle_t", .expr = @typeName(u32)},
|
.{.name = "zx_handle_t", .expr = @typeName(u32)},
|
||||||
.{.name = "GgpStreamDescriptor", .expr = @typeName(u32)}, // TODO: Remove GGP-related code
|
.{.name = "GgpStreamDescriptor", .expr = @typeName(u32)}, // TODO: Remove GGP-related code
|
||||||
.{.name = "GgpFrameToken", .expr = @typeName(u32)},
|
.{.name = "GgpFrameToken", .expr = @typeName(u32)},
|
||||||
|
.{.name = "ANativeWindow", .expr = "@OpaqueType()"},
|
||||||
|
.{.name = "AHardwareBuffer", .expr = "@OpaqueType()"},
|
||||||
|
.{.name = "CAMetalLayer", .expr = "@OpaqueType()"},
|
||||||
};
|
};
|
||||||
|
|
||||||
const foreign_types_namespace = "foreign";
|
const foreign_types_namespace = "foreign";
|
||||||
@@ -71,6 +74,8 @@ fn trimNamespace(name: []const u8) []const u8 {
|
|||||||
return name["vk".len ..];
|
return name["vk".len ..];
|
||||||
} else if (mem.startsWith(u8, name, "Vk")) {
|
} else if (mem.startsWith(u8, name, "Vk")) {
|
||||||
return name["Vk".len ..];
|
return name["Vk".len ..];
|
||||||
|
} else if (mem.startsWith(u8, name, "PFN_vk")) {
|
||||||
|
return name["PFN_vk".len..];
|
||||||
} else {
|
} else {
|
||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
@@ -92,6 +97,7 @@ fn trimTag(registry: *Registry, name: []const u8) []const u8 {
|
|||||||
return mem.trimRight(u8, name[0 .. name.len - tag.name.len], "_");
|
return mem.trimRight(u8, name[0 .. name.len - tag.name.len], "_");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lifted from src-self-hosted/translate_c.zig
|
||||||
fn isValidZigIdentifier(name: []const u8) bool {
|
fn isValidZigIdentifier(name: []const u8) bool {
|
||||||
for (name) |c, i| {
|
for (name) |c, i| {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
@@ -104,8 +110,43 @@ fn isValidZigIdentifier(name: []const u8) bool {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lifted from src-self-hosted/translate_c.zig
|
||||||
|
fn isZigReservedIdentifier(name: []const u8) bool {
|
||||||
|
if (name.len > 1 and (name[0] == 'u' or name[0] == 'i')) {
|
||||||
|
for (name[1..]) |c| {
|
||||||
|
switch (c) {
|
||||||
|
'0'...'9' => {},
|
||||||
|
else => return false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// void is invalid in c so it doesn't need to be checked.
|
||||||
|
return mem.eql(u8, name, "comptime_float") or
|
||||||
|
mem.eql(u8, name, "comptime_int") or
|
||||||
|
mem.eql(u8, name, "bool") or
|
||||||
|
mem.eql(u8, name, "isize") or
|
||||||
|
mem.eql(u8, name, "usize") or
|
||||||
|
mem.eql(u8, name, "f16") or
|
||||||
|
mem.eql(u8, name, "f32") or
|
||||||
|
mem.eql(u8, name, "f64") or
|
||||||
|
mem.eql(u8, name, "f128") or
|
||||||
|
mem.eql(u8, name, "c_longdouble") or
|
||||||
|
mem.eql(u8, name, "noreturn") or
|
||||||
|
mem.eql(u8, name, "type") or
|
||||||
|
mem.eql(u8, name, "anyerror") or
|
||||||
|
mem.eql(u8, name, "c_short") or
|
||||||
|
mem.eql(u8, name, "c_ushort") or
|
||||||
|
mem.eql(u8, name, "c_int") or
|
||||||
|
mem.eql(u8, name, "c_uint") or
|
||||||
|
mem.eql(u8, name, "c_long") or
|
||||||
|
mem.eql(u8, name, "c_ulong") or
|
||||||
|
mem.eql(u8, name, "c_longlong") or
|
||||||
|
mem.eql(u8, name, "c_ulonglong");
|
||||||
|
}
|
||||||
|
|
||||||
fn writeIdentifier(out: var, name: []const u8) !void {
|
fn writeIdentifier(out: var, name: []const u8) !void {
|
||||||
if (!isValidZigIdentifier(name) or std.zig.Token.getKeyword(name) != null) {
|
if (!isValidZigIdentifier(name) or isZigReservedIdentifier(name) or std.zig.Token.getKeyword(name) != null) {
|
||||||
try out.print("@\"{}\"", .{name});
|
try out.print("@\"{}\"", .{name});
|
||||||
} else {
|
} else {
|
||||||
try out.write(name);
|
try out.write(name);
|
||||||
@@ -275,8 +316,15 @@ fn renderDeclarations(out: var, registry: *Registry) !void {
|
|||||||
|
|
||||||
switch (decl.definition) {
|
switch (decl.definition) {
|
||||||
.Enum => |*info| try renderEnum(out, decl.name, info),
|
.Enum => |*info| try renderEnum(out, decl.name, info),
|
||||||
.Alias => |alias| try renderAlias(out, registry, decl.name, alias),
|
// .Alias => |alias| try renderAlias(out, registry, decl.name, alias),
|
||||||
.FnPtr => |*info| try renderFnPtr(out, registry, decl.name, info),
|
.FnPtr => |*info| try renderFnPtr(out, registry, decl.name, info),
|
||||||
|
.Struct => |*info| try renderContainer(out, registry, .Struct, decl.name, info),
|
||||||
|
.Union => |*info| try renderContainer(out, registry, .Union, decl.name, info),
|
||||||
|
.BaseType => |type_info| {
|
||||||
|
try writeConstAssignmemt(out, trimNamespace(decl.name));
|
||||||
|
try renderTypeInfo(out, registry, type_info);
|
||||||
|
try out.write(";\n\n");
|
||||||
|
},
|
||||||
else => {}
|
else => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -348,8 +396,7 @@ fn renderAlias(out: var, registry: *Registry, name: []const u8, alias: []const u
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn renderFnPtr(out: var, registry: *Registry, name: []const u8, info: *reg.CommandInfo) !void {
|
fn renderFnPtr(out: var, registry: *Registry, name: []const u8, info: *reg.CommandInfo) !void {
|
||||||
std.debug.assert(mem.startsWith(u8, name, "PFN_vk"));
|
try writeConstAssignmemt(out, trimNamespace(name));
|
||||||
try writeConstAssignmemt(out, name["PFN_vk".len .. ]);
|
|
||||||
try out.write("extern fn(");
|
try out.write("extern fn(");
|
||||||
|
|
||||||
if (info.parameters.count() > 0) {
|
if (info.parameters.count() > 0) {
|
||||||
@@ -369,10 +416,30 @@ fn renderFnPtr(out: var, registry: *Registry, name: []const u8, info: *reg.Comma
|
|||||||
try out.write(";\n\n");
|
try out.write(";\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn renderContainer(out: var, registry: *Registry, kind: enum{Struct, Union}, name: []const u8, info: *reg.ContainerInfo) !void {
|
||||||
|
try writeConstAssignmemt(out, trimNamespace(name));
|
||||||
|
|
||||||
|
switch (kind) {
|
||||||
|
.Struct => try out.write("extern struct {\n"),
|
||||||
|
.Union => try out.write("extern union {\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
var it = info.members.iterator(0);
|
||||||
|
while (it.next()) |member| {
|
||||||
|
try out.write(base_indent);
|
||||||
|
try writeIdentifier(out, member.name);
|
||||||
|
try out.write(": ");
|
||||||
|
try renderTypeInfo(out, registry, member.type_info);
|
||||||
|
try out.write(",\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
try out.write("};\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
fn renderTest(out: var) !void {
|
fn renderTest(out: var) !void {
|
||||||
try out.write(
|
try out.write(
|
||||||
\\test "Semantic analysis" {
|
\\test "Semantic analysis" {
|
||||||
\\ @import("std").meta.refAllDecls(@This());
|
\\ std.meta.refAllDecls(@This());
|
||||||
\\}
|
\\}
|
||||||
\\
|
\\
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user