Move vulkan/util.zig to id_render.zig, and make it more generic

This commit is contained in:
Robin Voetter
2020-08-11 18:07:21 +02:00
parent 74d6846d68
commit c708f01e3a
4 changed files with 61 additions and 57 deletions

View File

@@ -1,7 +1,7 @@
const std = @import("std");
const registry = @import("registry.zig");
const xml = @import("../xml.zig");
const cparse = @import("c-parse.zig");
const cparse = @import("c_parse.zig");
const mem = std.mem;
const Allocator = mem.Allocator;
const ArenaAllocator = std.heap.ArenaAllocator;

View File

@@ -1,7 +1,7 @@
const std = @import("std");
const reg = @import("registry.zig");
const util = @import("util.zig");
const cparse = @import("c-parse.zig");
const id_render = @import("../id_render.zig");
const cparse = @import("c_parse.zig");
const mem = std.mem;
const Allocator = mem.Allocator;
@@ -112,6 +112,17 @@ fn eqlIgnoreCase(lhs: []const u8, rhs: []const u8) bool {
return true;
}
pub fn trimVkNamespace(id: []const u8) []const u8 {
const prefixes = [_][]const u8{"VK_", "vk", "Vk", "PFN_vk"};
for (prefixes) |prefix| {
if (mem.startsWith(u8, id, prefix)) {
return id[prefix.len..];
}
}
return id;
}
fn Renderer(comptime WriterType: type) type {
return struct {
const Self = @This();
@@ -156,18 +167,22 @@ fn Renderer(comptime WriterType: type) type {
writer: WriterType,
allocator: *Allocator,
registry: *const reg.Registry,
id_renderer: util.IdRenderer,
id_renderer: id_render.IdRenderer,
fn init(writer: WriterType, allocator: *Allocator, registry: *const reg.Registry) Self {
return .{
fn init(writer: WriterType, allocator: *Allocator, registry: *const reg.Registry) !Self {
const tags = try allocator.alloc([]const u8, registry.tags.len);
for (tags) |*tag, i| tag.* = registry.tags[i].name;
return Self{
.writer = writer,
.allocator = allocator,
.registry = registry,
.id_renderer = util.IdRenderer.init(allocator, registry.tags),
.id_renderer = id_render.IdRenderer.init(allocator, tags),
};
}
fn deinit(self: Self) void {
self.allocator.free(self.id_renderer.tags);
self.id_renderer.deinit();
}
@@ -175,7 +190,7 @@ fn Renderer(comptime WriterType: type) type {
try self.id_renderer.render(self.writer, id);
}
fn writeIdentifierWithCase(self: *Self, case: util.CaseStyle, id: []const u8) !void {
fn writeIdentifierWithCase(self: *Self, case: id_render.CaseStyle, id: []const u8) !void {
try self.id_renderer.renderWithCase(self.writer, case, id);
}
@@ -184,10 +199,10 @@ fn Renderer(comptime WriterType: type) type {
}
fn extractEnumFieldName(self: Self, enum_name: []const u8, field_name: []const u8) ![]const u8 {
const adjusted_enum_name = util.stripAuthorTag(enum_name, self.registry.tags);
const adjusted_enum_name = self.id_renderer.stripAuthorTag(enum_name);
var enum_it = util.SegmentIterator.init(adjusted_enum_name);
var field_it = util.SegmentIterator.init(field_name);
var enum_it = id_render.SegmentIterator.init(adjusted_enum_name);
var field_it = id_render.SegmentIterator.init(field_name);
while (true) {
const rest = field_it.rest();
@@ -201,7 +216,7 @@ fn Renderer(comptime WriterType: type) type {
}
fn extractBitflagName(self: Self, name: []const u8) ?BitflagName {
const tag = util.getAuthorTag(name, self.registry.tags);
const tag = self.id_renderer.getAuthorTag(name);
const base_name = if (tag) |tag_name| name[0 .. name.len - tag_name.len] else name;
if (!mem.endsWith(u8, base_name, "FlagBits")) {
@@ -215,7 +230,7 @@ fn Renderer(comptime WriterType: type) type {
}
fn isFlags(self: Self, name: []const u8) bool {
const tag = util.getAuthorTag(name, self.registry.tags);
const tag = self.id_renderer.getAuthorTag(name);
const base_name = if (tag) |tag_name| name[0 .. name.len - tag_name.len] else name;
return mem.endsWith(u8, base_name, "Flags");
@@ -236,7 +251,7 @@ fn Renderer(comptime WriterType: type) type {
const child_name = ptr.child.name;
if (mem.eql(u8, child_name, "void")) {
return .other;
} else if (builtin_types.get(child_name) == null and util.trimVkNamespace(child_name).ptr == child_name.ptr) {
} else if (builtin_types.get(child_name) == null and trimVkNamespace(child_name).ptr == child_name.ptr) {
return .other; // External type
}
}
@@ -414,7 +429,7 @@ fn Renderer(comptime WriterType: type) type {
return;
} else if (self.extractBitflagName(name)) |bitflag_name| {
try self.writeIdentifierFmt("{}Flags{}", .{
util.trimVkNamespace(bitflag_name.base_name),
trimVkNamespace(bitflag_name.base_name),
@as([]const u8, if (bitflag_name.tag) |tag| tag else "")
});
return;
@@ -453,7 +468,7 @@ fn Renderer(comptime WriterType: type) type {
if (param.param_type == .name) {
if (self.extractBitflagName(param.param_type.name)) |bitflag_name| {
try self.writeIdentifierFmt("{}Flags{}", .{
util.trimVkNamespace(bitflag_name.base_name),
trimVkNamespace(bitflag_name.base_name),
@as([]const u8, if (bitflag_name.tag) |tag| tag else "")
});
try self.writer.writeAll(".IntType");
@@ -568,7 +583,7 @@ fn Renderer(comptime WriterType: type) type {
try self.writer.writeAll(" = null");
} else if (mem.eql(u8, field.name, "sType")) {
try self.writer.writeAll(" = .");
try self.writeIdentifierWithCase(.snake, util.trimVkNamespace(name));
try self.writeIdentifierWithCase(.snake, trimVkNamespace(name));
}
}
@@ -728,7 +743,7 @@ fn Renderer(comptime WriterType: type) type {
}
fn renderCommandPtrName(self: *Self, name: []const u8) !void {
try self.writeIdentifierFmt("Pfn{}", .{util.trimVkNamespace(name)});
try self.writeIdentifierFmt("Pfn{}", .{trimVkNamespace(name)});
}
fn renderCommandPtrs(self: *Self) !void {
@@ -755,7 +770,7 @@ fn Renderer(comptime WriterType: type) type {
);
for (self.registry.extensions) |ext| {
try self.writer.writeAll("pub const ");
try self.writeIdentifierWithCase(.snake, util.trimVkNamespace(ext.name));
try self.writeIdentifierWithCase(.snake, trimVkNamespace(ext.name));
try self.writer.writeAll("= Info {\n");
try self.writer.print(".name = \"{}\", .version = {},", .{ext.name, ext.version});
try self.writer.writeAll("};\n");
@@ -822,7 +837,7 @@ fn Renderer(comptime WriterType: type) type {
}
fn derefName(name: []const u8) []const u8 {
var it = util.SegmentIterator.init(name);
var it = id_render.SegmentIterator.init(name);
return if (mem.eql(u8, it.next().?, "p"))
name[1..]
else
@@ -831,7 +846,7 @@ fn Renderer(comptime WriterType: type) type {
fn renderWrapperPrototype(self: *Self, name: []const u8, command: reg.Command, returns: []const ReturnValue) !void {
try self.writer.writeAll("pub fn ");
try self.writeIdentifierWithCase(.camel, util.trimVkNamespace(name));
try self.writeIdentifierWithCase(.camel, trimVkNamespace(name));
try self.writer.writeAll("(self: Self, ");
for (command.params) |param| {
@@ -946,7 +961,7 @@ fn Renderer(comptime WriterType: type) type {
}
fn renderReturnStructName(self: *Self, command_name: []const u8) !void {
try self.writeIdentifierFmt("{}Result", .{util.trimVkNamespace(command_name)});
try self.writeIdentifierFmt("{}Result", .{trimVkNamespace(command_name)});
}
fn renderReturnStruct(self: *Self, command_name: []const u8, returns: []const ReturnValue) !void {
@@ -1076,14 +1091,14 @@ fn Renderer(comptime WriterType: type) type {
} else {
// Apparently some commands (VkAcquireProfilingLockInfoKHR) return
// success codes as error...
try self.writeIdentifierWithCase(.title, util.trimVkNamespace(name));
try self.writeIdentifierWithCase(.title, trimVkNamespace(name));
}
}
};
}
pub fn render(writer: anytype, allocator: *Allocator, registry: *const reg.Registry) !void {
var renderer = Renderer(@TypeOf(writer)).init(writer, allocator, registry);
var renderer = try Renderer(@TypeOf(writer)).init(writer, allocator, registry);
defer renderer.deinit();
try renderer.render();
}

View File

@@ -1,251 +0,0 @@
const std = @import("std");
const reg = @import("registry.zig");
const mem = std.mem;
const Allocator = mem.Allocator;
// Lifted from src-self-hosted/translate_c.zig
pub fn isValidZigIdentifier(name: []const u8) bool {
for (name) |c, i| {
switch (c) {
'_', 'a'...'z', 'A'...'Z' => {},
'0' ... '9' => if (i == 0) return false,
else => return false
}
}
return true;
}
// Lifted from src-self-hosted/translate_c.zig
pub 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;
}
const reserved_names = [_][]const u8 {
"void", "comptime_float", "comptime_int", "bool", "isize",
"usize", "f16", "f32", "f64", "f128", "c_longdouble",
"noreturn", "type", "anyerror", "c_short", "c_ushort",
"c_int", "c_uint", "c_long", "c_ulong", "c_longlong", "c_ulonglong"
};
for (reserved_names) |reserved| {
if (mem.eql(u8, reserved, name)) {
return true;
}
}
return false;
}
pub fn needZigEscape(name: []const u8) bool {
return !isValidZigIdentifier(name)
or isZigReservedIdentifier(name)
or std.zig.Token.getKeyword(name) != null;
}
pub fn writeIdentifier(out: anytype, id: []const u8) !void {
if (needZigEscape(id)) {
try out.print("@\"{}\"", .{id});
} else {
try out.writeAll(id);
}
}
pub const CaseStyle = enum {
snake,
screaming_snake,
title,
camel,
};
pub fn trimVkNamespace(id: []const u8) []const u8 {
const prefixes = [_][]const u8{"VK_", "vk", "Vk", "PFN_vk"};
for (prefixes) |prefix| {
if (mem.startsWith(u8, id, prefix)) {
return id[prefix.len..];
}
}
return id;
}
pub fn getAuthorTag(id: []const u8, tags: []const reg.Tag) ?[]const u8 {
for (tags) |tag| {
if (mem.endsWith(u8, id, tag.name)) {
return tag.name;
}
}
return null;
}
pub fn stripAuthorTag(id: []const u8, tags: []const reg.Tag) []const u8 {
if (getAuthorTag(id, tags)) |tag| {
return mem.trimRight(u8, id[0 .. id.len - tag.len], "_");
}
return id;
}
pub const SegmentIterator = struct {
text: []const u8,
offset: usize,
pub fn init(text: []const u8) SegmentIterator {
return .{
.text = text,
.offset = 0,
};
}
fn nextBoundary(self: SegmentIterator) usize {
var i = self.offset + 1;
while (true) {
if (i == self.text.len or self.text[i] == '_') {
return i;
}
const prev_lower = std.ascii.isLower(self.text[i - 1]);
const next_lower = std.ascii.isLower(self.text[i]);
if (prev_lower and !next_lower) {
return i;
} else if (i != self.offset + 1 and !prev_lower and next_lower) {
return i - 1;
}
i += 1;
}
}
pub fn next(self: *SegmentIterator) ?[]const u8 {
while (self.offset < self.text.len and self.text[self.offset] == '_') {
self.offset += 1;
}
if (self.offset == self.text.len) {
return null;
}
const end = self.nextBoundary();
const word = self.text[self.offset .. end];
self.offset = end;
return word;
}
pub fn rest(self: SegmentIterator) []const u8 {
if (self.offset >= self.text.len) {
return &[_]u8{};
} else {
return self.text[self.offset..];
}
}
};
pub const IdRenderer = struct {
tags: []const reg.Tag,
text_cache: std.ArrayList(u8),
pub fn init(allocator: *Allocator, tags: []const reg.Tag) IdRenderer {
return .{
.tags = tags,
.text_cache = std.ArrayList(u8).init(allocator),
};
}
pub fn deinit(self: IdRenderer) void {
self.text_cache.deinit();
}
fn renderSnake(self: *IdRenderer, screaming: bool, id: []const u8, tag: ?[]const u8) !void {
var it = SegmentIterator.init(id);
var first = true;
const transform = if (screaming) std.ascii.toUpper else std.ascii.toLower;
while (it.next()) |segment| {
if (first) {
first = false;
} else {
try self.text_cache.append('_');
}
for (segment) |c| {
try self.text_cache.append(transform(c));
}
}
if (tag) |name| {
try self.text_cache.append('_');
for (name) |c| {
try self.text_cache.append(transform(c));
}
}
}
fn renderCamel(self: *IdRenderer, title: bool, id: []const u8, tag: ?[]const u8) !void {
var it = SegmentIterator.init(id);
var lower_first = !title;
while (it.next()) |segment| {
var i: usize = 0;
while (i < segment.len and std.ascii.isDigit(segment[i])) {
try self.text_cache.append(segment[i]);
i += 1;
}
if (i == segment.len) {
continue;
}
if (i == 0 and lower_first) {
try self.text_cache.append(std.ascii.toLower(segment[i]));
} else {
try self.text_cache.append(std.ascii.toUpper(segment[i]));
}
lower_first = false;
for (segment[i + 1..]) |c| {
try self.text_cache.append(std.ascii.toLower(c));
}
}
if (tag) |name| {
try self.text_cache.appendSlice(name);
}
}
pub fn render(self: IdRenderer, out: anytype, id: []const u8) !void {
try writeIdentifier(out, id);
}
pub fn renderFmt(self: *IdRenderer, out: anytype, comptime fmt: []const u8, args: anytype) !void {
self.text_cache.items.len = 0;
try std.fmt.format(self.text_cache.writer(), fmt, args);
try writeIdentifier(out, self.text_cache.items);
}
pub fn renderWithCase(self: *IdRenderer, out: anytype, case_style: CaseStyle, id: []const u8) !void {
const tag = getAuthorTag(id, self.tags);
const adjusted_id = if (tag) |name| id[0 .. id.len - name.len] else id;
self.text_cache.items.len = 0;
switch (case_style) {
.snake => try self.renderSnake(false, adjusted_id, tag),
.screaming_snake => try self.renderSnake(true, adjusted_id, tag),
.title => try self.renderCamel(true, adjusted_id, tag),
.camel => try self.renderCamel(false, adjusted_id, tag),
}
try writeIdentifier(out, self.text_cache.items);
}
};