forked from mirror/vulkan-zig
Enum parsing
This commit is contained in:
@@ -12,7 +12,7 @@ pub const Declaration = struct {
|
|||||||
pub const ApiConstant = struct {
|
pub const ApiConstant = struct {
|
||||||
pub const Value = union(enum) {
|
pub const Value = union(enum) {
|
||||||
expr: []const u8,
|
expr: []const u8,
|
||||||
alias: []const u8,
|
alias: []const u8, // Alias of another API constant
|
||||||
};
|
};
|
||||||
|
|
||||||
name: []const u8,
|
name: []const u8,
|
||||||
@@ -50,9 +50,12 @@ pub const Container = struct {
|
|||||||
pub const Enum = struct {
|
pub const Enum = struct {
|
||||||
pub const Value = union(enum) {
|
pub const Value = union(enum) {
|
||||||
bitpos: u5, // 1 << bitpos
|
bitpos: u5, // 1 << bitpos
|
||||||
bitvector: u32, // Combined flags
|
bit_vector: i32, // Combined flags & some vendor IDs
|
||||||
int: i32,
|
int: i32,
|
||||||
alias: []const u8,
|
alias: struct {
|
||||||
|
alias_name: []const u8,
|
||||||
|
is_compat_alias: bool,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Field = struct {
|
pub const Field = struct {
|
||||||
@@ -61,7 +64,7 @@ pub const Enum = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fields: []Field,
|
fields: []Field,
|
||||||
is_bitmask_bits: bool,
|
is_bitmask: bool,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Bitmask = struct {
|
pub const Bitmask = struct {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ const mem = std.mem;
|
|||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||||
|
|
||||||
|
const api_constants_name = "API Constants";
|
||||||
|
|
||||||
pub const ParseResult = struct {
|
pub const ParseResult = struct {
|
||||||
arena: ArenaAllocator,
|
arena: ArenaAllocator,
|
||||||
registry: registry.Registry,
|
registry: registry.Registry,
|
||||||
@@ -14,18 +16,17 @@ pub const ParseResult = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parseXml(allocator: *Allocator, root: *xml.Element) !ParseResult {
|
pub fn parseXml(backing_allocator: *Allocator, root: *xml.Element) !ParseResult {
|
||||||
var arena = ArenaAllocator.init(allocator);
|
var arena = ArenaAllocator.init(backing_allocator);
|
||||||
errdefer arena.deinit();
|
errdefer arena.deinit();
|
||||||
|
|
||||||
var reg = registry.Registry{
|
const allocator = &arena.allocator;
|
||||||
.decls = &[_]registry.Declaration{},
|
|
||||||
.api_constants = &[_]registry.ApiConstant{},
|
|
||||||
.tags = &[_]registry.Tag{},
|
|
||||||
};
|
|
||||||
|
|
||||||
reg.api_constants = try parseApiConstants(&arena.allocator, root);
|
var reg = registry.Registry{
|
||||||
reg.tags = try parseTags(&arena.allocator, root);
|
.decls = try parseDeclarations(allocator, root),
|
||||||
|
.api_constants = try parseApiConstants(allocator, root),
|
||||||
|
.tags = try parseTags(allocator, root),
|
||||||
|
};
|
||||||
|
|
||||||
return ParseResult{
|
return ParseResult{
|
||||||
.arena = arena,
|
.arena = arena,
|
||||||
@@ -33,12 +34,117 @@ pub fn parseXml(allocator: *Allocator, root: *xml.Element) !ParseResult {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parseDeclarations(allocator: *Allocator, root: *xml.Element) ![]registry.Declaration {
|
||||||
|
var types_elem = root.findChildByTag("types") orelse return error.InvalidRegistry;
|
||||||
|
var commands_elem = root.findChildByTag("commands") orelse return error.InvalidRegistry;
|
||||||
|
|
||||||
|
const decl_upper_bound = types_elem.children.count() + commands_elem.children.count();
|
||||||
|
const decls = try allocator.alloc(registry.Declaration, decl_upper_bound);
|
||||||
|
errdefer allocator.free(decls);
|
||||||
|
|
||||||
|
var count: usize = 0;
|
||||||
|
count += try parseTypes(allocator, decls, types_elem);
|
||||||
|
count += try parseEnums(allocator, decls[count..], root);
|
||||||
|
count += try parseCommands(allocator, decls[count..], commands_elem);
|
||||||
|
return allocator.shrink(decls, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseTypes(allocator: *Allocator, out: []registry.Declaration, types_elem: *xml.Element) !usize {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseEnums(allocator: *Allocator, out: []registry.Declaration, root: *xml.Element) !usize {
|
||||||
|
var i: usize = 0;
|
||||||
|
var it = root.findChildrenByTag("enums");
|
||||||
|
while (it.next()) |enums| {
|
||||||
|
const name = enums.getAttribute("name") orelse return error.InvalidRegistry;
|
||||||
|
if (mem.eql(u8, name, api_constants_name)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
out[i] = .{
|
||||||
|
.name = name,
|
||||||
|
.decl_type = .{.Enum = try parseEnumFields(allocator, enums)},
|
||||||
|
};
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseEnumFields(allocator: *Allocator, elem: *xml.Element) !registry.Enum {
|
||||||
|
// TODO: `type` was added recently, fall back to checking endswith FlagBits for older versions?
|
||||||
|
const enum_type = elem.getAttribute("type") orelse return error.InvalidRegistry;
|
||||||
|
const is_bitmask = mem.eql(u8, enum_type, "bitmask");
|
||||||
|
if (!is_bitmask and !mem.eql(u8, enum_type, "enum")) {
|
||||||
|
return error.InvalidRegistry;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fields = try allocator.alloc(registry.Enum.Field, elem.children.count());
|
||||||
|
errdefer allocator.free(fields);
|
||||||
|
|
||||||
|
var i: usize = 0;
|
||||||
|
var it = elem.findChildrenByTag("enum");
|
||||||
|
while (it.next()) |field| {
|
||||||
|
fields[i] = try parseEnumField(field);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return registry.Enum{
|
||||||
|
.fields = allocator.shrink(fields, i),
|
||||||
|
.is_bitmask = is_bitmask,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseEnumField(field: *xml.Element) !registry.Enum.Field {
|
||||||
|
const is_compat_alias = if (field.getAttribute("comment")) |comment|
|
||||||
|
mem.eql(u8, comment, "Backwards-compatible alias containing a typo") or
|
||||||
|
mem.eql(u8, comment, "Deprecated name for backwards compatibility")
|
||||||
|
else
|
||||||
|
false;
|
||||||
|
|
||||||
|
const name = field.getAttribute("name") orelse return error.InvalidRegistry;
|
||||||
|
const value: registry.Enum.Value = blk: {
|
||||||
|
// An enum variant's value could be defined by any of the following attributes:
|
||||||
|
// - value: Straight up value of the enum variant, in either base 10 or 16 (prefixed with 0x).
|
||||||
|
// - bitpos: Used for bitmasks, and can also be set in extensions.
|
||||||
|
// - alias: The field is an alias of another variant within the same enum.
|
||||||
|
// - offset: Used with features and extensions, where a non-bitpos value is added to an enum.
|
||||||
|
// The value is given by `1e9 + (extr_nr - 1) * 1e3 + offset`, where `ext_nr` is either
|
||||||
|
// given by the `extnumber` field (in the case of a feature), or given in the parent <extension>
|
||||||
|
// tag. In the latter case its passed via the `ext_nr` parameter.
|
||||||
|
// TODO: Handle `offset` elsewhere
|
||||||
|
if (field.getAttribute("value")) |value| {
|
||||||
|
if (mem.startsWith(u8, value, "0x")) {
|
||||||
|
break :blk .{.bit_vector = try std.fmt.parseInt(i32, value[2..], 16)};
|
||||||
|
} else {
|
||||||
|
break :blk .{.int = try std.fmt.parseInt(i32, value, 10)};
|
||||||
|
}
|
||||||
|
} else if (field.getAttribute("bitpos")) |bitpos| {
|
||||||
|
break :blk .{.bitpos = try std.fmt.parseInt(u5, bitpos, 10)};
|
||||||
|
} else if (field.getAttribute("alias")) |alias| {
|
||||||
|
break :blk .{.alias = .{.alias_name = alias, .is_compat_alias = is_compat_alias}};
|
||||||
|
} else {
|
||||||
|
return error.InvalidRegistry;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return registry.Enum.Field{
|
||||||
|
.name = name,
|
||||||
|
.value = value,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parseCommands(allocator: *Allocator, out: []registry.Declaration, commmands_elem: *xml.Element) !usize {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
fn parseApiConstants(allocator: *Allocator, root: *xml.Element) ![]registry.ApiConstant {
|
fn parseApiConstants(allocator: *Allocator, root: *xml.Element) ![]registry.ApiConstant {
|
||||||
var enums = blk: {
|
var enums = blk: {
|
||||||
var it = root.elements();
|
var it = root.findChildrenByTag("enums");
|
||||||
while (it.next()) |child| {
|
while (it.next()) |child| {
|
||||||
const name = child.getAttribute("name") orelse continue;
|
const name = child.getAttribute("name") orelse continue;
|
||||||
if (mem.eql(u8, name, "API Constants")) {
|
if (mem.eql(u8, name, api_constants_name)) {
|
||||||
break :blk child;
|
break :blk child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,7 +152,7 @@ fn parseApiConstants(allocator: *Allocator, root: *xml.Element) ![]registry.ApiC
|
|||||||
return error.InvalidRegistry;
|
return error.InvalidRegistry;
|
||||||
};
|
};
|
||||||
|
|
||||||
var constants = try allocator.alloc(registry.ApiConstant, enums.children.count());
|
const constants = try allocator.alloc(registry.ApiConstant, enums.children.count());
|
||||||
errdefer allocator.free(constants);
|
errdefer allocator.free(constants);
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
@@ -72,7 +178,7 @@ fn parseApiConstants(allocator: *Allocator, root: *xml.Element) ![]registry.ApiC
|
|||||||
|
|
||||||
fn parseTags(allocator: *Allocator, root: *xml.Element) ![]registry.Tag {
|
fn parseTags(allocator: *Allocator, root: *xml.Element) ![]registry.Tag {
|
||||||
var tags_elem = root.findChildByTag("tags") orelse return error.InvalidRegistry;
|
var tags_elem = root.findChildByTag("tags") orelse return error.InvalidRegistry;
|
||||||
var tags = try allocator.alloc(registry.Tag, tags_elem.children.count());
|
const tags = try allocator.alloc(registry.Tag, tags_elem.children.count());
|
||||||
errdefer allocator.free(tags);
|
errdefer allocator.free(tags);
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user