forked from mirror/vulkan-zig
Zig 0.6.0 compat; More vulkan compat
This commit is contained in:
@@ -9,14 +9,14 @@ pub fn main() !void {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const file = try std.fs.cwd().openFileC(std.os.argv[1], .{});
|
const file = try std.fs.cwd().openFileZ(std.os.argv[1], .{});
|
||||||
defer file.close();
|
defer file.close();
|
||||||
|
|
||||||
const size = try file.seekableStream().stream.getEndPos();
|
const size = try file.seekableStream().getEndPos();
|
||||||
const source = try std.heap.page_allocator.alloc(u8, size);
|
const source = try std.heap.page_allocator.alloc(u8, size);
|
||||||
defer std.heap.page_allocator.free(source);
|
defer std.heap.page_allocator.free(source);
|
||||||
|
|
||||||
_ = try file.inStream().stream.read(source);
|
_ = try file.inStream().read(source);
|
||||||
|
|
||||||
const spec = try xml.parse(std.heap.page_allocator, source);
|
const spec = try xml.parse(std.heap.page_allocator, source);
|
||||||
defer spec.deinit();
|
defer spec.deinit();
|
||||||
@@ -27,7 +27,7 @@ pub fn main() !void {
|
|||||||
|
|
||||||
const stdout_file = std.io.getStdOut();
|
const stdout_file = std.io.getStdOut();
|
||||||
var stdout = stdout_file.outStream();
|
var stdout = stdout_file.outStream();
|
||||||
try vk_render(&stdout.stream, registry);
|
try vk_render(stdout, registry);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "main" {
|
test "main" {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ pub const Registry = struct {
|
|||||||
return registry;
|
return registry;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deinit(self: Registry) void {
|
pub fn deinit(self: Registry) void {
|
||||||
self.declarations_by_name.deinit();
|
self.declarations_by_name.deinit();
|
||||||
|
|
||||||
// Copy to stack so that the arena doesn't destroy itself
|
// Copy to stack so that the arena doesn't destroy itself
|
||||||
@@ -212,7 +212,7 @@ pub const TypeInfo = struct {
|
|||||||
|
|
||||||
// Read the sizes of each pointer
|
// Read the sizes of each pointer
|
||||||
if (elem.getAttribute("len")) |lens| {
|
if (elem.getAttribute("len")) |lens| {
|
||||||
var len_it = std.mem.separate(lens, ",");
|
var len_it = std.mem.split(lens, ",");
|
||||||
for (type_info.pointers) |*ptr, i| {
|
for (type_info.pointers) |*ptr, i| {
|
||||||
ptr.size = if (len_it.next()) |len| lenToPointerSize(len) else .One;
|
ptr.size = if (len_it.next()) |len| lenToPointerSize(len) else .One;
|
||||||
}
|
}
|
||||||
@@ -307,7 +307,7 @@ pub const TypeInfo = struct {
|
|||||||
// while the others are in the `post`.
|
// while the others are in the `post`.
|
||||||
|
|
||||||
// Check the outer pointers
|
// Check the outer pointers
|
||||||
var const_it = std.mem.separate(post, "*");
|
var const_it = std.mem.split(post, "*");
|
||||||
var i: usize = self.pointers.len;
|
var i: usize = self.pointers.len;
|
||||||
while (i > 0) {
|
while (i > 0) {
|
||||||
i -= 1;
|
i -= 1;
|
||||||
@@ -344,7 +344,11 @@ pub const TypeInfo = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try output(context, self.name);
|
if (self.name) |name| {
|
||||||
|
try output(context, self.name);
|
||||||
|
} else {
|
||||||
|
try output(context, "@Type(.Opaque)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lenToPointerSize(len: []const u8) PointerSize {
|
fn lenToPointerSize(len: []const u8) PointerSize {
|
||||||
@@ -463,7 +467,7 @@ pub const CommandInfo = struct {
|
|||||||
const ncodes = 1 + count(text, ',');
|
const ncodes = 1 + count(text, ',');
|
||||||
const codes = allocator.alloc([]const u8, ncodes) catch unreachable;
|
const codes = allocator.alloc([]const u8, ncodes) catch unreachable;
|
||||||
|
|
||||||
var it = mem.separate(text, ",");
|
var it = mem.split(text, ",");
|
||||||
|
|
||||||
for (codes) |*code, i| {
|
for (codes) |*code, i| {
|
||||||
code.* = it.next().?;
|
code.* = it.next().?;
|
||||||
@@ -650,7 +654,18 @@ fn processFuncPointerType(registry: *Registry, ty: *xml.Element) void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn processBaseType(registry: *Registry, ty: *xml.Element) void {
|
fn processBaseType(registry: *Registry, ty: *xml.Element) void {
|
||||||
|
const special_names = [_][]const u8{ // handled in render.zig
|
||||||
|
"ANativeWindow",
|
||||||
|
"AHardwareBuffer",
|
||||||
|
"CAMetalLayer"
|
||||||
|
};
|
||||||
|
|
||||||
const name = ty.getCharData("name").?;
|
const name = ty.getCharData("name").?;
|
||||||
|
|
||||||
|
for (special_names) |special| {
|
||||||
|
if (mem.eql(u8, name, special)) return;
|
||||||
|
}
|
||||||
|
|
||||||
const type_info = TypeInfo.fromXml(®istry.arena.allocator, ty);
|
const type_info = TypeInfo.fromXml(®istry.arena.allocator, ty);
|
||||||
registry.addDefinition(name, .{.BaseType = type_info});
|
registry.addDefinition(name, .{.BaseType = type_info});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ const ForeignType = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const foreign_types = [_]ForeignType{
|
const foreign_types = [_]ForeignType{
|
||||||
.{.name = "Display", .expr = "@OpaqueType()"},
|
.{.name = "Display", .expr = "Type(.Opaque)"},
|
||||||
.{.name = "VisualID", .expr = @typeName(c_uint)},
|
.{.name = "VisualID", .expr = @typeName(c_uint)},
|
||||||
.{.name = "Window", .expr = @typeName(c_ulong)},
|
.{.name = "Window", .expr = @typeName(c_ulong)},
|
||||||
.{.name = "RROutput", .expr = @typeName(c_ulong)},
|
.{.name = "RROutput", .expr = @typeName(c_ulong)},
|
||||||
.{.name = "wl_display", .expr = "@OpaqueType()"},
|
.{.name = "wl_display", .expr = "@Type(.Opaque)"},
|
||||||
.{.name = "wl_surface", .expr = "@OpaqueType()"},
|
.{.name = "wl_surface", .expr = "@Type(.Opaque)"},
|
||||||
.{.name = "HINSTANCE", .expr = "std.os.HINSTANCE"},
|
.{.name = "HINSTANCE", .expr = "std.os.HINSTANCE"},
|
||||||
.{.name = "HWND", .expr = "*@OpaqueType()"},
|
.{.name = "HWND", .expr = "*@OpaqueType()"},
|
||||||
.{.name = "HMONITOR", .expr = "*OpaqueType()"},
|
.{.name = "HMONITOR", .expr = "*OpaqueType()"},
|
||||||
@@ -32,9 +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 = "ANativeWindow", .expr = "@Type(.Opaque)"},
|
||||||
.{.name = "AHardwareBuffer", .expr = "@OpaqueType()"},
|
.{.name = "AHardwareBuffer", .expr = "@Type(.Opaque)"},
|
||||||
.{.name = "CAMetalLayer", .expr = "@OpaqueType()"},
|
.{.name = "CAMetalLayer", .expr = "@Type(.Opaque)"},
|
||||||
};
|
};
|
||||||
|
|
||||||
const foreign_types_namespace = "foreign";
|
const foreign_types_namespace = "foreign";
|
||||||
@@ -59,10 +59,10 @@ const builtin_types = [_]BuiltinType{
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub fn render(out: var, registry: *Registry) !void {
|
pub fn render(out: var, registry: *Registry) !void {
|
||||||
try out.write("const std = @import(\"std\");\n\n");
|
try out.writeAll("const std = @import(\"std\");\n\n");
|
||||||
try renderApiConstants(out, registry);
|
try renderApiConstants(out, registry);
|
||||||
try renderForeignTypes(out);
|
try renderForeignTypes(out);
|
||||||
try out.write("\n");
|
try out.writeAll("\n");
|
||||||
try renderDeclarations(out, registry);
|
try renderDeclarations(out, registry);
|
||||||
try renderTest(out);
|
try renderTest(out);
|
||||||
}
|
}
|
||||||
@@ -140,14 +140,14 @@ fn writeIdentifier(out: var, name: []const u8) !void {
|
|||||||
if (!isValidZigIdentifier(name) or isZigReservedIdentifier(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.writeAll(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn writeConstAssignmemt(out: var, name: []const u8) !void {
|
fn writeConstAssignmemt(out: var, name: []const u8) !void {
|
||||||
try out.write("pub const ");
|
try out.writeAll("pub const ");
|
||||||
try writeIdentifier(out, name);
|
try writeIdentifier(out, name);
|
||||||
try out.write(" = ");
|
try out.writeAll(" = ");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eqlIgnoreCase(lhs: []const u8, rhs: []const u8) bool {
|
fn eqlIgnoreCase(lhs: []const u8, rhs: []const u8) bool {
|
||||||
@@ -173,13 +173,13 @@ fn renderTypeInfo(out: var, registry: *Registry, type_info: reg.TypeInfo) !void
|
|||||||
// Apparently Vulkan optional-ness information is not correct, so every pointer
|
// Apparently Vulkan optional-ness information is not correct, so every pointer
|
||||||
// is considered optional
|
// is considered optional
|
||||||
switch (ptr.size) {
|
switch (ptr.size) {
|
||||||
.One => try out.write("?*"),
|
.One => try out.writeAll("?*"),
|
||||||
.Many => try out.write("?[*]"),
|
.Many => try out.writeAll("?[*]"),
|
||||||
.ZeroTerminated => try out.write("?[*:0]")
|
.ZeroTerminated => try out.writeAll("?[*:0]")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ptr.is_const) {
|
if (ptr.is_const) {
|
||||||
try out.write("const ");
|
try out.writeAll("const ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,7 +194,7 @@ fn renderTypeInfo(out: var, registry: *Registry, type_info: reg.TypeInfo) !void
|
|||||||
// Some types can be mapped directly to a built-in type
|
// Some types can be mapped directly to a built-in type
|
||||||
for (builtin_types) |bty| {
|
for (builtin_types) |bty| {
|
||||||
if (mem.eql(u8, type_info.name, bty.c_name)) {
|
if (mem.eql(u8, type_info.name, bty.c_name)) {
|
||||||
try out.write(bty.zig_name);
|
try out.writeAll(bty.zig_name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,9 +203,9 @@ fn renderTypeInfo(out: var, registry: *Registry, type_info: reg.TypeInfo) !void
|
|||||||
// If its not a pointer, its a return type, so `void` should be emitted.
|
// If its not a pointer, its a return type, so `void` should be emitted.
|
||||||
if (mem.eql(u8, type_info.name, "void")) {
|
if (mem.eql(u8, type_info.name, "void")) {
|
||||||
if (type_info.pointers.len > 0) {
|
if (type_info.pointers.len > 0) {
|
||||||
try out.write("c_void");
|
try out.writeAll("c_void");
|
||||||
} else {
|
} else {
|
||||||
try out.write("void");
|
try out.writeAll("void");
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -219,60 +219,61 @@ fn renderTypeInfo(out: var, registry: *Registry, type_info: reg.TypeInfo) !void
|
|||||||
try writeIdentifier(out, trimNamespace(type_info.name));
|
try writeIdentifier(out, trimNamespace(type_info.name));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderApiConstantExpr(out: var, constexpr: []const u8) !void {
|
fn renderApiConstantExpr(out: var, constant_expr: []const u8) !void {
|
||||||
// There are only a few different kinds of tokens in the expressions,
|
|
||||||
// all of which can be tokenized by the Zig tokenizer. The only parts which cannot
|
|
||||||
// be parsed properly are 'f', 'U', and 'ULL' suffixes.
|
|
||||||
// Render the C expression by simply substituting those values
|
|
||||||
|
|
||||||
// omit enclosing parenthesis
|
// omit enclosing parenthesis
|
||||||
const expr = if (constexpr[0] == '(' and constexpr[constexpr.len - 1] == ')')
|
const expr = if (constant_expr[0] == '(' and constant_expr[constant_expr.len - 1] == ')')
|
||||||
constexpr[1 .. constexpr.len - 1]
|
constant_expr[1 .. constant_expr.len - 1]
|
||||||
else
|
else
|
||||||
constexpr;
|
constant_expr;
|
||||||
|
|
||||||
var tokenizer = std.zig.Tokenizer.init(expr);
|
var i: usize = 0;
|
||||||
var peek_tok: ?std.zig.Token = null;
|
while (i < expr.len) {
|
||||||
|
switch (expr[i]) {
|
||||||
while (true) {
|
'(', ')', '~' => try out.writeByte(expr[i]),
|
||||||
const tok = peek_tok orelse tokenizer.next();
|
'-' => try out.writeAll(" - "),
|
||||||
const text = expr[tok.start .. tok.end];
|
'a'...'z', 'A'...'Z', '_' => {
|
||||||
peek_tok = null;
|
var j = i;
|
||||||
|
while (j < expr.len) : (j += 1) {
|
||||||
switch (tok.id) {
|
switch (expr[j]) {
|
||||||
.LParen, .RParen, .Tilde => try out.write(text),
|
'a'...'z', 'A'...'Z', '_', '0'...'9' => {},
|
||||||
.Identifier => try writeIdentifier(out, trimNamespace(text)),
|
else => break
|
||||||
.Minus => try out.write(" - "),
|
}
|
||||||
.FloatLiteral => {
|
|
||||||
try out.print("@as(f32, {})", .{text});
|
|
||||||
|
|
||||||
// Float literal has to be followed by an 'f' identifier.
|
|
||||||
const suffix = tokenizer.next();
|
|
||||||
const suffix_text = expr[suffix.start .. suffix.end];
|
|
||||||
if (suffix.id != .Identifier or !mem.eql(u8, suffix_text, "f")) {
|
|
||||||
return error.ExpectedFloatSuffix;
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
.IntegerLiteral => {
|
|
||||||
const suffix = tokenizer.next();
|
|
||||||
const suffix_text = expr[suffix.start .. suffix.end];
|
|
||||||
|
|
||||||
if (suffix.id != .Identifier) {
|
try writeIdentifier(out, trimNamespace(expr[i .. j]));
|
||||||
// Only need to check here because any identifier following an integer
|
i = j;
|
||||||
// that is not 'U' or 'ULL' is a syntax error.
|
continue;
|
||||||
peek_tok = suffix;
|
},
|
||||||
try out.write(text);
|
'0'...'9' => {
|
||||||
} else if (mem.eql(u8, suffix_text, "U")) {
|
var j = i;
|
||||||
try out.print("@as(u32, {})", .{text});
|
while (j < expr.len) : (j += 1) {
|
||||||
} else if (mem.eql(u8, suffix_text, "ULL")) {
|
switch (expr[j]) {
|
||||||
try out.print("@as(u64, {})", .{text});
|
'0'...'9', '.' => {},
|
||||||
|
else => break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mem.startsWith(u8, expr[j..], "f")) {
|
||||||
|
try out.print("@as(f32, {})", .{expr[i .. j]});
|
||||||
|
j += "f".len;
|
||||||
|
} else if (mem.startsWith(u8, expr[j..], "ULL")) {
|
||||||
|
try out.print("@as(u32, {})", .{expr[i .. j]});
|
||||||
|
j += "ULL".len;
|
||||||
|
} else if (mem.startsWith(u8, expr[j..], "U")) {
|
||||||
|
try out.print("@as(u64, {})", .{expr[i .. j]});
|
||||||
|
j += "U".len;
|
||||||
} else {
|
} else {
|
||||||
return error.InvalidIntSuffix;
|
try out.writeAll(expr[i .. j]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i = j;
|
||||||
|
continue;
|
||||||
},
|
},
|
||||||
.Eof => return,
|
' ' => {},
|
||||||
else => return error.UnexpectedToken
|
else => return error.InvalidConstantExpr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,23 +282,23 @@ fn renderApiConstants(out: var, registry: *Registry) !void {
|
|||||||
while (it.next()) |constant| {
|
while (it.next()) |constant| {
|
||||||
try writeConstAssignmemt(out, trimNamespace(constant.name));
|
try writeConstAssignmemt(out, trimNamespace(constant.name));
|
||||||
try renderApiConstantExpr(out, constant.expr);
|
try renderApiConstantExpr(out, constant.expr);
|
||||||
try out.write(";\n");
|
try out.writeAll(";\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
try out.write("\n");
|
try out.writeAll("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderForeignTypes(out: var) !void {
|
fn renderForeignTypes(out: var) !void {
|
||||||
try writeConstAssignmemt(out, foreign_types_namespace);
|
try writeConstAssignmemt(out, foreign_types_namespace);
|
||||||
try out.write("struct {\n");
|
try out.writeAll("struct {\n");
|
||||||
|
|
||||||
for (foreign_types) |fty| {
|
for (foreign_types) |fty| {
|
||||||
try out.write(base_indent);
|
try out.writeAll(base_indent);
|
||||||
try writeConstAssignmemt(out, fty.name);
|
try writeConstAssignmemt(out, fty.name);
|
||||||
try out.print("{};\n", .{fty.expr});
|
try out.print("{};\n", .{fty.expr});
|
||||||
}
|
}
|
||||||
|
|
||||||
try out.write("};\n");
|
try out.writeAll("};\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderDeclarations(out: var, registry: *Registry) !void {
|
fn renderDeclarations(out: var, registry: *Registry) !void {
|
||||||
@@ -314,7 +315,7 @@ fn renderDeclarations(out: var, registry: *Registry) !void {
|
|||||||
.BaseType => |type_info| {
|
.BaseType => |type_info| {
|
||||||
try writeConstAssignmemt(out, trimNamespace(decl.name));
|
try writeConstAssignmemt(out, trimNamespace(decl.name));
|
||||||
try renderTypeInfo(out, registry, type_info);
|
try renderTypeInfo(out, registry, type_info);
|
||||||
try out.write(";\n\n");
|
try out.writeAll(";\n\n");
|
||||||
},
|
},
|
||||||
else => {}
|
else => {}
|
||||||
}
|
}
|
||||||
@@ -334,14 +335,14 @@ fn renderEnum(out: var, name: []const u8, enum_info: *reg.EnumInfo) !void {
|
|||||||
const trimmed_name = trimNamespace(name);
|
const trimmed_name = trimNamespace(name);
|
||||||
|
|
||||||
try writeConstAssignmemt(out, trimmed_name);
|
try writeConstAssignmemt(out, trimmed_name);
|
||||||
try out.write("extern enum {\n");
|
try out.writeAll("extern enum {\n");
|
||||||
|
|
||||||
// Calculate the length of the enum namespace, by iterating through the segments
|
// Calculate the length of the enum namespace, by iterating through the segments
|
||||||
// of the variant (in screaming snake case) and comparing it to the name of the enum,
|
// of the variant (in screaming snake case) and comparing it to the name of the enum,
|
||||||
// until the two differ.
|
// until the two differ.
|
||||||
var prefix_len: usize = 0;
|
var prefix_len: usize = 0;
|
||||||
var snake_prefix_len: usize = 0;
|
var snake_prefix_len: usize = 0;
|
||||||
var segment_it = mem.separate(enum_info.variants.at(0).name, "_");
|
var segment_it = mem.split(enum_info.variants.at(0).name, "_");
|
||||||
while (segment_it.next()) |segment| {
|
while (segment_it.next()) |segment| {
|
||||||
if (prefix_len + segment.len <= name.len and eqlIgnoreCase(segment, name[prefix_len .. prefix_len + segment.len])) {
|
if (prefix_len + segment.len <= name.len and eqlIgnoreCase(segment, name[prefix_len .. prefix_len + segment.len])) {
|
||||||
prefix_len += segment.len;
|
prefix_len += segment.len;
|
||||||
@@ -355,7 +356,7 @@ fn renderEnum(out: var, name: []const u8, enum_info: *reg.EnumInfo) !void {
|
|||||||
while (it.next()) |variant| {
|
while (it.next()) |variant| {
|
||||||
if (variant.value == .Alias) continue; // Skip aliases
|
if (variant.value == .Alias) continue; // Skip aliases
|
||||||
|
|
||||||
try out.write(base_indent);
|
try out.writeAll(base_indent);
|
||||||
try writeIdentifier(out, variant.name[snake_prefix_len ..]);
|
try writeIdentifier(out, variant.name[snake_prefix_len ..]);
|
||||||
|
|
||||||
switch (variant.value) {
|
switch (variant.value) {
|
||||||
@@ -366,7 +367,7 @@ fn renderEnum(out: var, name: []const u8, enum_info: *reg.EnumInfo) !void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try out.write("};\n\n");
|
try out.writeAll("};\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderAlias(out: var, registry: *Registry, name: []const u8, alias: []const u8) !void {
|
fn renderAlias(out: var, registry: *Registry, name: []const u8, alias: []const u8) !void {
|
||||||
@@ -383,52 +384,52 @@ fn renderAlias(out: var, registry: *Registry, name: []const u8, alias: []const u
|
|||||||
|
|
||||||
try writeConstAssignmemt(out, trimNamespace(name));
|
try writeConstAssignmemt(out, trimNamespace(name));
|
||||||
try writeIdentifier(out, trimNamespace(alias));
|
try writeIdentifier(out, trimNamespace(alias));
|
||||||
try out.write(";\n\n");
|
try out.writeAll(";\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
try writeConstAssignmemt(out, trimNamespace(name));
|
try writeConstAssignmemt(out, trimNamespace(name));
|
||||||
try out.write("extern fn(");
|
try out.writeAll("?fn(");
|
||||||
|
|
||||||
if (info.parameters.count() > 0) {
|
if (info.parameters.count() > 0) {
|
||||||
try out.write("\n");
|
try out.writeAll("\n");
|
||||||
var it = info.parameters.iterator(0);
|
var it = info.parameters.iterator(0);
|
||||||
while (it.next()) |param| {
|
while (it.next()) |param| {
|
||||||
try out.write(base_indent);
|
try out.writeAll(base_indent);
|
||||||
try writeIdentifier(out, param.name);
|
try writeIdentifier(out, param.name);
|
||||||
try out.write(": ");
|
try out.writeAll(": ");
|
||||||
try renderTypeInfo(out, registry, param.type_info);
|
try renderTypeInfo(out, registry, param.type_info);
|
||||||
try out.write(",\n");
|
try out.writeAll(",\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try out.write(") ");
|
try out.writeAll(") callconv(.C) ");
|
||||||
try renderTypeInfo(out, registry, info.return_type_info);
|
try renderTypeInfo(out, registry, info.return_type_info);
|
||||||
try out.write(";\n\n");
|
try out.writeAll(";\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderContainer(out: var, registry: *Registry, kind: enum{Struct, Union}, name: []const u8, info: *reg.ContainerInfo) !void {
|
fn renderContainer(out: var, registry: *Registry, kind: enum{Struct, Union}, name: []const u8, info: *reg.ContainerInfo) !void {
|
||||||
try writeConstAssignmemt(out, trimNamespace(name));
|
try writeConstAssignmemt(out, trimNamespace(name));
|
||||||
|
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
.Struct => try out.write("extern struct {\n"),
|
.Struct => try out.writeAll("extern struct {\n"),
|
||||||
.Union => try out.write("extern union {\n")
|
.Union => try out.writeAll("extern union {\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
var it = info.members.iterator(0);
|
var it = info.members.iterator(0);
|
||||||
while (it.next()) |member| {
|
while (it.next()) |member| {
|
||||||
try out.write(base_indent);
|
try out.writeAll(base_indent);
|
||||||
try writeIdentifier(out, member.name);
|
try writeIdentifier(out, member.name);
|
||||||
try out.write(": ");
|
try out.writeAll(": ");
|
||||||
try renderTypeInfo(out, registry, member.type_info);
|
try renderTypeInfo(out, registry, member.type_info);
|
||||||
try out.write(",\n");
|
try out.writeAll(",\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
try out.write("};\n\n");
|
try out.writeAll("};\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn renderTest(out: var) !void {
|
fn renderTest(out: var) !void {
|
||||||
try out.write(
|
try out.writeAll(
|
||||||
\\test "Semantic analysis" {
|
\\test "Semantic analysis" {
|
||||||
\\ std.meta.refAllDecls(@This());
|
\\ std.meta.refAllDecls(@This());
|
||||||
\\}
|
\\}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ pub const Element = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getAttribute(self: *Element, attrib_name: []const u8) ?[]const u8 {
|
pub fn getAttribute(self: *Element, attrib_name: []const u8) ?[]const u8 {
|
||||||
var it = self.attributes.iterator(0);
|
var it = self.attributes.iterator(0);
|
||||||
while (it.next()) |child| {
|
while (it.next()) |child| {
|
||||||
if (mem.eql(u8, child.*.name, attrib_name)) {
|
if (mem.eql(u8, child.*.name, attrib_name)) {
|
||||||
@@ -43,7 +43,7 @@ pub const Element = struct {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn getCharData(self: *Element, child_tag: []const u8) ?[]const u8 {
|
pub fn getCharData(self: *Element, child_tag: []const u8) ?[]const u8 {
|
||||||
const child = self.findChildByTag(child_tag) orelse return null;
|
const child = self.findChildByTag(child_tag) orelse return null;
|
||||||
if (child.children.count() != 1) {
|
if (child.children.count() != 1) {
|
||||||
return null;
|
return null;
|
||||||
@@ -55,11 +55,11 @@ pub const Element = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn findChildByTag(self: *Element, tag: []const u8) ?*Element {
|
pub fn findChildByTag(self: *Element, tag: []const u8) ?*Element {
|
||||||
return self.findChildrenByTag(tag).next();
|
return self.findChildrenByTag(tag).next();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn findChildrenByTag(self: *Element, tag: []const u8) FindChildrenByTagIterator {
|
pub fn findChildrenByTag(self: *Element, tag: []const u8) FindChildrenByTagIterator {
|
||||||
return .{
|
return .{
|
||||||
.inner = self.children.iterator(0),
|
.inner = self.children.iterator(0),
|
||||||
.tag = tag
|
.tag = tag
|
||||||
@@ -70,7 +70,7 @@ pub const Element = struct {
|
|||||||
inner: ContentList.Iterator,
|
inner: ContentList.Iterator,
|
||||||
tag: []const u8,
|
tag: []const u8,
|
||||||
|
|
||||||
fn next(self: *FindChildrenByTagIterator) ?*Element {
|
pub fn next(self: *FindChildrenByTagIterator) ?*Element {
|
||||||
while (self.inner.next()) |child| {
|
while (self.inner.next()) |child| {
|
||||||
if (child.* != .Element or !mem.eql(u8, child.*.Element.tag, self.tag)) {
|
if (child.* != .Element or !mem.eql(u8, child.*.Element.tag, self.tag)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -424,15 +424,19 @@ fn tryParseElement(ctx: *ParseContext, alloc: *Allocator) !?*Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "tryParseElement" {
|
test "tryParseElement" {
|
||||||
|
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
var alloc = &arena.allocator;
|
||||||
|
|
||||||
{
|
{
|
||||||
var ctx = ParseContext.init("<= a='b'/>");
|
var ctx = ParseContext.init("<= a='b'/>");
|
||||||
testing.expectEqual(@as(?*Element, null), try tryParseElement(&ctx, std.debug.global_allocator));
|
testing.expectEqual(@as(?*Element, null), try tryParseElement(&ctx, alloc));
|
||||||
testing.expectEqual(@as(?u8, '<'), ctx.peek());
|
testing.expectEqual(@as(?u8, '<'), ctx.peek());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var ctx = ParseContext.init("<python size='15' color = \"green\"/>");
|
var ctx = ParseContext.init("<python size='15' color = \"green\"/>");
|
||||||
const elem = try tryParseElement(&ctx, std.debug.global_allocator);
|
const elem = try tryParseElement(&ctx, alloc);
|
||||||
testing.expectEqualSlices(u8, elem.?.tag, "python");
|
testing.expectEqualSlices(u8, elem.?.tag, "python");
|
||||||
|
|
||||||
const size_attr = elem.?.attributes.at(0).*;
|
const size_attr = elem.?.attributes.at(0).*;
|
||||||
@@ -446,14 +450,14 @@ test "tryParseElement" {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var ctx = ParseContext.init("<python>test</python>");
|
var ctx = ParseContext.init("<python>test</python>");
|
||||||
const elem = try tryParseElement(&ctx, std.debug.global_allocator);
|
const elem = try tryParseElement(&ctx, alloc);
|
||||||
testing.expectEqualSlices(u8, elem.?.tag, "python");
|
testing.expectEqualSlices(u8, elem.?.tag, "python");
|
||||||
testing.expectEqualSlices(u8, elem.?.children.at(0).CharData, "test");
|
testing.expectEqualSlices(u8, elem.?.children.at(0).CharData, "test");
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var ctx = ParseContext.init("<a>b<c/>d<e/>f<!--g--></a>");
|
var ctx = ParseContext.init("<a>b<c/>d<e/>f<!--g--></a>");
|
||||||
const elem = try tryParseElement(&ctx, std.debug.global_allocator);
|
const elem = try tryParseElement(&ctx, alloc);
|
||||||
testing.expectEqualSlices(u8, elem.?.tag, "a");
|
testing.expectEqualSlices(u8, elem.?.tag, "a");
|
||||||
testing.expectEqualSlices(u8, elem.?.children.at(0).CharData, "b");
|
testing.expectEqualSlices(u8, elem.?.children.at(0).CharData, "b");
|
||||||
testing.expectEqualSlices(u8, elem.?.children.at(1).Element.tag, "c");
|
testing.expectEqualSlices(u8, elem.?.children.at(1).Element.tag, "c");
|
||||||
@@ -508,15 +512,19 @@ fn tryParseProlog(ctx: *ParseContext, alloc: *Allocator) !?*XmlDecl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "tryParseProlog" {
|
test "tryParseProlog" {
|
||||||
|
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||||
|
defer arena.deinit();
|
||||||
|
var alloc = &arena.allocator;
|
||||||
|
|
||||||
{
|
{
|
||||||
var ctx = ParseContext.init("<?xmla version='aa'?>");
|
var ctx = ParseContext.init("<?xmla version='aa'?>");
|
||||||
testing.expectEqual(@as(?*XmlDecl, null), try tryParseProlog(&ctx, std.debug.global_allocator));
|
testing.expectEqual(@as(?*XmlDecl, null), try tryParseProlog(&ctx, alloc));
|
||||||
testing.expectEqual(@as(?u8, '<'), ctx.peek());
|
testing.expectEqual(@as(?u8, '<'), ctx.peek());
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var ctx = ParseContext.init("<?xml version='aa'?>");
|
var ctx = ParseContext.init("<?xml version='aa'?>");
|
||||||
const decl = try tryParseProlog(&ctx, std.debug.global_allocator);
|
const decl = try tryParseProlog(&ctx, alloc);
|
||||||
testing.expectEqualSlices(u8, "aa", decl.?.version);
|
testing.expectEqualSlices(u8, "aa", decl.?.version);
|
||||||
testing.expectEqual(@as(?[]const u8, null), decl.?.encoding);
|
testing.expectEqual(@as(?[]const u8, null), decl.?.encoding);
|
||||||
testing.expectEqual(@as(?bool, null), decl.?.standalone);
|
testing.expectEqual(@as(?bool, null), decl.?.standalone);
|
||||||
@@ -524,7 +532,7 @@ test "tryParseProlog" {
|
|||||||
|
|
||||||
{
|
{
|
||||||
var ctx = ParseContext.init("<?xml version=\"aa\" encoding = 'bbb' standalone \t = 'yes'?>");
|
var ctx = ParseContext.init("<?xml version=\"aa\" encoding = 'bbb' standalone \t = 'yes'?>");
|
||||||
const decl = try tryParseProlog(&ctx, std.debug.global_allocator);
|
const decl = try tryParseProlog(&ctx, alloc);
|
||||||
testing.expectEqualSlices(u8, "aa", decl.?.version);
|
testing.expectEqualSlices(u8, "aa", decl.?.version);
|
||||||
testing.expectEqualSlices(u8, "bbb", decl.?.encoding.?);
|
testing.expectEqualSlices(u8, "bbb", decl.?.encoding.?);
|
||||||
testing.expectEqual(@as(?bool, true), decl.?.standalone.?);
|
testing.expectEqual(@as(?bool, true), decl.?.standalone.?);
|
||||||
@@ -584,10 +592,14 @@ fn dupeAndUnescape(alloc: *Allocator, text: []const u8) ![]const u8 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test "dupeAndUnescape" {
|
test "dupeAndUnescape" {
|
||||||
testing.expectEqualSlices(u8, "test", try dupeAndUnescape(std.debug.global_allocator, "test"));
|
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
||||||
testing.expectEqualSlices(u8, "a<b&c>d\"e'f<", try dupeAndUnescape(std.debug.global_allocator, "a<b&c>d"e'f<"));
|
defer arena.deinit();
|
||||||
testing.expectError(error.InvalidEntity, dupeAndUnescape(std.debug.global_allocator, "python&"));
|
var alloc = &arena.allocator;
|
||||||
testing.expectError(error.InvalidEntity, dupeAndUnescape(std.debug.global_allocator, "python&&"));
|
|
||||||
testing.expectError(error.InvalidEntity, dupeAndUnescape(std.debug.global_allocator, "python&test;"));
|
testing.expectEqualSlices(u8, "test", try dupeAndUnescape(alloc, "test"));
|
||||||
testing.expectError(error.InvalidEntity, dupeAndUnescape(std.debug.global_allocator, "python&boa"));
|
testing.expectEqualSlices(u8, "a<b&c>d\"e'f<", try dupeAndUnescape(alloc, "a<b&c>d"e'f<"));
|
||||||
|
testing.expectError(error.InvalidEntity, dupeAndUnescape(alloc, "python&"));
|
||||||
|
testing.expectError(error.InvalidEntity, dupeAndUnescape(alloc, "python&&"));
|
||||||
|
testing.expectError(error.InvalidEntity, dupeAndUnescape(alloc, "python&test;"));
|
||||||
|
testing.expectError(error.InvalidEntity, dupeAndUnescape(alloc, "python&boa"));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user