forked from mirror/vulkan-zig
Api constant rendering
This commit is contained in:
@@ -139,7 +139,9 @@ const DeclarationResolver = struct {
|
|||||||
var write_index: usize = 0;
|
var write_index: usize = 0;
|
||||||
while (read_index < self.registry.decls.len) {
|
while (read_index < self.registry.decls.len) {
|
||||||
const decl = self.registry.decls[read_index];
|
const decl = self.registry.decls[read_index];
|
||||||
if (decl.decl_type == .foreign or self.declarations.contains(decl.name)) {
|
const is_required = self.declarations.contains(decl.name);
|
||||||
|
const is_empty_enum = decl.decl_type == .enumeration and decl.decl_type.enumeration.fields.len == 0;
|
||||||
|
if (decl.decl_type == .foreign or (is_required and !is_empty_enum)) {
|
||||||
self.registry.decls[write_index] = decl;
|
self.registry.decls[write_index] = decl;
|
||||||
write_index += 1;
|
write_index += 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,5 +138,3 @@ test "main" {
|
|||||||
_ = @import("xml.zig");
|
_ = @import("xml.zig");
|
||||||
_ = @import("registry/c-parse.zig");
|
_ = @import("registry/c-parse.zig");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Fix not all struct fields being marked as optional properly.
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const testing = std.testing;
|
|||||||
const ArraySize = registry.Array.ArraySize;
|
const ArraySize = registry.Array.ArraySize;
|
||||||
const TypeInfo = registry.TypeInfo;
|
const TypeInfo = registry.TypeInfo;
|
||||||
|
|
||||||
const Token = struct {
|
pub const Token = struct {
|
||||||
id: Id,
|
id: Id,
|
||||||
text: []const u8,
|
text: []const u8,
|
||||||
|
|
||||||
@@ -21,6 +21,9 @@ const Token = struct {
|
|||||||
comma,
|
comma,
|
||||||
semicolon,
|
semicolon,
|
||||||
colon,
|
colon,
|
||||||
|
minus,
|
||||||
|
tilde,
|
||||||
|
dot,
|
||||||
lparen,
|
lparen,
|
||||||
rparen,
|
rparen,
|
||||||
lbracket,
|
lbracket,
|
||||||
@@ -32,7 +35,7 @@ const Token = struct {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const CTokenizer = struct {
|
pub const CTokenizer = struct {
|
||||||
source: []const u8,
|
source: []const u8,
|
||||||
offset: usize = 0,
|
offset: usize = 0,
|
||||||
|
|
||||||
@@ -100,7 +103,7 @@ const CTokenizer = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next(self: *CTokenizer) !?Token {
|
pub fn next(self: *CTokenizer) !?Token {
|
||||||
while (true) {
|
while (true) {
|
||||||
switch (self.peek() orelse return null) {
|
switch (self.peek() orelse return null) {
|
||||||
' ', '\t', '\n', '\r' => _ = self.consumeNoEof(),
|
' ', '\t', '\n', '\r' => _ = self.consumeNoEof(),
|
||||||
@@ -117,6 +120,9 @@ const CTokenizer = struct {
|
|||||||
',' => id = .comma,
|
',' => id = .comma,
|
||||||
';' => id = .semicolon,
|
';' => id = .semicolon,
|
||||||
':' => id = .colon,
|
':' => id = .colon,
|
||||||
|
'-' => id = .minus,
|
||||||
|
'~' => id = .tilde,
|
||||||
|
'.' => id = .dot,
|
||||||
'[' => id = .lbracket,
|
'[' => id = .lbracket,
|
||||||
']' => id = .rbracket,
|
']' => id = .rbracket,
|
||||||
'(' => id = .lparen,
|
'(' => id = .lparen,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const registry = @import("../registry.zig");
|
const registry = @import("../registry.zig");
|
||||||
const xml = @import("../xml.zig");
|
const xml = @import("../xml.zig");
|
||||||
const xmlc = @import("c-parse.zig");
|
const cparse = @import("c-parse.zig");
|
||||||
const mem = std.mem;
|
const mem = std.mem;
|
||||||
const Allocator = mem.Allocator;
|
const Allocator = mem.Allocator;
|
||||||
const ArenaAllocator = std.heap.ArenaAllocator;
|
const ArenaAllocator = std.heap.ArenaAllocator;
|
||||||
@@ -144,8 +144,8 @@ fn parseHandleType(ty: *xml.Element) !registry.Declaration {
|
|||||||
fn parseBaseType(allocator: *Allocator, ty: *xml.Element) !registry.Declaration {
|
fn parseBaseType(allocator: *Allocator, ty: *xml.Element) !registry.Declaration {
|
||||||
const name = ty.getCharData("name") orelse return error.InvalidRegistry;
|
const name = ty.getCharData("name") orelse return error.InvalidRegistry;
|
||||||
if (ty.getCharData("type")) |_| {
|
if (ty.getCharData("type")) |_| {
|
||||||
var tok = xmlc.XmlCTokenizer.init(ty);
|
var tok = cparse.XmlCTokenizer.init(ty);
|
||||||
return try xmlc.parseTypedef(allocator, &tok);
|
return try cparse.parseTypedef(allocator, &tok);
|
||||||
} else {
|
} else {
|
||||||
// Either ANativeWindow, AHardwareBuffer or CAMetalLayer. The latter has a lot of
|
// Either ANativeWindow, AHardwareBuffer or CAMetalLayer. The latter has a lot of
|
||||||
// macros, which is why this part is not built into the xml/c parser.
|
// macros, which is why this part is not built into the xml/c parser.
|
||||||
@@ -171,8 +171,8 @@ fn parseContainer(allocator: *Allocator, ty: *xml.Element, is_union: bool) !regi
|
|||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var it = ty.findChildrenByTag("member");
|
var it = ty.findChildrenByTag("member");
|
||||||
while (it.next()) |member| {
|
while (it.next()) |member| {
|
||||||
var xctok = xmlc.XmlCTokenizer.init(member);
|
var xctok = cparse.XmlCTokenizer.init(member);
|
||||||
members[i] = try xmlc.parseMember(allocator, &xctok);
|
members[i] = try cparse.parseMember(allocator, &xctok);
|
||||||
try parsePointerMeta(&members[i].field_type, member);
|
try parsePointerMeta(&members[i].field_type, member);
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
@@ -189,8 +189,8 @@ fn parseContainer(allocator: *Allocator, ty: *xml.Element, is_union: bool) !regi
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parseFuncPointer(allocator: *Allocator, ty: *xml.Element) !registry.Declaration {
|
fn parseFuncPointer(allocator: *Allocator, ty: *xml.Element) !registry.Declaration {
|
||||||
var xctok = xmlc.XmlCTokenizer.init(ty);
|
var xctok = cparse.XmlCTokenizer.init(ty);
|
||||||
return try xmlc.parseTypedef(allocator, &xctok);
|
return try cparse.parseTypedef(allocator, &xctok);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lenToPointerSize(len: []const u8) registry.Pointer.PointerSize {
|
fn lenToPointerSize(len: []const u8) registry.Pointer.PointerSize {
|
||||||
@@ -362,16 +362,16 @@ fn parseCommand(allocator: *Allocator, elem: *xml.Element) !registry.Declaration
|
|||||||
}
|
}
|
||||||
|
|
||||||
const proto = elem.findChildByTag("proto") orelse return error.InvalidRegistry;
|
const proto = elem.findChildByTag("proto") orelse return error.InvalidRegistry;
|
||||||
var proto_xctok = xmlc.XmlCTokenizer.init(proto);
|
var proto_xctok = cparse.XmlCTokenizer.init(proto);
|
||||||
const command_decl = try xmlc.parseParamOrProto(allocator, &proto_xctok);
|
const command_decl = try cparse.parseParamOrProto(allocator, &proto_xctok);
|
||||||
|
|
||||||
var params = try allocator.alloc(registry.Command.Param, elem.children.count());
|
var params = try allocator.alloc(registry.Command.Param, elem.children.count());
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
var it = elem.findChildrenByTag("param");
|
var it = elem.findChildrenByTag("param");
|
||||||
while (it.next()) |param| {
|
while (it.next()) |param| {
|
||||||
var xctok = xmlc.XmlCTokenizer.init(param);
|
var xctok = cparse.XmlCTokenizer.init(param);
|
||||||
const decl = try xmlc.parseParamOrProto(allocator, &xctok);
|
const decl = try cparse.parseParamOrProto(allocator, &xctok);
|
||||||
params[i] = .{.name = decl.name, .param_type = decl.decl_type.typedef};
|
params[i] = .{.name = decl.name, .param_type = decl.decl_type.typedef};
|
||||||
try parsePointerMeta(¶ms[i].param_type, param);
|
try parsePointerMeta(¶ms[i].param_type, param);
|
||||||
i += 1;
|
i += 1;
|
||||||
|
|||||||
@@ -116,11 +116,81 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
fn render(self: *Self) !void {
|
fn render(self: *Self) !void {
|
||||||
try self.writer.writeAll(preamble);
|
try self.writer.writeAll(preamble);
|
||||||
|
|
||||||
|
for (self.registry.api_constants) |api_constant| {
|
||||||
|
try self.renderApiConstant(api_constant);
|
||||||
|
}
|
||||||
|
|
||||||
for (self.registry.decls) |decl| {
|
for (self.registry.decls) |decl| {
|
||||||
try self.renderDecl(decl);
|
try self.renderDecl(decl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn renderApiConstant(self: *Self, api_constant: reg.ApiConstant) !void {
|
||||||
|
try self.writer.writeAll("const ");
|
||||||
|
try self.writeIdentifier(util.trimVkNamespace(api_constant.name));
|
||||||
|
try self.writer.writeAll(" = ");
|
||||||
|
|
||||||
|
if (api_constant.value == .alias) {
|
||||||
|
try self.writeIdentifier(util.trimVkNamespace(api_constant.value.alias));
|
||||||
|
try self.writer.writeAll(";\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const expr = api_constant.value.expr;
|
||||||
|
const adjusted_expr = if (expr.len > 2 and expr[0] == '(' and expr[expr.len - 1] == ')')
|
||||||
|
expr[1 .. expr.len - 1]
|
||||||
|
else
|
||||||
|
expr;
|
||||||
|
|
||||||
|
var tokenizer = cparse.CTokenizer{.source = adjusted_expr};
|
||||||
|
var peeked: ?cparse.Token = null;
|
||||||
|
while (true) {
|
||||||
|
const tok = peeked orelse (try tokenizer.next()) orelse break;
|
||||||
|
peeked = null;
|
||||||
|
|
||||||
|
switch (tok.id) {
|
||||||
|
.lparen, .rparen, .tilde, .minus, .id => {
|
||||||
|
try self.writer.writeAll(tok.text);
|
||||||
|
continue;
|
||||||
|
},
|
||||||
|
.int => {},
|
||||||
|
else => return error.InvalidApiConstant,
|
||||||
|
}
|
||||||
|
|
||||||
|
const suffix = (try tokenizer.next()) orelse {
|
||||||
|
try self.writer.writeAll(tok.text);
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (suffix.id) {
|
||||||
|
.id => {
|
||||||
|
if (mem.eql(u8, suffix.text, "ULL")) {
|
||||||
|
try self.writer.print("@as(u64, {})", .{tok.text});
|
||||||
|
} else if (mem.eql(u8, suffix.text, "U")) {
|
||||||
|
try self.writer.print("@as(u32, {})", .{tok.text});
|
||||||
|
} else {
|
||||||
|
return error.InvalidApiConstant;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.dot => {
|
||||||
|
const decimal = (try tokenizer.next()) orelse return error.InvalidConstantExpr;
|
||||||
|
|
||||||
|
try self.writer.print("@as(f32, {}.{})", .{tok.text, decimal.text});
|
||||||
|
const f = (try tokenizer.next()) orelse return error.InvalidConstantExpr;
|
||||||
|
if (f.id != .id or !mem.eql(u8, f.text, "f")) {
|
||||||
|
return error.InvalidApiConstant;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
else => {
|
||||||
|
try self.writer.writeAll(tok.text);
|
||||||
|
peeked = suffix;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try self.writer.writeAll(";\n");
|
||||||
|
}
|
||||||
|
|
||||||
fn renderTypeInfo(self: *Self, type_info: reg.TypeInfo) RenderTypeInfoError!void {
|
fn renderTypeInfo(self: *Self, type_info: reg.TypeInfo) RenderTypeInfoError!void {
|
||||||
switch (type_info) {
|
switch (type_info) {
|
||||||
.name => |name| try self.renderTypeName(name),
|
.name => |name| try self.renderTypeName(name),
|
||||||
@@ -192,7 +262,7 @@ fn Renderer(comptime WriterType: type) type {
|
|||||||
try self.writer.writeByte('[');
|
try self.writer.writeByte('[');
|
||||||
switch (array.size) {
|
switch (array.size) {
|
||||||
.int => |size| try self.writer.print("{}", .{size}),
|
.int => |size| try self.writer.print("{}", .{size}),
|
||||||
.alias => |alias| try self.writeIdentifier(alias[3..]), //TODO: Check proper VK_ prefix
|
.alias => |alias| try self.writeIdentifier(util.trimVkNamespace(alias)),
|
||||||
}
|
}
|
||||||
try self.writer.writeByte(']');
|
try self.writer.writeByte(']');
|
||||||
try self.renderTypeInfo(array.child.*);
|
try self.renderTypeInfo(array.child.*);
|
||||||
|
|||||||
Reference in New Issue
Block a user