From dd14161e8f5e403116e653d08d97a12d01c2e28d Mon Sep 17 00:00:00 2001 From: "Pedro M. Silva" Date: Wed, 26 Aug 2020 18:58:35 +0100 Subject: [PATCH 01/13] First draft of the Python generator --- build.zig | 1 + generators/python.zig | 204 ++++++++++++++++++++++++++++++++++++++++++ header_gen.zig | 1 + 3 files changed, 206 insertions(+) create mode 100644 generators/python.zig diff --git a/build.zig b/build.zig index 6d6e851..c8a2c27 100644 --- a/build.zig +++ b/build.zig @@ -25,4 +25,5 @@ pub fn build(b: *Builder) void { // --- Using header_gen const gen = header_gen.HeaderGen("src/exports.zig").init(); gen.exec(header_gen.C_Generator); + gen.exec(header_gen.Python_Generator); } diff --git a/generators/python.zig b/generators/python.zig new file mode 100644 index 0000000..4e058e2 --- /dev/null +++ b/generators/python.zig @@ -0,0 +1,204 @@ +const std = @import("std"); +const Dir = std.fs.Dir; +const FnMeta = std.builtin.TypeInfo.Fn; +const FnDecl = std.builtin.TypeInfo.Declaration.Data.FnDecl; +const StructMeta = std.builtin.TypeInfo.Struct; +const EnumMeta = std.builtin.TypeInfo.Enum; +const UnionMeta = std.builtin.TypeInfo.Union; +const warn = std.debug.warn; + +pub const Python_Generator = struct { + file: std.fs.File, + + const Self = @This(); + + pub fn init(comptime src_file: []const u8, dst_dir: *Dir) Self { + comptime const filebaseext = std.fs.path.basename(src_file); + // The .len - 4 assumes a .zig extension + comptime const filebase = filebaseext[0 .. filebaseext.len - 4]; + + var file = dst_dir.createFile(filebase ++ ".py", .{}) catch + @panic("Failed to create header file for source: " ++ src_file); + + var res = Self{ .file = file }; + + res.write( + \\import ctypes + \\import enum + \\ + ); + + res.write("lib = ctypes.cdll.LoadLibrary(\"" ++ filebase ++ ".dll\")\n\n"); + + return res; + } + + pub fn deinit(self: *Self) void { + self.file.close(); + } + + pub fn gen_func(self: *Self, comptime name: []const u8, comptime func: FnDecl, comptime meta: FnMeta) void { + self.write("lib." ++ name ++ ".argtypes = ["); + + inline for (meta.args) |arg, i| { + self.writeType(arg.arg_type.?); + + if (i != meta.args.len - 1) { + self.write(", "); + } + } + + self.write("]\n"); + + self.write("lib." ++ name ++ ".restype = "); + self.writeType(func.return_type); + self.write("\n\n"); + } + + pub fn _gen_fields(self: *Self, comptime fields: var) void { + comptime const prefix = "\t "; + + self.write("\t_fields_ = ["); + + inline for (fields) |field, i| { + if (i > 0) { + self.write(prefix); + } + + self.write("("); + + self.write("\"" ++ field.name ++ "\", "); + + const info = @typeInfo(field.field_type); + + if (info == .Array) { + self.writeType(info.Array.child); + } else { + self.writeType(field.field_type); + } + + if (info == .Array) { + _ = self.file.writer().print(" * {}", .{info.Array.len}) catch unreachable; + } + + self.write(")"); + + if (i != fields.len - 1) { + self.write(",\n"); + } + } + + self.write("]\n"); + } + + pub fn gen_struct(self: *Self, comptime name: []const u8, comptime meta: StructMeta) void { + self.write("class " ++ name ++ "(ctypes.Structure):\n"); + + if (meta.layout == .Packed) { + self.write("\t_pack_ = 1\n"); + } + + self._gen_fields(meta.fields); + + self.write("\n"); + } + + pub fn gen_enum(self: *Self, comptime name: []const u8, comptime meta: EnumMeta) void { + self.write("class " ++ name ++ "(enum.IntEnum):\n"); + + inline for (meta.fields) |field, i| { + self.write("\t"); + self.writeScreamingSnakeCase(field.name); + _ = self.file.writer().print(" = {}", .{field.value}) catch unreachable; + self.write("\n"); + } + + self.write("\n"); + } + + pub fn gen_union(self: *Self, comptime name: []const u8, comptime meta: UnionMeta) void { + self.write("class " ++ name ++ "(ctypes.Union):\n"); + + self._gen_fields(meta.fields); + + self.write("\n"); + } + + fn writeType(self: *Self, comptime T: type) void { + switch (T) { + void => self.write("None"), + bool => self.writeCtype("c_bool"), + usize => self.writeCtype("c_size_t"), + isize => self.writeCtype("c_int"), // TODO + u8 => self.writeCtype("c_uint8"), + u16 => self.writeCtype("c_uint16"), + u32 => self.writeCtype("c_uint32"), + u64 => self.writeCtype("c_uint64"), + i8 => self.writeCtype("c_int8"), + i16 => self.writeCtype("c_int16"), + i24 => self.writeCtype("int24_t"), // TODO + i32 => self.writeCtype("c_int32"), + i64 => self.writeCtype("c_int54"), + f32 => self.writeCtype("c_float"), + f64 => self.writeCtype("c_double"), + f128 => self.writeCtype("c_longdouble"), + else => { + const meta = @typeInfo(T); + switch (meta) { + .Pointer => { + const child = meta.Pointer.child; + const childmeta = @typeInfo(child); + self.writeCtype("POINTER("); + if (childmeta == .Struct and childmeta.Struct.layout != .Extern) { + self.writeCtype("c_size_t"); + } else { + self.writeType(child); + } + self.write(")"); + }, + .Optional => self.writeType(meta.Optional.child), + .Array => @compileError("Handle goofy looking C Arrays in the calling function"), + else => self.write(@typeName(T)), + } + }, + } + } + + fn writeScreamingSnakeCase(self: *Self, str: []const u8) void { + var new_word: bool = false; + var was_lower: bool = false; + var is_upper: bool = undefined; + + for (str) |char, i| { + is_upper = std.ascii.isUpper(char); + + if (char == '_' and i > 0) { + new_word = true; + continue; + } + + if (new_word == true or (is_upper and was_lower)) { + new_word = false; + was_lower = false; + + self.writeChar('_'); + } else { + was_lower = !is_upper; + } + + self.writeChar(std.ascii.toUpper(char)); + } + } + + fn writeCtype(self: *Self, comptime str: []const u8) void { + self.write("ctypes." ++ str); + } + + fn writeChar(self: *Self, char: u8) void { + self.write(&[1]u8{char}); + } + + fn write(self: *Self, str: []const u8) void { + _ = self.file.writeAll(str) catch unreachable; + } +}; diff --git a/header_gen.zig b/header_gen.zig index 65bee6c..3c92998 100644 --- a/header_gen.zig +++ b/header_gen.zig @@ -6,6 +6,7 @@ const warn = std.debug.warn; // Provided generators pub const C_Generator = @import("generators/c.zig").C_Generator; +pub const Python_Generator = @import("generators/python.zig").Python_Generator; const GeneratorInterface = struct { fn init() void {} From 5fd01a629e4735d1a4645c38f14f852b1deea840 Mon Sep 17 00:00:00 2001 From: "Pedro M. Silva" Date: Thu, 27 Aug 2020 14:36:08 +0100 Subject: [PATCH 02/13] Generic dependencies graph structure --- deps_graph.zig | 427 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 427 insertions(+) create mode 100644 deps_graph.zig diff --git a/deps_graph.zig b/deps_graph.zig new file mode 100644 index 0000000..70531a3 --- /dev/null +++ b/deps_graph.zig @@ -0,0 +1,427 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const StringHashMap = std.StringHashMap; +const ArrayList = std.ArrayList; +const TailQueue = std.TailQueue; + +pub fn DepsGraph(comptime T: type) type { + return struct { + allocator: *Allocator, + // All the pointers to symbols inside this struct are owned by this struct + // More specifically, they sould be freed when removed from the symbols + // hash map. And they should only be removed from there when there are + // no references to them in the dependants_of hash map + symbols: StringHashMap(*Symbol), + // *Symbol owned by self.symbols + dependants_of: StringHashMap(ArrayList(*Symbol)), + // ?*Symbol owned by self.symbols + current_symbol: ?*Symbol, + // TODO + emitted: TailQueue(EmittedSymbol), + + const Self = @This(); + + pub fn init(allocator: *Allocator) Self { + return .{ + .allocator = allocator, + .symbols = StringHashMap(*Symbol).init(allocator), + .dependants_of = StringHashMap(ArrayList(*Symbol)).init(allocator), + .current_symbol = null, + .emitted = TailQueue(EmittedSymbol).init(), + }; + } + + pub fn deinit(self: *Self) void { + var s_iter = self.symbols.iterator(); + while (s_iter.next()) |entry| { + // Here entry.value is a *Symbol, so we deinit the symbol + entry.value.deinit(self.allocator); + + // And free the pointer + self.allocator.destroy(entry); + } + + self.symbols.deinit(); + + var d_iter = self.dependants_of.iterator(); + while (d_iter.next()) |entry| { + // Here entry.value is an ArrayList(*Symbol), so we simply + // deinit the array list (since the pointers were freed already) + entry.value.deinit(); + } + + self.dependants_of.deinit(); + + while (self.emitted.popFirst()) |node| { + self.emitted.destroyNode(node, self.allocator); + } + + self.current_symbol = null; + } + + pub fn isBlocking(self: *Self, symbol_name: []const u8) bool { + // A symbol_name can be blocking if either: + // 1. There is no symbol declared with that name yet + // 2. There is a symbol, but it is blocked by some dependencies too + const symbol = self.symbols.getValue(symbol_name) orelse return true; + + // TODO Should a symbol be able to depend on itself? + // If so, what to do in that case? For now, it blocks itself + // if (symbol == self.current_symbol) return true; + + return symbol.hasDependenciesOfType(.Linear); + } + + pub const BeginSymbolError = error{ DuplicateSymbol, OutOfMemory }; + + pub fn beginSymbol(self: *Self, name: []const u8, payload: T) BeginSymbolError!void { + const result = try self.symbols.getOrPut(name); + + if (result.found_existing) { + return error.DuplicateSymbol; + } + + // Since the allocation can fail, we do not want to leave the state + // inconsistent (with a KV whose value is empty) + errdefer self.symbols.removeAssertDiscard(name); + + result.kv.value = try self.allocator.create(Symbol); + + result.kv.value.* = Symbol.init(self.allocator, name, payload); + + self.current_symbol = result.kv.value; + } + + pub const AddDependencyError = error{ NoSymbol, OutOfMemory }; + + pub fn addDependency(self: *Self, dependency_name: []const u8) AddDependencyError!void { + // If the dependency is not blocking, then there's no need to add it + if (!self.isBlocking(dependency_name)) return; + + var current_symbol = self.current_symbol orelse return error.NoSymbol; + + var already_added: bool = false; + var is_circular: bool = false; + + // Checks if there are other symbols that depend on dependency_name + var result = try self.dependants_of.getOrPut(dependency_name); + + // Creates or retrieves the array list that contains what symbols + // depend on dependency_name. Also checks if this symbol is already there + if (result.found_existing) { + for (result.kv.value.items) |symbol| { + if (symbol == current_symbol) { + already_added = true; + } + } + } else { + result.kv.value = ArrayList(*Symbol).init(self.allocator); + } + + if (!already_added) { + try result.kv.value.append(current_symbol); + + if (self.dependants_of.get(current_symbol.name)) |dependants| { + for (dependants.value.items) |dep| { + if (std.mem.eql(u8, dep.name, dependency_name)) { + try dep.addDependency(.{ .Circular = current_symbol.name }); + + is_circular = true; + + break; + } + } + } + + if (is_circular) { + try current_symbol.addDependency(.{ .Circular = dependency_name }); + } else { + try current_symbol.addDependency(.{ .Linear = dependency_name }); + } + } + + // TODO + // 1. Implement Symbol.addDependency() ✔ + // 2. Implement Symbol.hasDependencies() ✔ + // 3. Implement Symbol.hasDependenciesOfType(tag) ✔ + // 4. Only add dependencies when they are not emitted yet, or ✔ + // the dependency itself is blocked + // 5. Add to the action queue in endSymbol() ✔ + // 6. Implement isBlocking(name) ✔ + } + + pub const EndSymbolError = error{OutOfMemory}; + + pub fn endSymbol(self: *Self) EndSymbolError!void { + var current_symbol = self.current_symbol orelse return; + + var unblock_queue = std.TailQueue(EmittedSymbol).init(); + + if (!self.isBlocking(current_symbol.name)) { + const node = try unblock_queue.createNode(.{ + .symbol = current_symbol, + .partial = current_symbol.hasDependencies(), + }, self.allocator); + + unblock_queue.append(node); + } + + while (unblock_queue.popFirst()) |symbol_node| { + self.emitted.append(symbol_node); + + const symbol = symbol_node.data.symbol; + + if (self.dependants_of.get(symbol.name)) |kv| { + for (kv.value.items) |dependant| { + if (dependant.removeDependency(symbol.name)) |dep| { + const unblock_dep = (dep == .Linear and !dependant.hasDependenciesOfType(.Linear)) or (dep == .Circular and !dependant.hasDependencies()); + + if (!unblock_dep) continue; + + const node = try unblock_queue.createNode(.{ + .symbol = dependant, + .partial = dependant.hasDependencies(), + }, self.allocator); + + unblock_queue.append(node); + } + } + } + + // if (!symbol.hasDependenciesOfType(.Linear) or !symbol.hasDependencies()) {} + } + + self.current_symbol = null; + } + + pub fn readEmitted(self: *Self) ?EmittedSymbol { + var symbol_node = self.emitted.popFirst() orelse return null; + + var symbol = symbol_node.data; + + self.emitted.destroyNode(symbol_node, self.allocator); + + return symbol; + } + + pub fn blockedIterator(self: *Self) BlockedSymbolsIterator { + return BlockedSymbolsIterator.init(self); + } + + const Dependency = union(enum) { + Linear: []const u8, + Circular: []const u8, + + pub fn getName(self: Dependency) []const u8 { + return switch (self) { + .Linear => |n| n, + .Circular => |n| n, + }; + } + + pub fn eql(self: Dependency, other: Dependency) bool { + switch (self) { + .Linear => |n| return other == .Linear and std.mem.eql(u8, other.Linear, n), + .Circular => |n| return other == .Circular and std.mem.eql(u8, other.Circular, n), + } + } + + pub fn eqlName(self: Dependency, other: Dependency) bool { + return std.mem.eql(u8, self.getName(), other.getName()); + } + }; + + const EmittedSymbol = struct { + symbol: *Symbol, + partial: bool, + }; + + const Symbol = struct { + // Not owned + name: []const u8, + // Slices not owned + dependencies: ArrayList(Dependency), + + payload: T, + + pub fn init(allocator: *Allocator, name: []const u8, payload: T) Symbol { + return .{ + .name = name, + .dependencies = ArrayList(Dependency).init(allocator), + .payload = payload, + }; + } + + pub fn deinit(self: *Symbol, allocator: *Allocator) void { + self.dependencies.deinit(); + } + + pub fn addDependency(self: *Symbol, dependency: Dependency) !void { + for (self.dependencies.items) |*existing| { + if (dependency.eqlName(existing.*)) { + existing.* = dependency; + + return; + } + } + + try self.dependencies.append(dependency); + } + + pub fn removeDependency(self: *Symbol, dependency_name: []const u8) ?Dependency { + var maybe_dep_index: ?usize = null; + + for (self.dependencies.items) |dependency, i| { + if (dependency.eqlName(dependency)) { + maybe_dep_index = i; + break; + } + } + + if (maybe_dep_index) |dep_index| { + // Since dependencies are not stored in any particurarly + // important order, we can use swapRemove which is more + // efficient than orderedRemove + return self.dependencies.swapRemove(dep_index); + } + + return null; + } + + pub fn getDependency(self: *Symbol, dependency_name: []const u8) ?Dependency { + for (self.dependencies.items) |dependency| { + if (dependency.eqlName(dependency)) { + return dependency; + } + } + + return null; + } + + pub fn hasDependencies(self: *Symbol) bool { + return self.dependencies.items.len > 0; + } + + pub fn hasDependenciesOfType(self: *Symbol, tag: @TagType(Dependency)) bool { + for (self.dependencies.items) |dep| { + if (dep == tag) return true; + } + + return false; + } + }; + + pub const BlockedSymbolsIterator = struct { + graph: *Self, + hash_iter: StringHashMap(*Symbol).Iterator, + + pub fn init(graph: *Self) BlockedSymbolsIterator { + return .{ + .graph = graph, + .hash_iter = graph.symbols.iterator(), + }; + } + + pub fn next(self: *BlockedSymbolsIterator) ?*Symbol { + while (self.hash_iter.next()) |symbol| { + if (symbol.value.hasDependenciesOfType(.Linear)) { + return symbol.value; + } + } + + return null; + } + }; + }; +} + +const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; +const expectEqualStrings = std.testing.expectEqualStrings; + +test "Simple dependency graph with circular dependencies" { + const allocator = std.testing.allocator; + + var deps = DepsGraph(void).init(allocator); + + try deps.beginSymbol("SourceMap", {}); + try deps.addDependency("TextSpan"); + try deps.endSymbol(); + expect(deps.readEmitted() == null); + + try deps.beginSymbol("TextSpan", {}); + try deps.addDependency("TextPosition"); + try deps.endSymbol(); + expect(deps.readEmitted() == null); + + try deps.beginSymbol("TextPosition", {}); + try deps.addDependency("TextSpan"); + try deps.endSymbol(); + + expect(deps.emitted.first != null); + if (deps.readEmitted()) |s| { + expectEqualStrings(s.symbol.name, "TextPosition"); + expectEqual(s.partial, true); + } + + expect(deps.emitted.first != null); + if (deps.readEmitted()) |s| { + expectEqualStrings(s.symbol.name, "TextSpan"); + expectEqual(s.partial, false); + } + + expect(deps.emitted.first != null); + if (deps.readEmitted()) |s| { + expectEqualStrings(s.symbol.name, "SourceMap"); + expectEqual(s.partial, false); + } + + expect(deps.emitted.first != null); + if (deps.readEmitted()) |s| { + expectEqualStrings(s.symbol.name, "TextPosition"); + expectEqual(s.partial, false); + } + + expect(deps.readEmitted() == null); + + deps.deinit(); +} + +test "Blocked symbols iterator" { + const allocator = std.testing.allocator; + + var deps = DepsGraph(void).init(allocator); + + try deps.beginSymbol("SourceMap", {}); + try deps.addDependency("TextSpan"); + try deps.endSymbol(); + expect(deps.readEmitted() == null); + + try deps.beginSymbol("TextSpan", {}); + try deps.endSymbol(); + expect(deps.emitted.first != null); + if (deps.readEmitted()) |s| { + expectEqualStrings(s.symbol.name, "TextSpan"); + expectEqual(s.partial, false); + } + expect(deps.emitted.first != null); + if (deps.readEmitted()) |s| { + expectEqualStrings(s.symbol.name, "SourceMap"); + expectEqual(s.partial, false); + } + expect(deps.readEmitted() == null); + + try deps.beginSymbol("TextPosition", {}); + try deps.addDependency("Cursor"); + try deps.endSymbol(); + expect(deps.readEmitted() == null); + + var iter = deps.blockedIterator(); + var symbol = iter.next(); + + expect(symbol != null); + expectEqualStrings(symbol.?.name, "TextPosition"); + expect(iter.next() == null); + + deps.deinit(); +} From d7898f693899947df8d73ca675b9797af56c1129 Mon Sep 17 00:00:00 2001 From: "Pedro M. Silva" Date: Sun, 30 Aug 2020 16:57:43 +0100 Subject: [PATCH 03/13] WIP Switch headergen from comptime --- build.zig | 13 +- generators/python.zig | 204 --------- deps_graph.zig => src/deps_graph.zig | 5 +- src/{ => example}/exports.zig | 16 +- src/{ => example}/main.zig | 0 {generators => src/generators}/c.zig | 4 +- src/generators/ordered.zig | 138 ++++++ src/generators/python.zig | 219 +++++++++ header_gen.zig => src/header_gen.zig | 37 +- src/runtime.zig | 647 +++++++++++++++++++++++++++ 10 files changed, 1057 insertions(+), 226 deletions(-) delete mode 100644 generators/python.zig rename deps_graph.zig => src/deps_graph.zig (98%) rename src/{ => example}/exports.zig (51%) rename src/{ => example}/main.zig (100%) rename {generators => src/generators}/c.zig (98%) create mode 100644 src/generators/ordered.zig create mode 100644 src/generators/python.zig rename header_gen.zig => src/header_gen.zig (79%) create mode 100644 src/runtime.zig diff --git a/build.zig b/build.zig index c8a2c27..9582d94 100644 --- a/build.zig +++ b/build.zig @@ -1,5 +1,4 @@ const Builder = @import("std").build.Builder; -const header_gen = @import("header_gen.zig"); const std = @import("std"); const warn = std.debug.warn; @@ -11,19 +10,17 @@ pub fn build(b: *Builder) void { const mode = b.standardReleaseOptions(); - const exe = b.addExecutable("example", "src/main.zig"); + // HEADER GEN BUILD STEP + const exe = b.addExecutable("example", "src/example/exports.zig"); + exe.main_pkg_path = "src/"; exe.setTarget(target); exe.setBuildMode(mode); + exe.addPackagePath("header_gen", "src/header_gen.zig"); exe.install(); const run_cmd = exe.run(); run_cmd.step.dependOn(b.getInstallStep()); - const run_step = b.step("run", "Run the app"); + const run_step = b.step("headergen", "Run the app"); run_step.dependOn(&run_cmd.step); - - // --- Using header_gen - const gen = header_gen.HeaderGen("src/exports.zig").init(); - gen.exec(header_gen.C_Generator); - gen.exec(header_gen.Python_Generator); } diff --git a/generators/python.zig b/generators/python.zig deleted file mode 100644 index 4e058e2..0000000 --- a/generators/python.zig +++ /dev/null @@ -1,204 +0,0 @@ -const std = @import("std"); -const Dir = std.fs.Dir; -const FnMeta = std.builtin.TypeInfo.Fn; -const FnDecl = std.builtin.TypeInfo.Declaration.Data.FnDecl; -const StructMeta = std.builtin.TypeInfo.Struct; -const EnumMeta = std.builtin.TypeInfo.Enum; -const UnionMeta = std.builtin.TypeInfo.Union; -const warn = std.debug.warn; - -pub const Python_Generator = struct { - file: std.fs.File, - - const Self = @This(); - - pub fn init(comptime src_file: []const u8, dst_dir: *Dir) Self { - comptime const filebaseext = std.fs.path.basename(src_file); - // The .len - 4 assumes a .zig extension - comptime const filebase = filebaseext[0 .. filebaseext.len - 4]; - - var file = dst_dir.createFile(filebase ++ ".py", .{}) catch - @panic("Failed to create header file for source: " ++ src_file); - - var res = Self{ .file = file }; - - res.write( - \\import ctypes - \\import enum - \\ - ); - - res.write("lib = ctypes.cdll.LoadLibrary(\"" ++ filebase ++ ".dll\")\n\n"); - - return res; - } - - pub fn deinit(self: *Self) void { - self.file.close(); - } - - pub fn gen_func(self: *Self, comptime name: []const u8, comptime func: FnDecl, comptime meta: FnMeta) void { - self.write("lib." ++ name ++ ".argtypes = ["); - - inline for (meta.args) |arg, i| { - self.writeType(arg.arg_type.?); - - if (i != meta.args.len - 1) { - self.write(", "); - } - } - - self.write("]\n"); - - self.write("lib." ++ name ++ ".restype = "); - self.writeType(func.return_type); - self.write("\n\n"); - } - - pub fn _gen_fields(self: *Self, comptime fields: var) void { - comptime const prefix = "\t "; - - self.write("\t_fields_ = ["); - - inline for (fields) |field, i| { - if (i > 0) { - self.write(prefix); - } - - self.write("("); - - self.write("\"" ++ field.name ++ "\", "); - - const info = @typeInfo(field.field_type); - - if (info == .Array) { - self.writeType(info.Array.child); - } else { - self.writeType(field.field_type); - } - - if (info == .Array) { - _ = self.file.writer().print(" * {}", .{info.Array.len}) catch unreachable; - } - - self.write(")"); - - if (i != fields.len - 1) { - self.write(",\n"); - } - } - - self.write("]\n"); - } - - pub fn gen_struct(self: *Self, comptime name: []const u8, comptime meta: StructMeta) void { - self.write("class " ++ name ++ "(ctypes.Structure):\n"); - - if (meta.layout == .Packed) { - self.write("\t_pack_ = 1\n"); - } - - self._gen_fields(meta.fields); - - self.write("\n"); - } - - pub fn gen_enum(self: *Self, comptime name: []const u8, comptime meta: EnumMeta) void { - self.write("class " ++ name ++ "(enum.IntEnum):\n"); - - inline for (meta.fields) |field, i| { - self.write("\t"); - self.writeScreamingSnakeCase(field.name); - _ = self.file.writer().print(" = {}", .{field.value}) catch unreachable; - self.write("\n"); - } - - self.write("\n"); - } - - pub fn gen_union(self: *Self, comptime name: []const u8, comptime meta: UnionMeta) void { - self.write("class " ++ name ++ "(ctypes.Union):\n"); - - self._gen_fields(meta.fields); - - self.write("\n"); - } - - fn writeType(self: *Self, comptime T: type) void { - switch (T) { - void => self.write("None"), - bool => self.writeCtype("c_bool"), - usize => self.writeCtype("c_size_t"), - isize => self.writeCtype("c_int"), // TODO - u8 => self.writeCtype("c_uint8"), - u16 => self.writeCtype("c_uint16"), - u32 => self.writeCtype("c_uint32"), - u64 => self.writeCtype("c_uint64"), - i8 => self.writeCtype("c_int8"), - i16 => self.writeCtype("c_int16"), - i24 => self.writeCtype("int24_t"), // TODO - i32 => self.writeCtype("c_int32"), - i64 => self.writeCtype("c_int54"), - f32 => self.writeCtype("c_float"), - f64 => self.writeCtype("c_double"), - f128 => self.writeCtype("c_longdouble"), - else => { - const meta = @typeInfo(T); - switch (meta) { - .Pointer => { - const child = meta.Pointer.child; - const childmeta = @typeInfo(child); - self.writeCtype("POINTER("); - if (childmeta == .Struct and childmeta.Struct.layout != .Extern) { - self.writeCtype("c_size_t"); - } else { - self.writeType(child); - } - self.write(")"); - }, - .Optional => self.writeType(meta.Optional.child), - .Array => @compileError("Handle goofy looking C Arrays in the calling function"), - else => self.write(@typeName(T)), - } - }, - } - } - - fn writeScreamingSnakeCase(self: *Self, str: []const u8) void { - var new_word: bool = false; - var was_lower: bool = false; - var is_upper: bool = undefined; - - for (str) |char, i| { - is_upper = std.ascii.isUpper(char); - - if (char == '_' and i > 0) { - new_word = true; - continue; - } - - if (new_word == true or (is_upper and was_lower)) { - new_word = false; - was_lower = false; - - self.writeChar('_'); - } else { - was_lower = !is_upper; - } - - self.writeChar(std.ascii.toUpper(char)); - } - } - - fn writeCtype(self: *Self, comptime str: []const u8) void { - self.write("ctypes." ++ str); - } - - fn writeChar(self: *Self, char: u8) void { - self.write(&[1]u8{char}); - } - - fn write(self: *Self, str: []const u8) void { - _ = self.file.writeAll(str) catch unreachable; - } -}; diff --git a/deps_graph.zig b/src/deps_graph.zig similarity index 98% rename from deps_graph.zig rename to src/deps_graph.zig index 70531a3..a3c4584 100644 --- a/deps_graph.zig +++ b/src/deps_graph.zig @@ -67,7 +67,7 @@ pub fn DepsGraph(comptime T: type) type { // TODO Should a symbol be able to depend on itself? // If so, what to do in that case? For now, it blocks itself - // if (symbol == self.current_symbol) return true; + // if (symbol == self.current_symbol) return false; return symbol.hasDependenciesOfType(.Linear); } @@ -100,6 +100,9 @@ pub fn DepsGraph(comptime T: type) type { var current_symbol = self.current_symbol orelse return error.NoSymbol; + // If a symbol depends on itself, whatever, not our business + if (std.mem.eql(u8, dependency_name, current_symbol.name)) return; + var already_added: bool = false; var is_circular: bool = false; diff --git a/src/exports.zig b/src/example/exports.zig similarity index 51% rename from src/exports.zig rename to src/example/exports.zig index 89755fd..2dac317 100644 --- a/src/exports.zig +++ b/src/example/exports.zig @@ -1,13 +1,16 @@ +const rt = @import("../runtime.zig"); +const header_gen = @import("header_gen"); + export fn thing(one: usize, two: *LameType, three: [*]u16) bool { return one == 1; } -export fn break_point(v: [*]ThisWillBeVoid) callconv(.Naked) void { +export fn break_point(v: [*]u8) callconv(.Naked) void { @breakpoint(); } const LameType = extern struct { - blah: u64, + blah: WackType, }; const WackType = packed struct { @@ -15,7 +18,7 @@ const WackType = packed struct { }; const WhatsAUnion = extern union { - a: LameType, + a: *LameType, b: u64, }; @@ -29,3 +32,10 @@ const LookMaAnEnum = extern enum { four, five = 5, }; + +pub fn main () void { + const gen = header_gen.HeaderGen(@This(), "lib").init(); + + gen.exec(header_gen.C_Generator); + gen.exec(header_gen.Ordered_Generator(header_gen.Python_Generator)); +} \ No newline at end of file diff --git a/src/main.zig b/src/example/main.zig similarity index 100% rename from src/main.zig rename to src/example/main.zig diff --git a/generators/c.zig b/src/generators/c.zig similarity index 98% rename from generators/c.zig rename to src/generators/c.zig index 7966c4b..e7e23e4 100644 --- a/generators/c.zig +++ b/src/generators/c.zig @@ -43,7 +43,7 @@ pub const C_Generator = struct { self.file.close(); } - pub fn gen_func(self: *Self, comptime name: []const u8, comptime func: FnDecl, comptime meta: FnMeta) void { + pub fn gen_func(self: *Self, comptime name: []const u8, comptime meta: FnMeta) void { switch (meta.calling_convention) { .Naked => self.write("__attribute__((naked)) "), .Stdcall => self.write("__attribute__((stdcall)) "), @@ -52,7 +52,7 @@ pub const C_Generator = struct { else => {}, } - self.writeType(func.return_type); + self.writeType(meta.return_type.?); self.write(" " ++ name ++ "("); inline for (meta.args) |arg, i| { diff --git a/src/generators/ordered.zig b/src/generators/ordered.zig new file mode 100644 index 0000000..4e43c0c --- /dev/null +++ b/src/generators/ordered.zig @@ -0,0 +1,138 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; +const FnMeta = std.builtin.TypeInfo.Fn; +const FnDecl = std.builtin.TypeInfo.Declaration.Data.FnDecl; +const StructMeta = std.builtin.TypeInfo.Struct; +const EnumMeta = std.builtin.TypeInfo.Enum; +const UnionMeta = std.builtin.TypeInfo.Union; +const Dir = std.fs.Dir; +const DepsGraph = @import("../deps_graph.zig").DepsGraph; +const rt = @import("../runtime.zig"); + +const SymbolDeclaration = union(enum) { + Struct: rt.TypeInfo.Struct, + Union: rt.TypeInfo.Union, + Enum: rt.TypeInfo.Enum, + + pub fn deinit(self: SymbolDeclaration, allocator: *Allocator) void { + switch (self) { + .Struct => |s| s.deinit(allocator), + .Union => |u| u.deinit(allocator), + .Enum => |e| e.deinit(allocator), + } + } +}; + +fn isSymbolDependency(comptime symbol_type: type) bool { + const info = @typeInfo(symbol_type); + + return switch (info) { + .Struct, .Union, .Enum => true, + else => false, + }; +} + +fn getTypeName (comptime T: type) []const u8 { + comptime const type_info = @typeInfo(T); + + return switch (type_info) { + .Pointer => |p| getTypeName(p.child), + .Array => |p| getTypeName(p.child), + else => @typeName(T), + }; +} + +pub fn Ordered_Generator(comptime Generator: type) type { + return struct { + inner_gen: Generator, + allocator: *Allocator, + symbols: DepsGraph(SymbolDeclaration), + + const Self = @This(); + + pub fn init(comptime src_file: []const u8, dst_dir: *Dir) Self { + var allocator = std.heap.page_allocator; + + return Self{ + .inner_gen = Generator.init(src_file, dst_dir), + .allocator = allocator, + .symbols = DepsGraph(SymbolDeclaration).init(allocator), + }; + } + + pub fn deinit(self: *Self) void { + self.flush(); + + self.inner_gen.deinit(); + + // TODO Enable deinit hashmap. Right now it segfaults, reason unknown + // var iter = self.symbols.symbols.iterator(); + // while (iter.next()) |kv| { + // kv.value.payload.deinit(self.allocator); + // } + + // self.symbols.deinit(); + } + + fn flush(self: *Self) void { + while (self.symbols.readEmitted()) |emitted| { + // Handle emitted.partial + switch (emitted.symbol.payload) { + .Struct => |meta| self.inner_gen.gen_struct(emitted.symbol.name, meta), + .Union => |meta| self.inner_gen.gen_union(emitted.symbol.name, meta), + .Enum => |meta| self.inner_gen.gen_enum(emitted.symbol.name, meta), + } + } + } + + pub fn gen_func(self: *Self, comptime name: []const u8, comptime meta: FnMeta) void { + self.flush(); + + // var rt_func = rt.TypeInfo.copy(rt.TypeInfo.Declaration.Data.FnDecl, self.allocator, func); + // defer rt_func.deinit(self.allocator); + + var rt_meta = rt.TypeInfo.copy2(rt.TypeInfo.Fn, self.allocator, meta, 2); + defer rt_meta.deinit(self.allocator); + + self.inner_gen.gen_func(name, rt_meta); + } + + pub fn gen_struct(self: *Self, comptime name: []const u8, comptime meta: StructMeta) void { + var decl: SymbolDeclaration = SymbolDeclaration{ .Struct = rt.TypeInfo.copy(rt.TypeInfo.Struct, self.allocator, meta) }; + + self.symbols.beginSymbol(name, decl) catch |err| @panic(@errorName(err)); + inline for (meta.fields) |f| { + if (comptime isSymbolDependency(f.field_type)) { + self.symbols.addDependency(getTypeName(f.field_type)) catch |err| @panic(@errorName(err)); + } + } + self.symbols.endSymbol() catch |err| @panic(@errorName(err)); + + self.flush(); + } + + pub fn gen_enum(self: *Self, comptime name: []const u8, comptime meta: EnumMeta) void { + var decl: SymbolDeclaration = SymbolDeclaration{ .Enum = rt.TypeInfo.copy(rt.TypeInfo.Enum, self.allocator, meta) }; + + self.symbols.beginSymbol(name, decl) catch |err| @panic(@errorName(err)); + // Enums have no type dependencies I think, yay + self.symbols.endSymbol() catch |err| @panic(@errorName(err)); + + self.flush(); + } + + pub fn gen_union(self: *Self, comptime name: []const u8, comptime meta: UnionMeta) void { + var decl: SymbolDeclaration = SymbolDeclaration{ .Union = rt.TypeInfo.copy(rt.TypeInfo.Union, self.allocator, meta) }; + + self.symbols.beginSymbol(name, decl) catch |err| @panic(@errorName(err)); + inline for (meta.fields) |f| { + if (comptime isSymbolDependency(f.field_type)) { + self.symbols.addDependency(getTypeName(f.field_type)) catch |err| @panic(@errorName(err)); + } + } + self.symbols.endSymbol() catch |err| @panic(@errorName(err)); + + self.flush(); + } + }; +} diff --git a/src/generators/python.zig b/src/generators/python.zig new file mode 100644 index 0000000..a3794fb --- /dev/null +++ b/src/generators/python.zig @@ -0,0 +1,219 @@ +const std = @import("std"); +const Dir = std.fs.Dir; +const warn = std.debug.warn; +const rt = @import("../runtime.zig"); +const FnDecl = rt.TypeInfo.Declaration.Data.FnDecl; +const FnMeta = rt.TypeInfo.Fn; +const StructMeta = rt.TypeInfo.Struct; +const EnumMeta = rt.TypeInfo.Enum; +const UnionMeta = rt.TypeInfo.Union; + +pub const Python_Generator = struct { + pub const symbols_order: bool = false; + + file: std.fs.File, + + const Self = @This(); + + pub fn init(comptime src_file: []const u8, dst_dir: *Dir) Self { + comptime const filebaseext = std.fs.path.basename(src_file); + // The .len - 4 assumes a .zig extension + comptime const filebase = filebaseext[0 .. filebaseext.len - 4]; + + var file = dst_dir.createFile(filebase ++ ".py", .{}) catch + @panic("Failed to create header file for source: " ++ src_file); + + var res = Self{ .file = file }; + + res.write( + \\import ctypes + \\import enum + \\ + ); + + res.write("lib = ctypes.cdll.LoadLibrary(\"" ++ filebase ++ ".dll\")\n\n"); + + return res; + } + + pub fn deinit(self: *Self) void { + self.file.close(); + } + + pub fn gen_func(self: *Self, name: []const u8, meta: FnMeta) void { + self.print("lib.{}.argtypes = [", .{name}); + + for (meta.args) |arg, i| { + if (arg.arg_type) |t| { + self.writeType(t.*); + } else { + self.write("None"); + } + + if (i != meta.args.len - 1) { + self.write(", "); + } + } + + self.write("]\n"); + + self.print("lib.{}.restype = ", .{name}); + if (meta.return_type) |return_type| { + self.writeType(return_type.*); + } else { + self.write("None"); + } + self.write("\n\n"); + } + + pub fn _gen_fields(self: *Self, fields: var) void { + comptime const prefix = "\t "; + + self.write("\t_fields_ = ["); + + for (fields) |field, i| { + if (i > 0) { + self.write(prefix); + } + + self.print("(\"{}\", ",.{field.name}); + + const info = field.field_type.*; + + if (info == .Array) { + self.writeType(info.Array.child.*); + } else { + self.writeType(info); + } + + if (info == .Array) { + self.print(" * {}", .{info.Array.len}); + } + + self.write(")"); + + if (i != fields.len - 1) { + self.write(",\n"); + } + } + + self.write("]\n"); + } + + pub fn gen_struct(self: *Self, name: []const u8, meta: StructMeta) void { + self.print("class {}(ctypes.Structure):\n", .{name}); + + if (meta.layout == .Packed) { + self.write("\t_pack_ = 1\n"); + } + + self._gen_fields(meta.fields); + + self.write("\n"); + } + + pub fn gen_enum(self: *Self, name: []const u8, meta: EnumMeta) void { + self.print("class {}(enum.IntEnum):\n", .{name}); + + for (meta.fields) |field, i| { + self.write("\t"); + self.writeScreamingSnakeCase(field.name); + self.print(" = {}\n", .{field.value}); + } + + if (meta.fields.len == 0) { + self.write("\tpass"); + } + + self.write("\n"); + } + + pub fn gen_union(self: *Self, name: []const u8, meta: UnionMeta) void { + self.print("class {}(ctypes.Union):\n", .{name}); + + self._gen_fields(meta.fields); + + self.write("\n"); + } + + fn writeType(self: *Self, meta: rt.TypeInfo) void { + switch (meta) { + .Void => self.write("None"), + .Bool => self.write("ctypes.c_bool"), + // .usize => self.writeCtype("c_usize"), // TODO + // .isize => self.writeCtype("c_isize"), // TODO + .Int => |i| { + switch (i.is_signed) { + true => self.print("ctypes.c_int{}", .{i.bits}), + false => self.print("ctypes.c_uint{}", .{i.bits}), + } + }, + .Float => |f| { + switch (f.bits) { + 32 => self.write("c_float"), + 64 => self.write("c_double"), + 128 => self.write("c_longdouble"), + else => self.print("ctypes.c_f{}", .{f.bits}), + } + }, + .Struct => |s| self.write(s.name orelse "__unknown__"), + .Union => |s| self.write(s.name orelse "__unknown__"), + .Enum => |s| self.write(s.name orelse "__unknown__"), + .Pointer => |p| { + const childmeta = p.child.*; + self.writeCtype("POINTER("); + if (childmeta == .Struct and childmeta.Struct.layout != .Extern) { + self.writeCtype("c_size_t"); + } else { + self.writeType(childmeta); + } + self.write(")"); + }, + .Optional => self.writeType(meta.Optional.child.*), + .Array => {}, // TODO @compileError("Handle goofy looking C Arrays in the calling function"), + else => self.write(@tagName(meta)), // TODO!!!!! + } + } + + fn writeScreamingSnakeCase(self: *Self, str: []const u8) void { + var new_word: bool = false; + var was_lower: bool = false; + var is_upper: bool = undefined; + + for (str) |char, i| { + is_upper = std.ascii.isUpper(char); + + if (char == '_' and i > 0) { + new_word = true; + continue; + } + + if (new_word == true or (is_upper and was_lower)) { + new_word = false; + was_lower = false; + + self.writeChar('_'); + } else { + was_lower = !is_upper; + } + + self.writeChar(std.ascii.toUpper(char)); + } + } + + fn writeCtype(self: *Self, comptime str: []const u8) void { + self.write("ctypes." ++ str); + } + + fn writeChar(self: *Self, char: u8) void { + self.write(&[1]u8{char}); + } + + fn print(self: *Self, comptime fmt: []const u8, args: var) void { + self.file.writer().print(fmt, args) catch unreachable; + } + + fn write(self: *Self, str: []const u8) void { + _ = self.file.writeAll(str) catch unreachable; + } +}; diff --git a/header_gen.zig b/src/header_gen.zig similarity index 79% rename from header_gen.zig rename to src/header_gen.zig index 3c92998..89047f1 100644 --- a/header_gen.zig +++ b/src/header_gen.zig @@ -7,6 +7,7 @@ const warn = std.debug.warn; // Provided generators pub const C_Generator = @import("generators/c.zig").C_Generator; pub const Python_Generator = @import("generators/python.zig").Python_Generator; +pub const Ordered_Generator = @import("generators/ordered.zig").Ordered_Generator; const GeneratorInterface = struct { fn init() void {} @@ -17,6 +18,23 @@ const GeneratorInterface = struct { fn gen_union() void {} }; + +fn includeSymbol(comptime decl: Declaration) bool { + if (decl.data == .Type) { + const T = decl.data.Type; + const info = @typeInfo(T); + + return switch (info) { + .Struct => |s| s.layout == .Extern or s.layout == .Packed, + .Union => |u| u.layout == .Extern, + .Enum => |e| e.layout == .Extern, + else => false + }; + } + + return false; +} + fn validateGenerator(comptime Generator: type) void { comptime { const interface = @typeInfo(GeneratorInterface).Struct.decls; @@ -32,15 +50,12 @@ fn validateGenerator(comptime Generator: type) void { } } -pub fn HeaderGen(comptime fname: []const u8) type { - comptime var all_decls: []const Declaration = undefined; - comptime { - const import = @typeInfo(@import(fname)); - all_decls = import.Struct.decls; - } +pub fn HeaderGen(comptime S: type, comptime libname: []const u8) type { + comptime var all_decls: []const Declaration = @typeInfo(S).Struct.decls; + return struct { decls: @TypeOf(all_decls) = all_decls, - source_file: []const u8 = fname, + source_file: []const u8 = libname ++ ".zig", const Self = @This(); @@ -112,7 +127,13 @@ pub fn HeaderGen(comptime fname: []const u8) type { if (func.is_export) { //TODO: Look into parsing file for argument names const fn_meta = @typeInfo(func.fn_type).Fn; - gen.gen_func(decl.name, func, fn_meta); + gen.gen_func(decl.name, fn_meta); + } + } else if (decl.data == .Var) { + const fn_meta = @typeInfo(decl.data.Var); + + if (fn_meta == .Fn) { + gen.gen_func(decl.name, fn_meta.Fn); } } } diff --git a/src/runtime.zig b/src/runtime.zig new file mode 100644 index 0000000..d721d40 --- /dev/null +++ b/src/runtime.zig @@ -0,0 +1,647 @@ +const std = @import("std"); +const Allocator = std.mem.Allocator; + +pub const TypeId = @TagType(TypeInfo); + +pub const TypeInfo = union(enum) { + Type: void, + Void: void, + Bool: void, + NoReturn: void, + Int: Int, + Float: Float, + Pointer: Pointer, + Array: Array, + Struct: Struct, + ComptimeFloat: void, + ComptimeInt: void, + Undefined: void, + Null: void, + Optional: Optional, + ErrorUnion: ErrorUnion, + ErrorSet: ErrorSet, + Enum: Enum, + Union: Union, + Fn: Fn, + BoundFn: Fn, + Opaque: void, + Frame: Frame, + AnyFrame: AnyFrame, + Vector: Vector, + EnumLiteral: void, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Int = struct { + is_signed: bool, + bits: i32, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Float = struct { + bits: i32, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Pointer = struct { + size: Size, + is_const: bool, + is_volatile: bool, + alignment: i32, + child: *TypeInfo, + is_allowzero: bool, + /// This field is an optional type. + /// The type of the sentinel is the element type of the pointer, which is + /// the value of the `child` field in this struct. However there is no way + /// to refer to that type here, so we use `var`. + // sentinel: var, + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Size = enum { + One, + Many, + Slice, + C, + }; + + pub fn deinit(self: *const Pointer, allocator: *Allocator) void { + self.child.deinit(allocator); + + allocator.destroy(self.child); + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Array = struct { + len: i32, + child: *TypeInfo, + /// This field is an optional type. + /// The type of the sentinel is the element type of the array, which is + /// the value of the `child` field in this struct. However there is no way + /// to refer to that type here, so we use `var`. + // sentinel: var, + pub fn deinit(self: *const Array, allocator: *Allocator) void { + self.child.deinit(allocator); + + allocator.destroy(self.child); + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const ContainerLayout = enum { + Auto, + Extern, + Packed, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const StructField = struct { + name: []const u8, + field_type: *TypeInfo, + // default_value: var, + + pub fn deinit(self: *const StructField, allocator: *Allocator) void { + allocator.free(self.name); + + self.field_type.deinit(allocator); + + allocator.destroy(self.field_type); + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Struct = struct { + name: ?[]const u8, + layout: ContainerLayout, + fields: []const StructField, + decls: []const Declaration, + + pub fn deinit(self: *const Struct, allocator: *Allocator) void { + for (self.fields) |f| f.deinit(allocator); + for (self.decls) |f| f.deinit(allocator); + + allocator.free(self.fields); + allocator.free(self.decls); + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Optional = struct { + child: *TypeInfo, + + pub fn deinit(self: *const Optional, allocator: *Allocator) void { + self.child.deinit(allocator); + + allocator.destroy(self.child); + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const ErrorUnion = struct { + error_set: *TypeInfo, + payload: *TypeInfo, + + pub fn deinit(self: *const ErrorUnion, allocator: *Allocator) void { + self.error_set.deinit(allocator); + allocator.destroy(self.error_set); + + self.payload.deinit(allocator); + allocator.destroy(self.payload); + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Error = struct { + name: []const u8, + + pub fn deinit(self: *const Error, allocator: *Allocator) void { + allocator.free(self.name); + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const ErrorSet = ?[]const Error; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const EnumField = struct { + name: []const u8, + value: i32, + + pub fn deinit(self: *const EnumField, allocator: *Allocator) void { + allocator.free(self.name); + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Enum = struct { + name: ?[]const u8, + layout: ContainerLayout, + tag_type: *TypeInfo, + fields: []const EnumField, + decls: []const Declaration, + is_exhaustive: bool, + + pub fn deinit(self: *const Enum, allocator: *Allocator) void { + for (self.fields) |f| f.deinit(allocator); + for (self.decls) |f| f.deinit(allocator); + + allocator.free(self.fields); + allocator.free(self.decls); + + self.tag_type.deinit(allocator); + allocator.destroy(self.tag_type); + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const UnionField = struct { + name: []const u8, + enum_field: ?EnumField, + field_type: *TypeInfo, + + pub fn deinit(self: *const UnionField, allocator: *Allocator) void { + allocator.free(self.name); + + self.field_type.deinit(allocator); + + allocator.destroy(self.field_type); + + if (self.enum_field) |ef| { + ef.deinit(allocator); + } + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Union = struct { + name: ?[]const u8, + layout: ContainerLayout, + tag_type: ?*TypeInfo, + fields: []const UnionField, + decls: []const Declaration, + + pub fn deinit(self: *const Union, allocator: *Allocator) void { + for (self.fields) |f| f.deinit(allocator); + for (self.decls) |f| f.deinit(allocator); + + allocator.free(self.fields); + allocator.free(self.decls); + + if (self.tag_type) |tag_type| { + tag_type.deinit(allocator); + + allocator.destroy(tag_type); + } + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const FnArg = struct { + is_generic: bool, + is_noalias: bool, + arg_type: ?*TypeInfo, + + pub fn deinit(self: *const FnArg, allocator: *Allocator) void { + if (self.arg_type) |t| { + t.deinit(allocator); + + allocator.destroy(self.arg_type); + } + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Fn = struct { + calling_convention: CallingConvention, + is_generic: bool, + is_var_args: bool, + return_type: ?*TypeInfo, + args: []const FnArg, + + pub fn deinit(self: *const Fn, allocator: *Allocator) void { + if (self.return_type) |r| { + r.deinit(allocator); + + allocator.destroy(r); + } + + for (self.args) |arg| arg.deinit(allocator); + + allocator.free(self.args); + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Frame = struct { + // function: var, + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const AnyFrame = struct { + child: ?*TypeInfo, + + pub fn deinit(self: *const AnyFrame, allocator: *Allocator) void { + if (self.child) |child| { + child.deinit(allocator); + + allocator.destroy(child); + } + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Vector = struct { + len: i32, + child: *TypeInfo, + + pub fn deinit(self: *const Vector, allocator: *Allocator) void { + self.child.deinit(allocator); + + allocator.destroy(self.child); + } + }; + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Declaration = struct { + name: []const u8, + is_pub: bool, + data: Data, + + pub fn deinit(self: *const Declaration, allocator: *Allocator) void { + self.data.deinit(allocator); + + allocator.free(self.name); + } + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Data = union(enum) { + Type: *TypeInfo, + Var: *TypeInfo, + Fn: FnDecl, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const FnDecl = struct { + fn_type: *TypeInfo, + inline_type: Inline, + is_var_args: bool, + is_extern: bool, + is_export: bool, + lib_name: ?[]const u8, + return_type: *TypeInfo, + arg_names: []const []const u8, + + /// This data structure is used by the Zig language code generation and + /// therefore must be kept in sync with the compiler implementation. + pub const Inline = enum { + Auto, + Always, + Never, + }; + + pub fn deinit(self: *const FnDecl, allocator: *Allocator) void { + self.fn_type.deinit(allocator); + self.return_type.deinit(allocator); + + allocator.destroy(self.fn_type); + allocator.destroy(self.return_type); + + for (self.arg_names) |a| allocator.free(a); + allocator.free(self.arg_names); + + if (self.lib_name) |lib_name| { + allocator.free(lib_name); + } + } + }; + + pub fn deinit(self: *const Data, allocator: *Allocator) void { + switch (self.*) { + .Type, .Var => |t| { + t.deinit(allocator); + + allocator.destroy(t); + }, + .Fn => |f| f.deinit(allocator), + } + } + }; + }; + + pub fn init(allocator: *Allocator, comptime builtin: std.builtin.TypeInfo) TypeInfo { + return TypeInfo.copy(TypeInfo, allocator, builtin); + } + + pub fn init2(allocator: *Allocator, comptime builtin: std.builtin.TypeInfo, comptime depth: u32) TypeInfo { + return TypeInfo.copy2(TypeInfo, allocator, builtin, depth); + } + + pub fn deinit(self: *TypeInfo, allocator: *Allocator) void { + switch (self.*) { + .Array => |a| a.deinit(allocator), + .Pointer => |p| p.deinit(allocator), + .Struct => |s| s.deinit(allocator), + .Union => |u| u.deinit(allocator), + .Enum => |e| e.deinit(allocator), + .Optional => |o| o.deinit(allocator), + .Fn => |f| f.deinit(allocator), + .ErrorUnion => |e| e.deinit(allocator), + .ErrorSet => |maybe_set| { + if (maybe_set) |set| { + for (set) |err| err.deinit(allocator); + + allocator.free(set); + } + }, + .AnyFrame => |a| a.deinit(allocator), + .Vector => |v| v.deinit(allocator), + else => {}, + } + } + + pub fn copy(comptime T: type, allocator: *Allocator, comptime src: var) T { + return TypeInfo.copy2(T, allocator, src, 1); + } + + pub fn copy2(comptime T: type, allocator: *Allocator, comptime src: var, comptime depth: u32) T { + comptime const info = @typeInfo(T); + + if (info == .Void) { + return; + } else if (info == .Pointer and info.Pointer.size == .One and info.Pointer.child == TypeInfo) { + var ptr = allocator.create(TypeInfo) catch unreachable; + + if (depth > 0) { + ptr.* = TypeInfo.init2(allocator, @typeInfo(src), depth - 1); + + if (ptr.* == .Struct) ptr.*.Struct.name = @typeName(src) + else if (ptr.* == .Union) ptr.*.Union.name = @typeName(src) + else if (ptr.* == .Enum) ptr.*.Enum.name = @typeName(src); + } else { + // TODO Create special variant for max-depth + ptr.* = TypeInfo{ .Void = {} }; + } + + return ptr; + } else if (info == .Enum) { + return @intToEnum(T, @enumToInt(src)); + } else if (info == .Pointer and info.Pointer.size == .Slice) { + var dst_slice = allocator.alloc(info.Pointer.child, src.len) catch unreachable; + + inline for (src) |src_val, i| { + dst_slice[i] = TypeInfo.copy2(info.Pointer.child, allocator, src_val, depth); + } + + return dst_slice; + } else if (info == .Struct) { + var obj: T = undefined; + + inline for (info.Struct.fields) |struct_field| { + if (comptime @hasField(@TypeOf(src), struct_field.name)) { + @field(obj, struct_field.name) = TypeInfo.copy2(struct_field.field_type, allocator, @field(src, struct_field.name), depth); + } + } + + return obj; + } else if (info == .Union) { + inline for (info.Union.fields) |union_field| { + comptime var tag_type = @field(@TagType(@TypeOf(src)), union_field.enum_field.?.name); + + if (src == tag_type) { + var obj = TypeInfo.copy2(union_field.field_type, allocator, @field(src, union_field.name), depth); + + return @unionInit(T, union_field.name, obj); + } + } + + @panic("Type not runtimable"); + } else if (info == .Optional) { + if (src) |src_val| { + return TypeInfo.copy2(info.Optional.child, allocator, src_val, depth); + } else { + return null; + } + } else { + return @as(T, src); + } + } +}; + +pub const CallingConvention = enum { + Unspecified, + C, + Cold, + Naked, + Async, + Interrupt, + Signal, + Stdcall, + Fastcall, + Vectorcall, + Thiscall, + APCS, + AAPCS, + AAPCSVFP, +}; + +const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; +const expectEqualStrings = std.testing.expectEqualStrings; + +const talloc = std.testing.allocator; + +// TODO .Type + +test "Runtime TypeInfo.Void" { + var info_void = TypeInfo.init(talloc, @typeInfo(void)); + expect(info_void == .Void); + info_void.deinit(talloc); +} +test "Runtime TypeInfo.Bool" { + var info_bool = TypeInfo.init(talloc, @typeInfo(bool)); + expect(info_bool == .Bool); + info_bool.deinit(talloc); +} + +// TODO .NoReturn + +test "Runtime TypeInfo.Int" { + var info_i32 = TypeInfo.init(talloc, @typeInfo(i32)); + expect(info_i32 == .Int); + expectEqual(@as(i32, 32), info_i32.Int.bits); + expectEqual(true, info_i32.Int.is_signed); + info_i32.deinit(talloc); +} + +test "Runtime TypeInfo.Float" { + var info_f64 = TypeInfo.init(talloc, @typeInfo(f64)); + expect(info_f64 == .Float); + expectEqual(@as(i32, 64), info_f64.Float.bits); + info_f64.deinit(talloc); +} + +test "Runtime TypeInfo.Pointer" { + var info_pointer_f64 = TypeInfo.init(talloc, @typeInfo(*f64)); + expect(info_pointer_f64 == .Pointer); + expectEqual(TypeInfo.Pointer.Size.One, info_pointer_f64.Pointer.size); + expectEqual(false, info_pointer_f64.Pointer.is_const); + expectEqual(false, info_pointer_f64.Pointer.is_volatile); + expectEqual(@as(i32, 8), info_pointer_f64.Pointer.alignment); + expect(info_pointer_f64.Pointer.child.* == .Float); + expectEqual(false, info_pointer_f64.Pointer.is_allowzero); + info_pointer_f64.deinit(talloc); + + var info_pointer_many = TypeInfo.init(talloc, @typeInfo([*]f64)); + expect(info_pointer_many == .Pointer); + expectEqual(TypeInfo.Pointer.Size.Many, info_pointer_many.Pointer.size); + expectEqual(false, info_pointer_many.Pointer.is_const); + expectEqual(false, info_pointer_many.Pointer.is_volatile); + expectEqual(@as(i32, 8), info_pointer_many.Pointer.alignment); + expect(info_pointer_many.Pointer.child.* == .Float); + expectEqual(false, info_pointer_many.Pointer.is_allowzero); + info_pointer_many.deinit(talloc); +} + +test "Runtime TypeInfo.Array" { + var info_array = TypeInfo.init(talloc, @typeInfo([2]i32)); + expect(info_array == .Array); + expectEqual(@as(i32, 2), info_array.Array.len); + expect(info_array.Array.child.* == .Int); + info_array.deinit(talloc); +} + +test "Runtime TypeInfo.Struct" { + const FooStruct = struct { + int: i32, + + pub fn bar() void {} + }; + + var info_struct = TypeInfo.init(talloc, @typeInfo(FooStruct)); + expect(info_struct == .Struct); + expect(info_struct.Struct.layout == .Auto); + expectEqual(@as(usize, 1), info_struct.Struct.fields.len); + expectEqualStrings("int", info_struct.Struct.fields[0].name); + expect(info_struct.Struct.fields[0].field_type.* == .Int); + info_struct.deinit(talloc); +} + +test "Runtime TypeInfo.ComptimeFloat" { + var info_comptime_float = TypeInfo.init(talloc, @typeInfo(comptime_float)); + expect(info_comptime_float == .ComptimeFloat); + info_comptime_float.deinit(talloc); +} + +test "Runtime TypeInfo.ComptimeInt" { + var info_comptime_int = TypeInfo.init(talloc, @typeInfo(comptime_int)); + expect(info_comptime_int == .ComptimeInt); + info_comptime_int.deinit(talloc); +} + +// TODO .Undefined +// TODO .Null + +test "Runtime TypeInfo.Optional" { + var info_optional = TypeInfo.init(talloc, @typeInfo(?i32)); + expect(info_optional == .Optional); + expect(info_optional.Optional.child.* == .Int); + info_optional.deinit(talloc); +} + +// TODO .ErrorUnion +// TODO .ErrorSet + +test "Runtime TypeInfo.Enum" { + const FooEnum = enum { + Foo, Bar + }; + + var info_enum = TypeInfo.init(talloc, @typeInfo(FooEnum)); + expect(info_enum == .Enum); + info_enum.deinit(talloc); +} + +test "Runtime TypeInfo.Union" { + const FooUnion = union { + Foo: void, Bar: i32 + }; + + var info_union = TypeInfo.init(talloc, @typeInfo(FooUnion)); + expect(info_union == .Union); + info_union.deinit(talloc); +} + +test "Runtime TypeInfo.Fn" { + // .Fn + var info_fn = TypeInfo.init(talloc, @typeInfo(fn () void)); + expect(info_fn == .Fn); + info_fn.deinit(talloc); +} + +// TODO .BoundFn +// TODO .Opaque +// TODO .Frame +// TODO .AnyFrame +// TODO .Vector +// TODO .EnumLiteral From ba90d7f8f9c356c746db56dbb1cf017b9560db75 Mon Sep 17 00:00:00 2001 From: "Pedro M. Silva" Date: Mon, 31 Aug 2020 14:18:59 +0100 Subject: [PATCH 04/13] Partial implementation of circular deps --- src/example/exports.zig | 9 ++++----- src/generators/ordered.zig | 41 +++++++++++++++++++++++++++++++++----- src/generators/python.zig | 41 +++++++++++++++++++++++++++----------- src/runtime.zig | 2 +- 4 files changed, 70 insertions(+), 23 deletions(-) diff --git a/src/example/exports.zig b/src/example/exports.zig index 2dac317..0fa0d58 100644 --- a/src/example/exports.zig +++ b/src/example/exports.zig @@ -9,14 +9,13 @@ export fn break_point(v: [*]u8) callconv(.Naked) void { @breakpoint(); } -const LameType = extern struct { - blah: WackType, -}; - const WackType = packed struct { - mr_field: u8, + mr_field: *LameType, }; +const LameType = extern struct { + blah: WackType, +}; const WhatsAUnion = extern union { a: *LameType, b: u64, diff --git a/src/generators/ordered.zig b/src/generators/ordered.zig index 4e43c0c..379b434 100644 --- a/src/generators/ordered.zig +++ b/src/generators/ordered.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const StringHashMap = std.StringHashMap; const Allocator = std.mem.Allocator; const FnMeta = std.builtin.TypeInfo.Fn; const FnDecl = std.builtin.TypeInfo.Declaration.Data.FnDecl; @@ -32,9 +33,9 @@ fn isSymbolDependency(comptime symbol_type: type) bool { }; } -fn getTypeName (comptime T: type) []const u8 { +fn getTypeName(comptime T: type) []const u8 { comptime const type_info = @typeInfo(T); - + return switch (type_info) { .Pointer => |p| getTypeName(p.child), .Array => |p| getTypeName(p.child), @@ -42,11 +43,16 @@ fn getTypeName (comptime T: type) []const u8 { }; } +pub const SymbolPhase = enum { + Signature, Body, Full +}; + pub fn Ordered_Generator(comptime Generator: type) type { return struct { inner_gen: Generator, allocator: *Allocator, symbols: DepsGraph(SymbolDeclaration), + emitted_phase: StringHashMap(SymbolPhase), const Self = @This(); @@ -57,6 +63,7 @@ pub fn Ordered_Generator(comptime Generator: type) type { .inner_gen = Generator.init(src_file, dst_dir), .allocator = allocator, .symbols = DepsGraph(SymbolDeclaration).init(allocator), + .emitted_phase = StringHashMap(SymbolPhase).init(allocator), }; } @@ -72,15 +79,39 @@ pub fn Ordered_Generator(comptime Generator: type) type { // } // self.symbols.deinit(); + + self.emitted_phase.deinit(); + } + + fn getNextPhaseFor(self: *Self, symbol_name: []const u8, partial: bool) !?SymbolPhase { + var result = try self.emitted_phase.getOrPut(symbol_name); + + if (!result.found_existing) { + result.kv.value = if (partial) .Signature else .Full; + + return result.kv.value; + } else if (result.kv.value == .Signature) { + if (partial) { + return null; + } else { + result.kv.value = .Full; + + return .Body; + } + } + + return null; } fn flush(self: *Self) void { while (self.symbols.readEmitted()) |emitted| { + var phase = self.getNextPhaseFor(emitted.symbol.name, emitted.partial) catch unreachable orelse continue ; + // Handle emitted.partial switch (emitted.symbol.payload) { - .Struct => |meta| self.inner_gen.gen_struct(emitted.symbol.name, meta), - .Union => |meta| self.inner_gen.gen_union(emitted.symbol.name, meta), - .Enum => |meta| self.inner_gen.gen_enum(emitted.symbol.name, meta), + .Struct => |meta| self.inner_gen.gen_struct(emitted.symbol.name, meta, phase), + .Union => |meta| self.inner_gen.gen_union(emitted.symbol.name, meta, phase), + .Enum => |meta| self.inner_gen.gen_enum(emitted.symbol.name, meta, phase), } } } diff --git a/src/generators/python.zig b/src/generators/python.zig index a3794fb..aba7f3f 100644 --- a/src/generators/python.zig +++ b/src/generators/python.zig @@ -7,6 +7,7 @@ const FnMeta = rt.TypeInfo.Fn; const StructMeta = rt.TypeInfo.Struct; const EnumMeta = rt.TypeInfo.Enum; const UnionMeta = rt.TypeInfo.Union; +const SymbolPhase = @import("ordered.zig").SymbolPhase; pub const Python_Generator = struct { pub const symbols_order: bool = false; @@ -66,17 +67,21 @@ pub const Python_Generator = struct { self.write("\n\n"); } - pub fn _gen_fields(self: *Self, fields: var) void { + pub fn _gen_fields(self: *Self, name: []const u8, fields: var, phase: SymbolPhase) void { comptime const prefix = "\t "; - self.write("\t_fields_ = ["); + if (phase == .Body) { + self.print("{}._fields_ = [", .{name}); + } else { + self.write("\t_fields_ = ["); + } for (fields) |field, i| { if (i > 0) { self.write(prefix); } - self.print("(\"{}\", ",.{field.name}); + self.print("(\"{}\", ", .{field.name}); const info = field.field_type.*; @@ -100,19 +105,25 @@ pub const Python_Generator = struct { self.write("]\n"); } - pub fn gen_struct(self: *Self, name: []const u8, meta: StructMeta) void { - self.print("class {}(ctypes.Structure):\n", .{name}); + pub fn gen_struct(self: *Self, name: []const u8, meta: StructMeta, phase: SymbolPhase) void { + if (phase != .Body) { + self.print("class {}(ctypes.Structure):\n", .{name}); - if (meta.layout == .Packed) { - self.write("\t_pack_ = 1\n"); + if (meta.layout == .Packed) { + self.write("\t_pack_ = 1\n"); + } } - self._gen_fields(meta.fields); + if (phase != .Signature) { + self._gen_fields(name, meta.fields, phase); + } else if (meta.layout != .Packed) { + self.write("\tpass\n"); + } self.write("\n"); } - pub fn gen_enum(self: *Self, name: []const u8, meta: EnumMeta) void { + pub fn gen_enum(self: *Self, name: []const u8, meta: EnumMeta, phase: SymbolPhase) void { self.print("class {}(enum.IntEnum):\n", .{name}); for (meta.fields) |field, i| { @@ -128,10 +139,16 @@ pub const Python_Generator = struct { self.write("\n"); } - pub fn gen_union(self: *Self, name: []const u8, meta: UnionMeta) void { - self.print("class {}(ctypes.Union):\n", .{name}); + pub fn gen_union(self: *Self, name: []const u8, meta: UnionMeta, phase: SymbolPhase) void { + if (phase != .Body) { + self.print("class {}(ctypes.Union):\n", .{name}); + } - self._gen_fields(meta.fields); + if (phase != .Signature) { + self._gen_fields(name, meta.fields, phase); + } else { + self.write("\tpass\n"); + } self.write("\n"); } diff --git a/src/runtime.zig b/src/runtime.zig index d721d40..10bb34c 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -421,7 +421,7 @@ pub const TypeInfo = union(enum) { } pub fn copy(comptime T: type, allocator: *Allocator, comptime src: var) T { - return TypeInfo.copy2(T, allocator, src, 1); + return TypeInfo.copy2(T, allocator, src, 5); } pub fn copy2(comptime T: type, allocator: *Allocator, comptime src: var, comptime depth: u32) T { From 0ad25ec81a3caacf54c7ac0e936aa591e9fcc6c0 Mon Sep 17 00:00:00 2001 From: "Pedro M. Silva" Date: Mon, 31 Aug 2020 14:24:52 +0100 Subject: [PATCH 05/13] Update to run on zig master --- src/generators/python.zig | 4 ++-- src/runtime.zig | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/generators/python.zig b/src/generators/python.zig index aba7f3f..449a0b6 100644 --- a/src/generators/python.zig +++ b/src/generators/python.zig @@ -67,7 +67,7 @@ pub const Python_Generator = struct { self.write("\n\n"); } - pub fn _gen_fields(self: *Self, name: []const u8, fields: var, phase: SymbolPhase) void { + pub fn _gen_fields(self: *Self, name: []const u8, fields: anytype, phase: SymbolPhase) void { comptime const prefix = "\t "; if (phase == .Body) { @@ -226,7 +226,7 @@ pub const Python_Generator = struct { self.write(&[1]u8{char}); } - fn print(self: *Self, comptime fmt: []const u8, args: var) void { + fn print(self: *Self, comptime fmt: []const u8, args: anytype) void { self.file.writer().print(fmt, args) catch unreachable; } diff --git a/src/runtime.zig b/src/runtime.zig index 10bb34c..620d4e3 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -420,11 +420,11 @@ pub const TypeInfo = union(enum) { } } - pub fn copy(comptime T: type, allocator: *Allocator, comptime src: var) T { + pub fn copy(comptime T: type, allocator: *Allocator, comptime src: anytype) T { return TypeInfo.copy2(T, allocator, src, 5); } - pub fn copy2(comptime T: type, allocator: *Allocator, comptime src: var, comptime depth: u32) T { + pub fn copy2(comptime T: type, allocator: *Allocator, comptime src: anytype, comptime depth: u32) T { comptime const info = @typeInfo(T); if (info == .Void) { From 580a3f65ff458a57ae557f3b0e7b70521b2dd01b Mon Sep 17 00:00:00 2001 From: "Pedro M. Silva" Date: Mon, 31 Aug 2020 23:42:59 +0100 Subject: [PATCH 06/13] Finalize circular dependencies handling --- src/deps_graph.zig | 64 ++++-- src/example/exports.zig | 2 +- src/generators/ordered.zig | 59 +++-- src/generators/python.zig | 21 +- src/runtime.zig | 442 +++++++++++++++++++++++++++---------- 5 files changed, 415 insertions(+), 173 deletions(-) diff --git a/src/deps_graph.zig b/src/deps_graph.zig index a3c4584..e1ea83d 100644 --- a/src/deps_graph.zig +++ b/src/deps_graph.zig @@ -16,7 +16,8 @@ pub fn DepsGraph(comptime T: type) type { dependants_of: StringHashMap(ArrayList(*Symbol)), // ?*Symbol owned by self.symbols current_symbol: ?*Symbol, - // TODO + // Queue containing symbols ready to be emitted + // Can be updated each time after calling endSymbol() emitted: TailQueue(EmittedSymbol), const Self = @This(); @@ -38,7 +39,7 @@ pub fn DepsGraph(comptime T: type) type { entry.value.deinit(self.allocator); // And free the pointer - self.allocator.destroy(entry); + self.allocator.destroy(entry.value); } self.symbols.deinit(); @@ -142,15 +143,6 @@ pub fn DepsGraph(comptime T: type) type { try current_symbol.addDependency(.{ .Linear = dependency_name }); } } - - // TODO - // 1. Implement Symbol.addDependency() ✔ - // 2. Implement Symbol.hasDependencies() ✔ - // 3. Implement Symbol.hasDependenciesOfType(tag) ✔ - // 4. Only add dependencies when they are not emitted yet, or ✔ - // the dependency itself is blocked - // 5. Add to the action queue in endSymbol() ✔ - // 6. Implement isBlocking(name) ✔ } pub const EndSymbolError = error{OutOfMemory}; @@ -169,6 +161,9 @@ pub fn DepsGraph(comptime T: type) type { unblock_queue.append(node); } + // All items in unblock_queue have already been unblocked, and so + // should be emitted. Also, any dependants of them should be checked + // if they themselves can be unblocked as well while (unblock_queue.popFirst()) |symbol_node| { self.emitted.append(symbol_node); @@ -177,10 +172,12 @@ pub fn DepsGraph(comptime T: type) type { if (self.dependants_of.get(symbol.name)) |kv| { for (kv.value.items) |dependant| { if (dependant.removeDependency(symbol.name)) |dep| { - const unblock_dep = (dep == .Linear and !dependant.hasDependenciesOfType(.Linear)) or (dep == .Circular and !dependant.hasDependencies()); + const unblock_dep = (!dependant.emitted and !dependant.hasDependenciesOfType(.Linear)) or !dependant.hasDependencies(); if (!unblock_dep) continue; + dependant.emitted = true; + const node = try unblock_queue.createNode(.{ .symbol = dependant, .partial = dependant.hasDependencies(), @@ -190,8 +187,6 @@ pub fn DepsGraph(comptime T: type) type { } } } - - // if (!symbol.hasDependenciesOfType(.Linear) or !symbol.hasDependencies()) {} } self.current_symbol = null; @@ -244,7 +239,7 @@ pub fn DepsGraph(comptime T: type) type { name: []const u8, // Slices not owned dependencies: ArrayList(Dependency), - + emitted: bool = false, payload: T, pub fn init(allocator: *Allocator, name: []const u8, payload: T) Symbol { @@ -342,6 +337,12 @@ const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; const expectEqualStrings = std.testing.expectEqualStrings; +fn expectSymbol(emitted: ?DepsGraph(void).EmittedSymbol, expected_name: []const u8, expected_partial: bool) void { + expect(emitted != null); + expectEqualStrings(expected_name, emitted.?.symbol.name); + expectEqual(expected_partial, emitted.?.partial); +} + test "Simple dependency graph with circular dependencies" { const allocator = std.testing.allocator; @@ -428,3 +429,36 @@ test "Blocked symbols iterator" { deps.deinit(); } + +test "Three tier circular dependencies" { + const allocator = std.testing.allocator; + + var deps = DepsGraph(void).init(allocator); + + try deps.beginSymbol("LookMaAnEnum", {}); + try deps.endSymbol(); + + try deps.beginSymbol("WackType", {}); + try deps.addDependency("LameType"); + try deps.endSymbol(); + + try deps.beginSymbol("LameType", {}); + try deps.addDependency("WackType"); + try deps.addDependency("WhatsAUnion"); + try deps.endSymbol(); + + try deps.beginSymbol("WhatsAUnion", {}); + try deps.addDependency("LameType"); + try deps.endSymbol(); + + expectSymbol(deps.readEmitted(), "LookMaAnEnum", false); + expectSymbol(deps.readEmitted(), "WhatsAUnion", true); + expectSymbol(deps.readEmitted(), "LameType", true); + expectSymbol(deps.readEmitted(), "WackType", false); + expectSymbol(deps.readEmitted(), "WhatsAUnion", false); + expectSymbol(deps.readEmitted(), "LameType", false); + + expect(deps.readEmitted() == null); + + deps.deinit(); +} diff --git a/src/example/exports.zig b/src/example/exports.zig index 0fa0d58..4738210 100644 --- a/src/example/exports.zig +++ b/src/example/exports.zig @@ -1,4 +1,3 @@ -const rt = @import("../runtime.zig"); const header_gen = @import("header_gen"); export fn thing(one: usize, two: *LameType, three: [*]u16) bool { @@ -15,6 +14,7 @@ const WackType = packed struct { const LameType = extern struct { blah: WackType, + bleh: *WhatsAUnion, }; const WhatsAUnion = extern union { a: *LameType, diff --git a/src/generators/ordered.zig b/src/generators/ordered.zig index 379b434..688497d 100644 --- a/src/generators/ordered.zig +++ b/src/generators/ordered.zig @@ -14,12 +14,14 @@ const SymbolDeclaration = union(enum) { Struct: rt.TypeInfo.Struct, Union: rt.TypeInfo.Union, Enum: rt.TypeInfo.Enum, + Fn: rt.TypeInfo.Fn, pub fn deinit(self: SymbolDeclaration, allocator: *Allocator) void { switch (self) { .Struct => |s| s.deinit(allocator), .Union => |u| u.deinit(allocator), .Enum => |e| e.deinit(allocator), + .Fn => |f| f.deinit(allocator), } } }; @@ -29,6 +31,8 @@ fn isSymbolDependency(comptime symbol_type: type) bool { return switch (info) { .Struct, .Union, .Enum => true, + .Pointer => |p| isSymbolDependency(p.child), + .Array => |a| isSymbolDependency(a.child), else => false, }; } @@ -70,22 +74,16 @@ pub fn Ordered_Generator(comptime Generator: type) type { pub fn deinit(self: *Self) void { self.flush(); + self.symbols.deinit(); + self.inner_gen.deinit(); - // TODO Enable deinit hashmap. Right now it segfaults, reason unknown - // var iter = self.symbols.symbols.iterator(); - // while (iter.next()) |kv| { - // kv.value.payload.deinit(self.allocator); - // } - - // self.symbols.deinit(); - self.emitted_phase.deinit(); } fn getNextPhaseFor(self: *Self, symbol_name: []const u8, partial: bool) !?SymbolPhase { var result = try self.emitted_phase.getOrPut(symbol_name); - + if (!result.found_existing) { result.kv.value = if (partial) .Signature else .Full; @@ -105,31 +103,44 @@ pub fn Ordered_Generator(comptime Generator: type) type { fn flush(self: *Self) void { while (self.symbols.readEmitted()) |emitted| { - var phase = self.getNextPhaseFor(emitted.symbol.name, emitted.partial) catch unreachable orelse continue ; - - // Handle emitted.partial + const partial = if (emitted.symbol.payload == .Fn) false else emitted.partial; + + var phase = self.getNextPhaseFor(emitted.symbol.name, emitted.partial) catch unreachable orelse continue; + switch (emitted.symbol.payload) { .Struct => |meta| self.inner_gen.gen_struct(emitted.symbol.name, meta, phase), .Union => |meta| self.inner_gen.gen_union(emitted.symbol.name, meta, phase), .Enum => |meta| self.inner_gen.gen_enum(emitted.symbol.name, meta, phase), + .Fn => |meta| self.inner_gen.gen_func(emitted.symbol.name, meta), } } } pub fn gen_func(self: *Self, comptime name: []const u8, comptime meta: FnMeta) void { - self.flush(); - - // var rt_func = rt.TypeInfo.copy(rt.TypeInfo.Declaration.Data.FnDecl, self.allocator, func); - // defer rt_func.deinit(self.allocator); + comptime const decl: SymbolDeclaration = SymbolDeclaration{ + .Fn = rt.TypeInfo.Fn.init(meta, rt.dd), + }; - var rt_meta = rt.TypeInfo.copy2(rt.TypeInfo.Fn, self.allocator, meta, 2); - defer rt_meta.deinit(self.allocator); + self.symbols.beginSymbol(name, decl) catch |err| @panic(@errorName(err)); + inline for (meta.args) |f| { + if (f.arg_type != null and comptime isSymbolDependency(f.arg_type.?)) { + self.symbols.addDependency(getTypeName(f.arg_type.?)) catch |err| @panic(@errorName(err)); + } + } + if (meta.return_type) |t| { + if (comptime isSymbolDependency(t)) { + self.symbols.addDependency(getTypeName(t)) catch |err| @panic(@errorName(err)); + } + } + self.symbols.endSymbol() catch |err| @panic(@errorName(err)); - self.inner_gen.gen_func(name, rt_meta); + self.flush(); } pub fn gen_struct(self: *Self, comptime name: []const u8, comptime meta: StructMeta) void { - var decl: SymbolDeclaration = SymbolDeclaration{ .Struct = rt.TypeInfo.copy(rt.TypeInfo.Struct, self.allocator, meta) }; + comptime const decl: SymbolDeclaration = SymbolDeclaration{ + .Struct = rt.TypeInfo.Struct.init(meta, name, rt.dd), + }; self.symbols.beginSymbol(name, decl) catch |err| @panic(@errorName(err)); inline for (meta.fields) |f| { @@ -143,7 +154,9 @@ pub fn Ordered_Generator(comptime Generator: type) type { } pub fn gen_enum(self: *Self, comptime name: []const u8, comptime meta: EnumMeta) void { - var decl: SymbolDeclaration = SymbolDeclaration{ .Enum = rt.TypeInfo.copy(rt.TypeInfo.Enum, self.allocator, meta) }; + comptime const decl: SymbolDeclaration = SymbolDeclaration{ + .Enum = rt.TypeInfo.Enum.init(meta, name, rt.dd), + }; self.symbols.beginSymbol(name, decl) catch |err| @panic(@errorName(err)); // Enums have no type dependencies I think, yay @@ -153,7 +166,9 @@ pub fn Ordered_Generator(comptime Generator: type) type { } pub fn gen_union(self: *Self, comptime name: []const u8, comptime meta: UnionMeta) void { - var decl: SymbolDeclaration = SymbolDeclaration{ .Union = rt.TypeInfo.copy(rt.TypeInfo.Union, self.allocator, meta) }; + comptime const decl: SymbolDeclaration = SymbolDeclaration{ + .Union = rt.TypeInfo.Union.init(meta, name, rt.dd), + }; self.symbols.beginSymbol(name, decl) catch |err| @panic(@errorName(err)); inline for (meta.fields) |f| { diff --git a/src/generators/python.zig b/src/generators/python.zig index 449a0b6..3b612e5 100644 --- a/src/generators/python.zig +++ b/src/generators/python.zig @@ -67,7 +67,7 @@ pub const Python_Generator = struct { self.write("\n\n"); } - pub fn _gen_fields(self: *Self, name: []const u8, fields: anytype, phase: SymbolPhase) void { + pub fn _gen_fields(self: *Self, name: []const u8, fields: var, phase: SymbolPhase) void { comptime const prefix = "\t "; if (phase == .Body) { @@ -83,17 +83,7 @@ pub const Python_Generator = struct { self.print("(\"{}\", ", .{field.name}); - const info = field.field_type.*; - - if (info == .Array) { - self.writeType(info.Array.child.*); - } else { - self.writeType(info); - } - - if (info == .Array) { - self.print(" * {}", .{info.Array.len}); - } + self.writeType(field.field_type.*); self.write(")"); @@ -187,7 +177,10 @@ pub const Python_Generator = struct { self.write(")"); }, .Optional => self.writeType(meta.Optional.child.*), - .Array => {}, // TODO @compileError("Handle goofy looking C Arrays in the calling function"), + .Array => |a| { + self.writeType(a.child.*); + self.print(" * {}", .{a.len}); + }, else => self.write(@tagName(meta)), // TODO!!!!! } } @@ -226,7 +219,7 @@ pub const Python_Generator = struct { self.write(&[1]u8{char}); } - fn print(self: *Self, comptime fmt: []const u8, args: anytype) void { + fn print(self: *Self, comptime fmt: []const u8, args: var) void { self.file.writer().print(fmt, args) catch unreachable; } diff --git a/src/runtime.zig b/src/runtime.zig index 620d4e3..7a3ee2a 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -1,6 +1,8 @@ const std = @import("std"); const Allocator = std.mem.Allocator; +pub const dd: i32 = 2; + pub const TypeId = @TagType(TypeInfo); pub const TypeInfo = union(enum) { @@ -35,12 +37,25 @@ pub const TypeInfo = union(enum) { pub const Int = struct { is_signed: bool, bits: i32, + + pub fn init(comptime m: std.builtin.TypeInfo.Int, comptime depth: i32) Int { + return comptime .{ + .is_signed = m.is_signed, + .bits = m.bits, + }; + } }; /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Float = struct { bits: i32, + + pub fn init(comptime m: std.builtin.TypeInfo.Float, comptime depth: i32) Float { + return comptime .{ + .bits = m.bits, + }; + } }; /// This data structure is used by the Zig language code generation and @@ -50,7 +65,7 @@ pub const TypeInfo = union(enum) { is_const: bool, is_volatile: bool, alignment: i32, - child: *TypeInfo, + child: *const TypeInfo, is_allowzero: bool, /// This field is an optional type. /// The type of the sentinel is the element type of the pointer, which is @@ -66,6 +81,17 @@ pub const TypeInfo = union(enum) { C, }; + pub fn init(comptime m: std.builtin.TypeInfo.Pointer, comptime depth: i32) Pointer { + return comptime .{ + .size = @intToEnum(TypeInfo.Pointer.Size, @enumToInt(m.size)), + .is_const = m.is_const, + .is_volatile = m.is_volatile, + .alignment = m.alignment, + .child = &TypeInfo.init(m.child, depth), + .is_allowzero = m.is_allowzero, + }; + } + pub fn deinit(self: *const Pointer, allocator: *Allocator) void { self.child.deinit(allocator); @@ -77,12 +103,19 @@ pub const TypeInfo = union(enum) { /// therefore must be kept in sync with the compiler implementation. pub const Array = struct { len: i32, - child: *TypeInfo, + child: *const TypeInfo, /// This field is an optional type. /// The type of the sentinel is the element type of the array, which is /// the value of the `child` field in this struct. However there is no way /// to refer to that type here, so we use `var`. // sentinel: var, + pub fn init(comptime m: std.builtin.TypeInfo.Array, comptime depth: i32) Array { + return comptime .{ + .len = m.len, + .child = &TypeInfo.init(m.child, depth), + }; + } + pub fn deinit(self: *const Array, allocator: *Allocator) void { self.child.deinit(allocator); @@ -102,9 +135,16 @@ pub const TypeInfo = union(enum) { /// therefore must be kept in sync with the compiler implementation. pub const StructField = struct { name: []const u8, - field_type: *TypeInfo, + field_type: *const TypeInfo, // default_value: var, + pub fn init(comptime f: std.builtin.TypeInfo.StructField, comptime depth: i32) StructField { + return comptime .{ + .name = f.name, + .field_type = &TypeInfo.init(f.field_type, depth), + }; + } + pub fn deinit(self: *const StructField, allocator: *Allocator) void { allocator.free(self.name); @@ -122,6 +162,31 @@ pub const TypeInfo = union(enum) { fields: []const StructField, decls: []const Declaration, + pub fn init(comptime m: std.builtin.TypeInfo.Struct, comptime name: []const u8, comptime depth: i32) Struct { + return comptime .{ + .name = name, + .layout = @intToEnum(TypeInfo.ContainerLayout, @enumToInt(m.layout)), + .fields = fields: { + comptime var arr: [m.fields.len]StructField = undefined; + + inline for (m.fields) |f, i| { + arr[i] = StructField.init(f, depth - 1); + } + + break :fields &arr; + }, + .decls = decls: { + comptime var arr: [m.decls.len]Declaration = undefined; + + inline for (m.decls) |f, i| { + arr[i] = Declaration.init(f, depth - 1); + } + + break :decls &arr; + }, + }; + } + pub fn deinit(self: *const Struct, allocator: *Allocator) void { for (self.fields) |f| f.deinit(allocator); for (self.decls) |f| f.deinit(allocator); @@ -134,7 +199,13 @@ pub const TypeInfo = union(enum) { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Optional = struct { - child: *TypeInfo, + child: *const TypeInfo, + + pub fn init(comptime m: std.builtin.TypeInfo.Optional, comptime depth: i32) Optional { + return comptime .{ + .child = &TypeInfo.init(m.child, depth), + }; + } pub fn deinit(self: *const Optional, allocator: *Allocator) void { self.child.deinit(allocator); @@ -146,8 +217,15 @@ pub const TypeInfo = union(enum) { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const ErrorUnion = struct { - error_set: *TypeInfo, - payload: *TypeInfo, + error_set: *const TypeInfo, + payload: *const TypeInfo, + + pub fn init(comptime m: std.builtin.TypeInfo.ErrorUnion, comptime depth: i32) ErrorUnion { + return comptime .{ + .error_set = &TypeInfo.init(m.error_set, depth), + .payload = &TypeInfo.init(m.payload, depth), + }; + } pub fn deinit(self: *const ErrorUnion, allocator: *Allocator) void { self.error_set.deinit(allocator); @@ -178,6 +256,13 @@ pub const TypeInfo = union(enum) { name: []const u8, value: i32, + pub fn init(comptime f: std.builtin.TypeInfo.EnumField, comptime depth: i32) EnumField { + return comptime .{ + .name = f.name, + .value = f.value, + }; + } + pub fn deinit(self: *const EnumField, allocator: *Allocator) void { allocator.free(self.name); } @@ -188,11 +273,38 @@ pub const TypeInfo = union(enum) { pub const Enum = struct { name: ?[]const u8, layout: ContainerLayout, - tag_type: *TypeInfo, + tag_type: *const TypeInfo, fields: []const EnumField, decls: []const Declaration, is_exhaustive: bool, + pub fn init(comptime m: std.builtin.TypeInfo.Enum, comptime name: []const u8, comptime depth: i32) Enum { + return comptime .{ + .name = name, + .layout = @intToEnum(TypeInfo.ContainerLayout, @enumToInt(m.layout)), + .tag_type = &TypeInfo.init(m.tag_type, depth), + .fields = fields: { + comptime var arr: [m.fields.len]EnumField = undefined; + + inline for (m.fields) |f, i| { + arr[i] = EnumField.init(f, depth - 1); + } + + break :fields &arr; + }, + .decls = decls: { + comptime var arr: [m.decls.len]Declaration = undefined; + + inline for (m.decls) |f, i| { + arr[i] = Declaration.init(f, depth - 1); + } + + break :decls &arr; + }, + .is_exhaustive = m.is_exhaustive, + }; + } + pub fn deinit(self: *const Enum, allocator: *Allocator) void { for (self.fields) |f| f.deinit(allocator); for (self.decls) |f| f.deinit(allocator); @@ -210,7 +322,21 @@ pub const TypeInfo = union(enum) { pub const UnionField = struct { name: []const u8, enum_field: ?EnumField, - field_type: *TypeInfo, + field_type: *const TypeInfo, + + pub fn init(comptime f: std.builtin.TypeInfo.UnionField, comptime depth: i32) UnionField { + return comptime .{ + .name = f.name, + .enum_field = if (f.enum_field) |ef| + .{ + .name = ef.name, + .value = ef.value, + } + else + null, + .field_type = &TypeInfo.init(f.field_type, depth), + }; + } pub fn deinit(self: *const UnionField, allocator: *Allocator) void { allocator.free(self.name); @@ -230,10 +356,36 @@ pub const TypeInfo = union(enum) { pub const Union = struct { name: ?[]const u8, layout: ContainerLayout, - tag_type: ?*TypeInfo, + tag_type: ?*const TypeInfo, fields: []const UnionField, decls: []const Declaration, + pub fn init(comptime m: std.builtin.TypeInfo.Union, comptime name: []const u8, comptime depth: i32) Union { + return comptime .{ + .name = name, + .layout = @intToEnum(TypeInfo.ContainerLayout, @enumToInt(m.layout)), + .tag_type = if (m.tag_type) |t| &TypeInfo.init(t, depth) else null, + .fields = fields: { + comptime var arr: [m.fields.len]UnionField = undefined; + + inline for (m.fields) |f, i| { + arr[i] = UnionField.init(f, depth - 1); + } + + break :fields &arr; + }, + .decls = decls: { + comptime var arr: [m.decls.len]Declaration = undefined; + + inline for (m.decls) |f, i| { + arr[i] = Declaration.init(f, depth - 1); + } + + break :decls &arr; + }, + }; + } + pub fn deinit(self: *const Union, allocator: *Allocator) void { for (self.fields) |f| f.deinit(allocator); for (self.decls) |f| f.deinit(allocator); @@ -254,7 +406,15 @@ pub const TypeInfo = union(enum) { pub const FnArg = struct { is_generic: bool, is_noalias: bool, - arg_type: ?*TypeInfo, + arg_type: ?*const TypeInfo, + + pub fn init(comptime f: std.builtin.TypeInfo.FnArg, comptime depth: i32) FnArg { + return comptime .{ + .is_generic = f.is_generic, + .is_noalias = f.is_noalias, + .arg_type = if (f.arg_type) |t| &TypeInfo.init(t, depth) else null, + }; + } pub fn deinit(self: *const FnArg, allocator: *Allocator) void { if (self.arg_type) |t| { @@ -271,9 +431,27 @@ pub const TypeInfo = union(enum) { calling_convention: CallingConvention, is_generic: bool, is_var_args: bool, - return_type: ?*TypeInfo, + return_type: ?*const TypeInfo, args: []const FnArg, + pub fn init(comptime m: std.builtin.TypeInfo.Fn, comptime depth: i32) Fn { + return comptime .{ + .calling_convention = @intToEnum(CallingConvention, @enumToInt(m.calling_convention)), + .is_generic = m.is_generic, + .is_var_args = m.is_var_args, + .return_type = if (m.return_type) |t| &TypeInfo.init(t, depth) else null, + .args = args: { + comptime var arr: [m.args.len]FnArg = undefined; + + inline for (m.args) |f, i| { + arr[i] = FnArg.init(f, depth); + } + + break :args &arr; + }, + }; + } + pub fn deinit(self: *const Fn, allocator: *Allocator) void { if (self.return_type) |r| { r.deinit(allocator); @@ -296,7 +474,13 @@ pub const TypeInfo = union(enum) { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const AnyFrame = struct { - child: ?*TypeInfo, + child: ?*const TypeInfo, + + pub fn init(comptime m: std.builtin.TypeInfo.AnyFrame, comptime depth: i32) AnyFrame { + return comptime .{ + .child = if (m.child) |t| &TypeInfo.init(t, depth) else null, + }; + } pub fn deinit(self: *const AnyFrame, allocator: *Allocator) void { if (self.child) |child| { @@ -311,7 +495,14 @@ pub const TypeInfo = union(enum) { /// therefore must be kept in sync with the compiler implementation. pub const Vector = struct { len: i32, - child: *TypeInfo, + child: *const TypeInfo, + + pub fn init(comptime m: std.builtin.TypeInfo.Vector, comptime depth: i32) Vector { + return comptime .{ + .len = m.len, + .child = &TypeInfo.init(m.child, depth), + }; + } pub fn deinit(self: *const Vector, allocator: *Allocator) void { self.child.deinit(allocator); @@ -327,6 +518,14 @@ pub const TypeInfo = union(enum) { is_pub: bool, data: Data, + pub fn init(comptime f: std.builtin.TypeInfo.Declaration, comptime depth: i32) Declaration { + return comptime .{ + .name = f.name, + .is_pub = f.is_pub, + .data = Data.init(f.data, depth), + }; + } + pub fn deinit(self: *const Declaration, allocator: *Allocator) void { self.data.deinit(allocator); @@ -336,20 +535,30 @@ pub const TypeInfo = union(enum) { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Data = union(enum) { - Type: *TypeInfo, - Var: *TypeInfo, + Type: *const TypeInfo, + Var: *const TypeInfo, Fn: FnDecl, + pub fn init(comptime d: std.builtin.TypeInfo.Declaration.Data, comptime depth: i32) Data { + return comptime switch (d) { + .Type => |t| .{ .Type = &TypeInfo.init(t, depth) }, + .Var => |t| .{ + .Var = &TypeInfo.init(t, depth), + }, + .Fn => |t| .{ .Fn = FnDecl.init(t, depth) }, + }; + } + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const FnDecl = struct { - fn_type: *TypeInfo, + fn_type: *const TypeInfo, inline_type: Inline, is_var_args: bool, is_extern: bool, is_export: bool, lib_name: ?[]const u8, - return_type: *TypeInfo, + return_type: *const TypeInfo, arg_names: []const []const u8, /// This data structure is used by the Zig language code generation and @@ -360,6 +569,19 @@ pub const TypeInfo = union(enum) { Never, }; + pub fn init(comptime t: std.builtin.TypeInfo.Declaration.Data.FnDecl, comptime depth: i32) FnDecl { + return comptime .{ + .fn_type = &TypeInfo.init(t.fn_type, depth), + .inline_type = @intToEnum(TypeInfo.Declaration.Data.FnDecl.Inline, @enumToInt(t.inline_type)), + .is_var_args = t.is_var_args, + .is_extern = t.is_extern, + .is_export = t.is_export, + .lib_name = t.lib_name, + .return_type = &TypeInfo.init(t.return_type, depth), + .arg_names = t.arg_names, + }; + } + pub fn deinit(self: *const FnDecl, allocator: *Allocator) void { self.fn_type.deinit(allocator); self.return_type.deinit(allocator); @@ -389,12 +611,52 @@ pub const TypeInfo = union(enum) { }; }; - pub fn init(allocator: *Allocator, comptime builtin: std.builtin.TypeInfo) TypeInfo { - return TypeInfo.copy(TypeInfo, allocator, builtin); - } + pub fn init(comptime builtin: type, comptime depth: i32) TypeInfo { + if (depth <= 0) return .{ .Opaque = {} }; + + comptime const info = @typeInfo(builtin); + + return comptime switch (info) { + .Type => .{ .Type = {} }, + .Void => .{ .Void = {} }, + .Bool => .{ .Bool = {} }, + .NoReturn => .{ .NoReturn = {} }, + .Int => |m| .{ .Int = Int.init(m, depth) }, + .Float => |m| .{ .Float = Float.init(m, depth) }, + .Pointer => |m| .{ .Pointer = Pointer.init(m, depth) }, + .Array => |m| .{ .Array = Array.init(m, depth) }, + .Struct => |m| .{ .Struct = Struct.init(m, @typeName(builtin), depth) }, + .ComptimeFloat => .{ .ComptimeFloat = {} }, + .ComptimeInt => .{ .ComptimeInt = {} }, + .Undefined => .{ .Undefined = {} }, + .Null => .{ .Null = {} }, + .Optional => |m| .{ .Optional = Optional.init(m, depth) }, + .ErrorUnion => |m| .{ .ErrorUnion = ErrorUnion.init(m, depth) }, // TODO + .ErrorSet => |m| .{ + .ErrorSet = errorset: { + if (m == null) return null; + + comptime var arr: [m.?.len]Error = undefined; + + inline for (m.?) |f, i| { + arr[i] = .{ + .name = f.name, + }; + } - pub fn init2(allocator: *Allocator, comptime builtin: std.builtin.TypeInfo, comptime depth: u32) TypeInfo { - return TypeInfo.copy2(TypeInfo, allocator, builtin, depth); + break :errorset &arr; + }, + }, + .Enum => |m| .{ .Enum = Enum.init(m, @typeName(builtin), depth) }, + .Union => |m| .{ .Union = Union.init(m, @typeName(builtin), depth) }, + .Fn => |m| .{ .Fn = Fn.init(m, depth) }, + .BoundFn => |m| .{ .BoundedFn = Fn.init(m, depth) }, + .Opaque => .{ .Opaque = {} }, + .Frame => .{ .Frame = {} }, // TODO + .AnyFrame => |m| .{ .AnyFrame = AnyFrame.init(m, depth) }, + .Vector => |m| .{ .Vector = Vector.init(m, depth) }, + .EnumLiteral => .{ .EnumLiteral = {} }, + }; } pub fn deinit(self: *TypeInfo, allocator: *Allocator) void { @@ -419,73 +681,6 @@ pub const TypeInfo = union(enum) { else => {}, } } - - pub fn copy(comptime T: type, allocator: *Allocator, comptime src: anytype) T { - return TypeInfo.copy2(T, allocator, src, 5); - } - - pub fn copy2(comptime T: type, allocator: *Allocator, comptime src: anytype, comptime depth: u32) T { - comptime const info = @typeInfo(T); - - if (info == .Void) { - return; - } else if (info == .Pointer and info.Pointer.size == .One and info.Pointer.child == TypeInfo) { - var ptr = allocator.create(TypeInfo) catch unreachable; - - if (depth > 0) { - ptr.* = TypeInfo.init2(allocator, @typeInfo(src), depth - 1); - - if (ptr.* == .Struct) ptr.*.Struct.name = @typeName(src) - else if (ptr.* == .Union) ptr.*.Union.name = @typeName(src) - else if (ptr.* == .Enum) ptr.*.Enum.name = @typeName(src); - } else { - // TODO Create special variant for max-depth - ptr.* = TypeInfo{ .Void = {} }; - } - - return ptr; - } else if (info == .Enum) { - return @intToEnum(T, @enumToInt(src)); - } else if (info == .Pointer and info.Pointer.size == .Slice) { - var dst_slice = allocator.alloc(info.Pointer.child, src.len) catch unreachable; - - inline for (src) |src_val, i| { - dst_slice[i] = TypeInfo.copy2(info.Pointer.child, allocator, src_val, depth); - } - - return dst_slice; - } else if (info == .Struct) { - var obj: T = undefined; - - inline for (info.Struct.fields) |struct_field| { - if (comptime @hasField(@TypeOf(src), struct_field.name)) { - @field(obj, struct_field.name) = TypeInfo.copy2(struct_field.field_type, allocator, @field(src, struct_field.name), depth); - } - } - - return obj; - } else if (info == .Union) { - inline for (info.Union.fields) |union_field| { - comptime var tag_type = @field(@TagType(@TypeOf(src)), union_field.enum_field.?.name); - - if (src == tag_type) { - var obj = TypeInfo.copy2(union_field.field_type, allocator, @field(src, union_field.name), depth); - - return @unionInit(T, union_field.name, obj); - } - } - - @panic("Type not runtimable"); - } else if (info == .Optional) { - if (src) |src_val| { - return TypeInfo.copy2(info.Optional.child, allocator, src_val, depth); - } else { - return null; - } - } else { - return @as(T, src); - } - } }; pub const CallingConvention = enum { @@ -514,35 +709,32 @@ const talloc = std.testing.allocator; // TODO .Type test "Runtime TypeInfo.Void" { - var info_void = TypeInfo.init(talloc, @typeInfo(void)); + var info_void = TypeInfo.init(void, dd); expect(info_void == .Void); - info_void.deinit(talloc); } + test "Runtime TypeInfo.Bool" { - var info_bool = TypeInfo.init(talloc, @typeInfo(bool)); + var info_bool = TypeInfo.init(bool, dd); expect(info_bool == .Bool); - info_bool.deinit(talloc); } // TODO .NoReturn test "Runtime TypeInfo.Int" { - var info_i32 = TypeInfo.init(talloc, @typeInfo(i32)); + var info_i32 = TypeInfo.init(i32, dd); expect(info_i32 == .Int); expectEqual(@as(i32, 32), info_i32.Int.bits); expectEqual(true, info_i32.Int.is_signed); - info_i32.deinit(talloc); } test "Runtime TypeInfo.Float" { - var info_f64 = TypeInfo.init(talloc, @typeInfo(f64)); + var info_f64 = TypeInfo.init(f64, dd); expect(info_f64 == .Float); expectEqual(@as(i32, 64), info_f64.Float.bits); - info_f64.deinit(talloc); } test "Runtime TypeInfo.Pointer" { - var info_pointer_f64 = TypeInfo.init(talloc, @typeInfo(*f64)); + var info_pointer_f64 = TypeInfo.init(*f64, dd); expect(info_pointer_f64 == .Pointer); expectEqual(TypeInfo.Pointer.Size.One, info_pointer_f64.Pointer.size); expectEqual(false, info_pointer_f64.Pointer.is_const); @@ -550,9 +742,8 @@ test "Runtime TypeInfo.Pointer" { expectEqual(@as(i32, 8), info_pointer_f64.Pointer.alignment); expect(info_pointer_f64.Pointer.child.* == .Float); expectEqual(false, info_pointer_f64.Pointer.is_allowzero); - info_pointer_f64.deinit(talloc); - var info_pointer_many = TypeInfo.init(talloc, @typeInfo([*]f64)); + var info_pointer_many = TypeInfo.init([*]f64, dd); expect(info_pointer_many == .Pointer); expectEqual(TypeInfo.Pointer.Size.Many, info_pointer_many.Pointer.size); expectEqual(false, info_pointer_many.Pointer.is_const); @@ -560,15 +751,13 @@ test "Runtime TypeInfo.Pointer" { expectEqual(@as(i32, 8), info_pointer_many.Pointer.alignment); expect(info_pointer_many.Pointer.child.* == .Float); expectEqual(false, info_pointer_many.Pointer.is_allowzero); - info_pointer_many.deinit(talloc); } test "Runtime TypeInfo.Array" { - var info_array = TypeInfo.init(talloc, @typeInfo([2]i32)); + var info_array = TypeInfo.init([2]i32, dd); expect(info_array == .Array); expectEqual(@as(i32, 2), info_array.Array.len); expect(info_array.Array.child.* == .Int); - info_array.deinit(talloc); } test "Runtime TypeInfo.Struct" { @@ -578,48 +767,43 @@ test "Runtime TypeInfo.Struct" { pub fn bar() void {} }; - var info_struct = TypeInfo.init(talloc, @typeInfo(FooStruct)); + var info_struct = TypeInfo.init(FooStruct, dd); expect(info_struct == .Struct); expect(info_struct.Struct.layout == .Auto); expectEqual(@as(usize, 1), info_struct.Struct.fields.len); expectEqualStrings("int", info_struct.Struct.fields[0].name); expect(info_struct.Struct.fields[0].field_type.* == .Int); - info_struct.deinit(talloc); } test "Runtime TypeInfo.ComptimeFloat" { - var info_comptime_float = TypeInfo.init(talloc, @typeInfo(comptime_float)); + var info_comptime_float = TypeInfo.init(comptime_float, dd); expect(info_comptime_float == .ComptimeFloat); - info_comptime_float.deinit(talloc); } test "Runtime TypeInfo.ComptimeInt" { - var info_comptime_int = TypeInfo.init(talloc, @typeInfo(comptime_int)); + var info_comptime_int = TypeInfo.init(comptime_int, dd); expect(info_comptime_int == .ComptimeInt); - info_comptime_int.deinit(talloc); } -// TODO .Undefined -// TODO .Null +// // TODO .Undefined +// // TODO .Null test "Runtime TypeInfo.Optional" { - var info_optional = TypeInfo.init(talloc, @typeInfo(?i32)); + var info_optional = TypeInfo.init(?i32, dd); expect(info_optional == .Optional); expect(info_optional.Optional.child.* == .Int); - info_optional.deinit(talloc); } -// TODO .ErrorUnion -// TODO .ErrorSet +// // TODO .ErrorUnion +// // TODO .ErrorSet test "Runtime TypeInfo.Enum" { const FooEnum = enum { Foo, Bar }; - var info_enum = TypeInfo.init(talloc, @typeInfo(FooEnum)); + var info_enum = TypeInfo.init(FooEnum, dd); expect(info_enum == .Enum); - info_enum.deinit(talloc); } test "Runtime TypeInfo.Union" { @@ -627,16 +811,32 @@ test "Runtime TypeInfo.Union" { Foo: void, Bar: i32 }; - var info_union = TypeInfo.init(talloc, @typeInfo(FooUnion)); + var info_union = TypeInfo.init(FooUnion, dd); expect(info_union == .Union); - info_union.deinit(talloc); } test "Runtime TypeInfo.Fn" { // .Fn - var info_fn = TypeInfo.init(talloc, @typeInfo(fn () void)); + var info_fn = TypeInfo.init(fn () void, dd); expect(info_fn == .Fn); - info_fn.deinit(talloc); +} + +test "Runtime TypeInfo.Struct declarations" { + // .Fn + var info_fn = TypeInfo.init(struct { + const WackType = packed struct { + mr_field: *LameType, ola: u8 + }; + + const LameType = struct { + blah: **WackType, + }; + + pub fn thing(one: usize, two: *LameType, three: [*]u16) bool { + return one == 1; + } + }, dd); + expect(info_fn == .Struct); } // TODO .BoundFn From 90562e5a42289a6f1d2b45839d927d820e9a03e8 Mon Sep 17 00:00:00 2001 From: "Pedro M. Silva" Date: Tue, 1 Sep 2020 21:33:51 +0100 Subject: [PATCH 07/13] Fix infinite recursion and remove depth argument --- src/generators/ordered.zig | 8 +- src/runtime.zig | 179 +++++++++++++++++++++---------------- 2 files changed, 104 insertions(+), 83 deletions(-) diff --git a/src/generators/ordered.zig b/src/generators/ordered.zig index 688497d..8793dd6 100644 --- a/src/generators/ordered.zig +++ b/src/generators/ordered.zig @@ -118,7 +118,7 @@ pub fn Ordered_Generator(comptime Generator: type) type { pub fn gen_func(self: *Self, comptime name: []const u8, comptime meta: FnMeta) void { comptime const decl: SymbolDeclaration = SymbolDeclaration{ - .Fn = rt.TypeInfo.Fn.init(meta, rt.dd), + .Fn = rt.TypeInfo.Fn.init(meta), }; self.symbols.beginSymbol(name, decl) catch |err| @panic(@errorName(err)); @@ -139,7 +139,7 @@ pub fn Ordered_Generator(comptime Generator: type) type { pub fn gen_struct(self: *Self, comptime name: []const u8, comptime meta: StructMeta) void { comptime const decl: SymbolDeclaration = SymbolDeclaration{ - .Struct = rt.TypeInfo.Struct.init(meta, name, rt.dd), + .Struct = rt.TypeInfo.Struct.init(meta, name), }; self.symbols.beginSymbol(name, decl) catch |err| @panic(@errorName(err)); @@ -155,7 +155,7 @@ pub fn Ordered_Generator(comptime Generator: type) type { pub fn gen_enum(self: *Self, comptime name: []const u8, comptime meta: EnumMeta) void { comptime const decl: SymbolDeclaration = SymbolDeclaration{ - .Enum = rt.TypeInfo.Enum.init(meta, name, rt.dd), + .Enum = rt.TypeInfo.Enum.init(meta, name), }; self.symbols.beginSymbol(name, decl) catch |err| @panic(@errorName(err)); @@ -167,7 +167,7 @@ pub fn Ordered_Generator(comptime Generator: type) type { pub fn gen_union(self: *Self, comptime name: []const u8, comptime meta: UnionMeta) void { comptime const decl: SymbolDeclaration = SymbolDeclaration{ - .Union = rt.TypeInfo.Union.init(meta, name, rt.dd), + .Union = rt.TypeInfo.Union.init(meta, name), }; self.symbols.beginSymbol(name, decl) catch |err| @panic(@errorName(err)); diff --git a/src/runtime.zig b/src/runtime.zig index 7a3ee2a..bf49e9a 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -1,10 +1,13 @@ const std = @import("std"); const Allocator = std.mem.Allocator; -pub const dd: i32 = 2; - pub const TypeId = @TagType(TypeInfo); +const TypeInfoSingleton = struct { + resolved: bool = false, + info: TypeInfo = .{ .Void = {} }, +}; + pub const TypeInfo = union(enum) { Type: void, Void: void, @@ -38,7 +41,7 @@ pub const TypeInfo = union(enum) { is_signed: bool, bits: i32, - pub fn init(comptime m: std.builtin.TypeInfo.Int, comptime depth: i32) Int { + pub fn init(comptime m: std.builtin.TypeInfo.Int) Int { return comptime .{ .is_signed = m.is_signed, .bits = m.bits, @@ -51,7 +54,7 @@ pub const TypeInfo = union(enum) { pub const Float = struct { bits: i32, - pub fn init(comptime m: std.builtin.TypeInfo.Float, comptime depth: i32) Float { + pub fn init(comptime m: std.builtin.TypeInfo.Float) Float { return comptime .{ .bits = m.bits, }; @@ -81,13 +84,13 @@ pub const TypeInfo = union(enum) { C, }; - pub fn init(comptime m: std.builtin.TypeInfo.Pointer, comptime depth: i32) Pointer { + pub fn init(comptime m: std.builtin.TypeInfo.Pointer) Pointer { return comptime .{ .size = @intToEnum(TypeInfo.Pointer.Size, @enumToInt(m.size)), .is_const = m.is_const, .is_volatile = m.is_volatile, .alignment = m.alignment, - .child = &TypeInfo.init(m.child, depth), + .child = &TypeInfo.init(m.child), .is_allowzero = m.is_allowzero, }; } @@ -109,10 +112,10 @@ pub const TypeInfo = union(enum) { /// the value of the `child` field in this struct. However there is no way /// to refer to that type here, so we use `var`. // sentinel: var, - pub fn init(comptime m: std.builtin.TypeInfo.Array, comptime depth: i32) Array { + pub fn init(comptime m: std.builtin.TypeInfo.Array) Array { return comptime .{ .len = m.len, - .child = &TypeInfo.init(m.child, depth), + .child = &TypeInfo.init(m.child), }; } @@ -138,10 +141,10 @@ pub const TypeInfo = union(enum) { field_type: *const TypeInfo, // default_value: var, - pub fn init(comptime f: std.builtin.TypeInfo.StructField, comptime depth: i32) StructField { + pub fn init(comptime f: std.builtin.TypeInfo.StructField) StructField { return comptime .{ .name = f.name, - .field_type = &TypeInfo.init(f.field_type, depth), + .field_type = &TypeInfo.init(f.field_type), }; } @@ -162,7 +165,7 @@ pub const TypeInfo = union(enum) { fields: []const StructField, decls: []const Declaration, - pub fn init(comptime m: std.builtin.TypeInfo.Struct, comptime name: []const u8, comptime depth: i32) Struct { + pub fn init(comptime m: std.builtin.TypeInfo.Struct, comptime name: []const u8) Struct { return comptime .{ .name = name, .layout = @intToEnum(TypeInfo.ContainerLayout, @enumToInt(m.layout)), @@ -170,7 +173,7 @@ pub const TypeInfo = union(enum) { comptime var arr: [m.fields.len]StructField = undefined; inline for (m.fields) |f, i| { - arr[i] = StructField.init(f, depth - 1); + arr[i] = StructField.init(f); } break :fields &arr; @@ -179,7 +182,7 @@ pub const TypeInfo = union(enum) { comptime var arr: [m.decls.len]Declaration = undefined; inline for (m.decls) |f, i| { - arr[i] = Declaration.init(f, depth - 1); + arr[i] = Declaration.init(f); } break :decls &arr; @@ -201,9 +204,9 @@ pub const TypeInfo = union(enum) { pub const Optional = struct { child: *const TypeInfo, - pub fn init(comptime m: std.builtin.TypeInfo.Optional, comptime depth: i32) Optional { + pub fn init(comptime m: std.builtin.TypeInfo.Optional) Optional { return comptime .{ - .child = &TypeInfo.init(m.child, depth), + .child = &TypeInfo.init(m.child), }; } @@ -220,10 +223,10 @@ pub const TypeInfo = union(enum) { error_set: *const TypeInfo, payload: *const TypeInfo, - pub fn init(comptime m: std.builtin.TypeInfo.ErrorUnion, comptime depth: i32) ErrorUnion { + pub fn init(comptime m: std.builtin.TypeInfo.ErrorUnion) ErrorUnion { return comptime .{ - .error_set = &TypeInfo.init(m.error_set, depth), - .payload = &TypeInfo.init(m.payload, depth), + .error_set = &TypeInfo.init(m.error_set), + .payload = &TypeInfo.init(m.payload), }; } @@ -256,7 +259,7 @@ pub const TypeInfo = union(enum) { name: []const u8, value: i32, - pub fn init(comptime f: std.builtin.TypeInfo.EnumField, comptime depth: i32) EnumField { + pub fn init(comptime f: std.builtin.TypeInfo.EnumField) EnumField { return comptime .{ .name = f.name, .value = f.value, @@ -278,16 +281,16 @@ pub const TypeInfo = union(enum) { decls: []const Declaration, is_exhaustive: bool, - pub fn init(comptime m: std.builtin.TypeInfo.Enum, comptime name: []const u8, comptime depth: i32) Enum { + pub fn init(comptime m: std.builtin.TypeInfo.Enum, comptime name: []const u8) Enum { return comptime .{ .name = name, .layout = @intToEnum(TypeInfo.ContainerLayout, @enumToInt(m.layout)), - .tag_type = &TypeInfo.init(m.tag_type, depth), + .tag_type = &TypeInfo.init(m.tag_type), .fields = fields: { comptime var arr: [m.fields.len]EnumField = undefined; inline for (m.fields) |f, i| { - arr[i] = EnumField.init(f, depth - 1); + arr[i] = EnumField.init(f); } break :fields &arr; @@ -296,7 +299,7 @@ pub const TypeInfo = union(enum) { comptime var arr: [m.decls.len]Declaration = undefined; inline for (m.decls) |f, i| { - arr[i] = Declaration.init(f, depth - 1); + arr[i] = Declaration.init(f); } break :decls &arr; @@ -324,7 +327,7 @@ pub const TypeInfo = union(enum) { enum_field: ?EnumField, field_type: *const TypeInfo, - pub fn init(comptime f: std.builtin.TypeInfo.UnionField, comptime depth: i32) UnionField { + pub fn init(comptime f: std.builtin.TypeInfo.UnionField) UnionField { return comptime .{ .name = f.name, .enum_field = if (f.enum_field) |ef| @@ -334,7 +337,7 @@ pub const TypeInfo = union(enum) { } else null, - .field_type = &TypeInfo.init(f.field_type, depth), + .field_type = &TypeInfo.init(f.field_type), }; } @@ -360,16 +363,16 @@ pub const TypeInfo = union(enum) { fields: []const UnionField, decls: []const Declaration, - pub fn init(comptime m: std.builtin.TypeInfo.Union, comptime name: []const u8, comptime depth: i32) Union { + pub fn init(comptime m: std.builtin.TypeInfo.Union, comptime name: []const u8) Union { return comptime .{ .name = name, .layout = @intToEnum(TypeInfo.ContainerLayout, @enumToInt(m.layout)), - .tag_type = if (m.tag_type) |t| &TypeInfo.init(t, depth) else null, + .tag_type = if (m.tag_type) |t| &TypeInfo.init(t) else null, .fields = fields: { comptime var arr: [m.fields.len]UnionField = undefined; inline for (m.fields) |f, i| { - arr[i] = UnionField.init(f, depth - 1); + arr[i] = UnionField.init(f); } break :fields &arr; @@ -378,7 +381,7 @@ pub const TypeInfo = union(enum) { comptime var arr: [m.decls.len]Declaration = undefined; inline for (m.decls) |f, i| { - arr[i] = Declaration.init(f, depth - 1); + arr[i] = Declaration.init(f); } break :decls &arr; @@ -408,11 +411,11 @@ pub const TypeInfo = union(enum) { is_noalias: bool, arg_type: ?*const TypeInfo, - pub fn init(comptime f: std.builtin.TypeInfo.FnArg, comptime depth: i32) FnArg { + pub fn init(comptime f: std.builtin.TypeInfo.FnArg) FnArg { return comptime .{ .is_generic = f.is_generic, .is_noalias = f.is_noalias, - .arg_type = if (f.arg_type) |t| &TypeInfo.init(t, depth) else null, + .arg_type = if (f.arg_type) |t| &TypeInfo.init(t) else null, }; } @@ -434,17 +437,17 @@ pub const TypeInfo = union(enum) { return_type: ?*const TypeInfo, args: []const FnArg, - pub fn init(comptime m: std.builtin.TypeInfo.Fn, comptime depth: i32) Fn { + pub fn init(comptime m: std.builtin.TypeInfo.Fn) Fn { return comptime .{ .calling_convention = @intToEnum(CallingConvention, @enumToInt(m.calling_convention)), .is_generic = m.is_generic, .is_var_args = m.is_var_args, - .return_type = if (m.return_type) |t| &TypeInfo.init(t, depth) else null, + .return_type = if (m.return_type) |t| &TypeInfo.init(t) else null, .args = args: { comptime var arr: [m.args.len]FnArg = undefined; inline for (m.args) |f, i| { - arr[i] = FnArg.init(f, depth); + arr[i] = FnArg.init(f); } break :args &arr; @@ -476,9 +479,9 @@ pub const TypeInfo = union(enum) { pub const AnyFrame = struct { child: ?*const TypeInfo, - pub fn init(comptime m: std.builtin.TypeInfo.AnyFrame, comptime depth: i32) AnyFrame { + pub fn init(comptime m: std.builtin.TypeInfo.AnyFrame) AnyFrame { return comptime .{ - .child = if (m.child) |t| &TypeInfo.init(t, depth) else null, + .child = if (m.child) |t| &TypeInfo.init(t) else null, }; } @@ -497,10 +500,10 @@ pub const TypeInfo = union(enum) { len: i32, child: *const TypeInfo, - pub fn init(comptime m: std.builtin.TypeInfo.Vector, comptime depth: i32) Vector { + pub fn init(comptime m: std.builtin.TypeInfo.Vector) Vector { return comptime .{ .len = m.len, - .child = &TypeInfo.init(m.child, depth), + .child = &TypeInfo.init(m.child), }; } @@ -518,11 +521,11 @@ pub const TypeInfo = union(enum) { is_pub: bool, data: Data, - pub fn init(comptime f: std.builtin.TypeInfo.Declaration, comptime depth: i32) Declaration { + pub fn init(comptime f: std.builtin.TypeInfo.Declaration) Declaration { return comptime .{ .name = f.name, .is_pub = f.is_pub, - .data = Data.init(f.data, depth), + .data = Data.init(f.data), }; } @@ -539,13 +542,13 @@ pub const TypeInfo = union(enum) { Var: *const TypeInfo, Fn: FnDecl, - pub fn init(comptime d: std.builtin.TypeInfo.Declaration.Data, comptime depth: i32) Data { + pub fn init(comptime d: std.builtin.TypeInfo.Declaration.Data) Data { return comptime switch (d) { - .Type => |t| .{ .Type = &TypeInfo.init(t, depth) }, + .Type => |t| .{ .Type = &TypeInfo.init(t) }, .Var => |t| .{ - .Var = &TypeInfo.init(t, depth), + .Var = &TypeInfo.init(t), }, - .Fn => |t| .{ .Fn = FnDecl.init(t, depth) }, + .Fn => |t| .{ .Fn = FnDecl.init(t) }, }; } @@ -569,15 +572,15 @@ pub const TypeInfo = union(enum) { Never, }; - pub fn init(comptime t: std.builtin.TypeInfo.Declaration.Data.FnDecl, comptime depth: i32) FnDecl { + pub fn init(comptime t: std.builtin.TypeInfo.Declaration.Data.FnDecl) FnDecl { return comptime .{ - .fn_type = &TypeInfo.init(t.fn_type, depth), + .fn_type = &TypeInfo.init(t.fn_type), .inline_type = @intToEnum(TypeInfo.Declaration.Data.FnDecl.Inline, @enumToInt(t.inline_type)), .is_var_args = t.is_var_args, .is_extern = t.is_extern, .is_export = t.is_export, .lib_name = t.lib_name, - .return_type = &TypeInfo.init(t.return_type, depth), + .return_type = &TypeInfo.init(t.return_type), .arg_names = t.arg_names, }; } @@ -611,27 +614,43 @@ pub const TypeInfo = union(enum) { }; }; - pub fn init(comptime builtin: type, comptime depth: i32) TypeInfo { - if (depth <= 0) return .{ .Opaque = {} }; + pub fn alloc (comptime T: type) *TypeInfoSingleton { + comptime var ptr = TypeInfoSingleton {}; + + return &ptr; + } + + pub fn init(comptime T: type) TypeInfo { + return TypeInfo.initPtr(T).*; + } + + pub fn initPtr(comptime T: type) *const TypeInfo { + comptime var ptr = TypeInfo.alloc(T); + + if (ptr.resolved) { + return &ptr.info; + } + + ptr.resolved = true; - comptime const info = @typeInfo(builtin); + comptime const info = @typeInfo(T); - return comptime switch (info) { + ptr.info = comptime switch (info) { .Type => .{ .Type = {} }, .Void => .{ .Void = {} }, .Bool => .{ .Bool = {} }, .NoReturn => .{ .NoReturn = {} }, - .Int => |m| .{ .Int = Int.init(m, depth) }, - .Float => |m| .{ .Float = Float.init(m, depth) }, - .Pointer => |m| .{ .Pointer = Pointer.init(m, depth) }, - .Array => |m| .{ .Array = Array.init(m, depth) }, - .Struct => |m| .{ .Struct = Struct.init(m, @typeName(builtin), depth) }, + .Int => |m| .{ .Int = Int.init(m) }, + .Float => |m| .{ .Float = Float.init(m) }, + .Pointer => |m| .{ .Pointer = Pointer.init(m) }, + .Array => |m| .{ .Array = Array.init(m) }, + .Struct => |m| .{ .Struct = Struct.init(m, @typeName(T)) }, .ComptimeFloat => .{ .ComptimeFloat = {} }, .ComptimeInt => .{ .ComptimeInt = {} }, .Undefined => .{ .Undefined = {} }, .Null => .{ .Null = {} }, - .Optional => |m| .{ .Optional = Optional.init(m, depth) }, - .ErrorUnion => |m| .{ .ErrorUnion = ErrorUnion.init(m, depth) }, // TODO + .Optional => |m| .{ .Optional = Optional.init(m) }, + .ErrorUnion => |m| .{ .ErrorUnion = ErrorUnion.init(m) }, // TODO .ErrorSet => |m| .{ .ErrorSet = errorset: { if (m == null) return null; @@ -647,16 +666,18 @@ pub const TypeInfo = union(enum) { break :errorset &arr; }, }, - .Enum => |m| .{ .Enum = Enum.init(m, @typeName(builtin), depth) }, - .Union => |m| .{ .Union = Union.init(m, @typeName(builtin), depth) }, - .Fn => |m| .{ .Fn = Fn.init(m, depth) }, - .BoundFn => |m| .{ .BoundedFn = Fn.init(m, depth) }, + .Enum => |m| .{ .Enum = Enum.init(m, @typeName(T)) }, + .Union => |m| .{ .Union = Union.init(m, @typeName(T)) }, + .Fn => |m| .{ .Fn = Fn.init(m) }, + .BoundFn => |m| .{ .BoundedFn = Fn.init(m) }, .Opaque => .{ .Opaque = {} }, .Frame => .{ .Frame = {} }, // TODO - .AnyFrame => |m| .{ .AnyFrame = AnyFrame.init(m, depth) }, - .Vector => |m| .{ .Vector = Vector.init(m, depth) }, + .AnyFrame => |m| .{ .AnyFrame = AnyFrame.init(m) }, + .Vector => |m| .{ .Vector = Vector.init(m) }, .EnumLiteral => .{ .EnumLiteral = {} }, }; + + return &ptr.info; } pub fn deinit(self: *TypeInfo, allocator: *Allocator) void { @@ -709,32 +730,32 @@ const talloc = std.testing.allocator; // TODO .Type test "Runtime TypeInfo.Void" { - var info_void = TypeInfo.init(void, dd); + var info_void = TypeInfo.init(void); expect(info_void == .Void); } test "Runtime TypeInfo.Bool" { - var info_bool = TypeInfo.init(bool, dd); + var info_bool = TypeInfo.init(bool); expect(info_bool == .Bool); } // TODO .NoReturn test "Runtime TypeInfo.Int" { - var info_i32 = TypeInfo.init(i32, dd); + var info_i32 = TypeInfo.init(i32); expect(info_i32 == .Int); expectEqual(@as(i32, 32), info_i32.Int.bits); expectEqual(true, info_i32.Int.is_signed); } test "Runtime TypeInfo.Float" { - var info_f64 = TypeInfo.init(f64, dd); + var info_f64 = TypeInfo.init(f64); expect(info_f64 == .Float); expectEqual(@as(i32, 64), info_f64.Float.bits); } test "Runtime TypeInfo.Pointer" { - var info_pointer_f64 = TypeInfo.init(*f64, dd); + var info_pointer_f64 = TypeInfo.init(*f64); expect(info_pointer_f64 == .Pointer); expectEqual(TypeInfo.Pointer.Size.One, info_pointer_f64.Pointer.size); expectEqual(false, info_pointer_f64.Pointer.is_const); @@ -743,7 +764,7 @@ test "Runtime TypeInfo.Pointer" { expect(info_pointer_f64.Pointer.child.* == .Float); expectEqual(false, info_pointer_f64.Pointer.is_allowzero); - var info_pointer_many = TypeInfo.init([*]f64, dd); + var info_pointer_many = TypeInfo.init([*]f64); expect(info_pointer_many == .Pointer); expectEqual(TypeInfo.Pointer.Size.Many, info_pointer_many.Pointer.size); expectEqual(false, info_pointer_many.Pointer.is_const); @@ -754,7 +775,7 @@ test "Runtime TypeInfo.Pointer" { } test "Runtime TypeInfo.Array" { - var info_array = TypeInfo.init([2]i32, dd); + var info_array = TypeInfo.init([2]i32); expect(info_array == .Array); expectEqual(@as(i32, 2), info_array.Array.len); expect(info_array.Array.child.* == .Int); @@ -767,7 +788,7 @@ test "Runtime TypeInfo.Struct" { pub fn bar() void {} }; - var info_struct = TypeInfo.init(FooStruct, dd); + var info_struct = TypeInfo.init(FooStruct); expect(info_struct == .Struct); expect(info_struct.Struct.layout == .Auto); expectEqual(@as(usize, 1), info_struct.Struct.fields.len); @@ -776,12 +797,12 @@ test "Runtime TypeInfo.Struct" { } test "Runtime TypeInfo.ComptimeFloat" { - var info_comptime_float = TypeInfo.init(comptime_float, dd); + var info_comptime_float = TypeInfo.init(comptime_float); expect(info_comptime_float == .ComptimeFloat); } test "Runtime TypeInfo.ComptimeInt" { - var info_comptime_int = TypeInfo.init(comptime_int, dd); + var info_comptime_int = TypeInfo.init(comptime_int); expect(info_comptime_int == .ComptimeInt); } @@ -789,7 +810,7 @@ test "Runtime TypeInfo.ComptimeInt" { // // TODO .Null test "Runtime TypeInfo.Optional" { - var info_optional = TypeInfo.init(?i32, dd); + var info_optional = TypeInfo.init(?i32); expect(info_optional == .Optional); expect(info_optional.Optional.child.* == .Int); } @@ -802,7 +823,7 @@ test "Runtime TypeInfo.Enum" { Foo, Bar }; - var info_enum = TypeInfo.init(FooEnum, dd); + var info_enum = TypeInfo.init(FooEnum); expect(info_enum == .Enum); } @@ -811,13 +832,13 @@ test "Runtime TypeInfo.Union" { Foo: void, Bar: i32 }; - var info_union = TypeInfo.init(FooUnion, dd); + var info_union = TypeInfo.init(FooUnion); expect(info_union == .Union); } test "Runtime TypeInfo.Fn" { // .Fn - var info_fn = TypeInfo.init(fn () void, dd); + var info_fn = TypeInfo.init(fn () void); expect(info_fn == .Fn); } @@ -835,7 +856,7 @@ test "Runtime TypeInfo.Struct declarations" { pub fn thing(one: usize, two: *LameType, three: [*]u16) bool { return one == 1; } - }, dd); + }); expect(info_fn == .Struct); } From b640b12481a412abae8de7a1f5fa8796090a31c6 Mon Sep 17 00:00:00 2001 From: "Pedro M. Silva" Date: Mon, 9 Nov 2020 18:55:58 +0000 Subject: [PATCH 08/13] Upgrade to Zig version 0.7 --- README.md | 2 +- src/deps_graph.zig | 40 +++++++++++++++----------- src/generators/ordered.zig | 8 +++--- src/generators/python.zig | 4 +-- src/runtime.zig | 58 ++++++++++++++++++++++++++++---------- 5 files changed, 73 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 431c412..19e2f08 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Here are the following supported language binding outputs: - [x] C Bindings -- [ ] Python Bindings +- [x] Python Bindings - [ ] Rust Bindings - [ ] Go Bindings - [ ] Nim Bindings diff --git a/src/deps_graph.zig b/src/deps_graph.zig index e1ea83d..2378557 100644 --- a/src/deps_graph.zig +++ b/src/deps_graph.zig @@ -28,7 +28,7 @@ pub fn DepsGraph(comptime T: type) type { .symbols = StringHashMap(*Symbol).init(allocator), .dependants_of = StringHashMap(ArrayList(*Symbol)).init(allocator), .current_symbol = null, - .emitted = TailQueue(EmittedSymbol).init(), + .emitted = TailQueue(EmittedSymbol){}, }; } @@ -54,7 +54,7 @@ pub fn DepsGraph(comptime T: type) type { self.dependants_of.deinit(); while (self.emitted.popFirst()) |node| { - self.emitted.destroyNode(node, self.allocator); + self.allocator.destroy(node); } self.current_symbol = null; @@ -64,7 +64,7 @@ pub fn DepsGraph(comptime T: type) type { // A symbol_name can be blocking if either: // 1. There is no symbol declared with that name yet // 2. There is a symbol, but it is blocked by some dependencies too - const symbol = self.symbols.getValue(symbol_name) orelse return true; + const symbol = self.symbols.get(symbol_name) orelse return true; // TODO Should a symbol be able to depend on itself? // If so, what to do in that case? For now, it blocks itself @@ -86,11 +86,11 @@ pub fn DepsGraph(comptime T: type) type { // inconsistent (with a KV whose value is empty) errdefer self.symbols.removeAssertDiscard(name); - result.kv.value = try self.allocator.create(Symbol); + result.entry.value = try self.allocator.create(Symbol); - result.kv.value.* = Symbol.init(self.allocator, name, payload); + result.entry.value.* = Symbol.init(self.allocator, name, payload); - self.current_symbol = result.kv.value; + self.current_symbol = result.entry.value; } pub const AddDependencyError = error{ NoSymbol, OutOfMemory }; @@ -113,19 +113,19 @@ pub fn DepsGraph(comptime T: type) type { // Creates or retrieves the array list that contains what symbols // depend on dependency_name. Also checks if this symbol is already there if (result.found_existing) { - for (result.kv.value.items) |symbol| { + for (result.entry.value.items) |symbol| { if (symbol == current_symbol) { already_added = true; } } } else { - result.kv.value = ArrayList(*Symbol).init(self.allocator); + result.entry.value = ArrayList(*Symbol).init(self.allocator); } if (!already_added) { - try result.kv.value.append(current_symbol); + try result.entry.value.append(current_symbol); - if (self.dependants_of.get(current_symbol.name)) |dependants| { + if (self.dependants_of.getEntry(current_symbol.name)) |dependants| { for (dependants.value.items) |dep| { if (std.mem.eql(u8, dep.name, dependency_name)) { try dep.addDependency(.{ .Circular = current_symbol.name }); @@ -147,13 +147,19 @@ pub fn DepsGraph(comptime T: type) type { pub const EndSymbolError = error{OutOfMemory}; + pub fn createNode(comptime V: type, data: V, allocator: *Allocator) !*TailQueue(V).Node { + var node = try allocator.create(TailQueue(V).Node); + node.* = .{ .data = data }; + return node; + } + pub fn endSymbol(self: *Self) EndSymbolError!void { var current_symbol = self.current_symbol orelse return; - var unblock_queue = std.TailQueue(EmittedSymbol).init(); + var unblock_queue = std.TailQueue(EmittedSymbol){}; if (!self.isBlocking(current_symbol.name)) { - const node = try unblock_queue.createNode(.{ + const node = try createNode(EmittedSymbol, .{ .symbol = current_symbol, .partial = current_symbol.hasDependencies(), }, self.allocator); @@ -169,7 +175,7 @@ pub fn DepsGraph(comptime T: type) type { const symbol = symbol_node.data.symbol; - if (self.dependants_of.get(symbol.name)) |kv| { + if (self.dependants_of.getEntry(symbol.name)) |kv| { for (kv.value.items) |dependant| { if (dependant.removeDependency(symbol.name)) |dep| { const unblock_dep = (!dependant.emitted and !dependant.hasDependenciesOfType(.Linear)) or !dependant.hasDependencies(); @@ -178,7 +184,7 @@ pub fn DepsGraph(comptime T: type) type { dependant.emitted = true; - const node = try unblock_queue.createNode(.{ + const node = try createNode(EmittedSymbol, .{ .symbol = dependant, .partial = dependant.hasDependencies(), }, self.allocator); @@ -197,7 +203,7 @@ pub fn DepsGraph(comptime T: type) type { var symbol = symbol_node.data; - self.emitted.destroyNode(symbol_node, self.allocator); + self.allocator.destroy(symbol_node); return symbol; } @@ -457,8 +463,8 @@ test "Three tier circular dependencies" { expectSymbol(deps.readEmitted(), "WackType", false); expectSymbol(deps.readEmitted(), "WhatsAUnion", false); expectSymbol(deps.readEmitted(), "LameType", false); - + expect(deps.readEmitted() == null); - + deps.deinit(); } diff --git a/src/generators/ordered.zig b/src/generators/ordered.zig index 8793dd6..e212c5d 100644 --- a/src/generators/ordered.zig +++ b/src/generators/ordered.zig @@ -85,14 +85,14 @@ pub fn Ordered_Generator(comptime Generator: type) type { var result = try self.emitted_phase.getOrPut(symbol_name); if (!result.found_existing) { - result.kv.value = if (partial) .Signature else .Full; + result.entry.value = if (partial) .Signature else .Full; - return result.kv.value; - } else if (result.kv.value == .Signature) { + return result.entry.value; + } else if (result.entry.value == .Signature) { if (partial) { return null; } else { - result.kv.value = .Full; + result.entry.value = .Full; return .Body; } diff --git a/src/generators/python.zig b/src/generators/python.zig index 3b612e5..e181acc 100644 --- a/src/generators/python.zig +++ b/src/generators/python.zig @@ -67,7 +67,7 @@ pub const Python_Generator = struct { self.write("\n\n"); } - pub fn _gen_fields(self: *Self, name: []const u8, fields: var, phase: SymbolPhase) void { + pub fn _gen_fields(self: *Self, name: []const u8, fields: anytype, phase: SymbolPhase) void { comptime const prefix = "\t "; if (phase == .Body) { @@ -219,7 +219,7 @@ pub const Python_Generator = struct { self.write(&[1]u8{char}); } - fn print(self: *Self, comptime fmt: []const u8, args: var) void { + fn print(self: *Self, comptime fmt: []const u8, args: anytype) void { self.file.writer().print(fmt, args) catch unreachable; } diff --git a/src/runtime.zig b/src/runtime.zig index bf49e9a..5b95537 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -29,7 +29,7 @@ pub const TypeInfo = union(enum) { Union: Union, Fn: Fn, BoundFn: Fn, - Opaque: void, + Opaque: void, // TODO Opaque Frame: Frame, AnyFrame: AnyFrame, Vector: Vector, @@ -74,7 +74,7 @@ pub const TypeInfo = union(enum) { /// The type of the sentinel is the element type of the pointer, which is /// the value of the `child` field in this struct. However there is no way /// to refer to that type here, so we use `var`. - // sentinel: var, + // sentinel: anytype, /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Size = enum { @@ -111,7 +111,7 @@ pub const TypeInfo = union(enum) { /// The type of the sentinel is the element type of the array, which is /// the value of the `child` field in this struct. However there is no way /// to refer to that type here, so we use `var`. - // sentinel: var, + // sentinel: anytype, pub fn init(comptime m: std.builtin.TypeInfo.Array) Array { return comptime .{ .len = m.len, @@ -139,12 +139,16 @@ pub const TypeInfo = union(enum) { pub const StructField = struct { name: []const u8, field_type: *const TypeInfo, - // default_value: var, + // default_value: anytype, + is_comptime: bool, + alignment: i32, pub fn init(comptime f: std.builtin.TypeInfo.StructField) StructField { return comptime .{ .name = f.name, .field_type = &TypeInfo.init(f.field_type), + .is_comptime = f.is_comptime, + .alignment = f.alignment, }; } @@ -160,10 +164,13 @@ pub const TypeInfo = union(enum) { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Struct = struct { + // Additional Field name: ?[]const u8, + layout: ContainerLayout, fields: []const StructField, decls: []const Declaration, + is_tuple: bool, pub fn init(comptime m: std.builtin.TypeInfo.Struct, comptime name: []const u8) Struct { return comptime .{ @@ -187,6 +194,7 @@ pub const TypeInfo = union(enum) { break :decls &arr; }, + .is_tuple = m.is_tuple, }; } @@ -274,7 +282,9 @@ pub const TypeInfo = union(enum) { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Enum = struct { + // Additional Field name: ?[]const u8, + layout: ContainerLayout, tag_type: *const TypeInfo, fields: []const EnumField, @@ -323,21 +333,17 @@ pub const TypeInfo = union(enum) { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const UnionField = struct { + // Additional Field name: []const u8, - enum_field: ?EnumField, + field_type: *const TypeInfo, + alignment: i32, pub fn init(comptime f: std.builtin.TypeInfo.UnionField) UnionField { return comptime .{ .name = f.name, - .enum_field = if (f.enum_field) |ef| - .{ - .name = ef.name, - .value = ef.value, - } - else - null, .field_type = &TypeInfo.init(f.field_type), + .alignment = f.alignment, }; } @@ -357,7 +363,9 @@ pub const TypeInfo = union(enum) { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Union = struct { + // Additional Field name: ?[]const u8, + layout: ContainerLayout, tag_type: ?*const TypeInfo, fields: []const UnionField, @@ -432,6 +440,7 @@ pub const TypeInfo = union(enum) { /// therefore must be kept in sync with the compiler implementation. pub const Fn = struct { calling_convention: CallingConvention, + alignment: i32, is_generic: bool, is_var_args: bool, return_type: ?*const TypeInfo, @@ -440,6 +449,7 @@ pub const TypeInfo = union(enum) { pub fn init(comptime m: std.builtin.TypeInfo.Fn) Fn { return comptime .{ .calling_convention = @intToEnum(CallingConvention, @enumToInt(m.calling_convention)), + .alignment = m.alignment, .is_generic = m.is_generic, .is_var_args = m.is_var_args, .return_type = if (m.return_type) |t| &TypeInfo.init(t) else null, @@ -468,10 +478,28 @@ pub const TypeInfo = union(enum) { } }; + pub const Opaque = struct { + decls: []const Declaration, + + pub fn init(comptime m: std.builtin.TypeInfo.Opaque) Opaque { + return comptime .{ + .decls = decls: { + comptime var arr: [m.decls.len]Declaration = undefined; + + inline for (m.decls) |f, i| { + arr[i] = Declaration.init(f); + } + + break :decls &arr; + }, + }; + } + }; + /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Frame = struct { - // function: var, + // function: anytype, }; /// This data structure is used by the Zig language code generation and @@ -614,8 +642,8 @@ pub const TypeInfo = union(enum) { }; }; - pub fn alloc (comptime T: type) *TypeInfoSingleton { - comptime var ptr = TypeInfoSingleton {}; + pub fn alloc(comptime T: type) *TypeInfoSingleton { + comptime var ptr = TypeInfoSingleton{}; return &ptr; } From ddb4839458dac0170d6caa6a2b4ad7e6a7ae8578 Mon Sep 17 00:00:00 2001 From: "Pedro M. Silva" Date: Wed, 26 Aug 2020 18:35:57 +0100 Subject: [PATCH 09/13] Remove unnecessary allocator --- src/generators/c.zig | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/generators/c.zig b/src/generators/c.zig index e7e23e4..eaeaa83 100644 --- a/src/generators/c.zig +++ b/src/generators/c.zig @@ -13,20 +13,10 @@ pub const C_Generator = struct { const Self = @This(); pub fn init(comptime src_file: []const u8, dst_dir: *Dir) Self { - var strbuf = [_]u8{0} ** 256; - - var fba = std.heap.FixedBufferAllocator.init(strbuf[0..]); - - var allocator = &fba.allocator; - comptime const filebaseext = std.fs.path.basename(src_file); comptime const filebase = filebaseext[0 .. filebaseext.len - 4]; - var filename = fba.allocator.alloc(u8, filebase.len + 2) catch unreachable; - std.mem.copy(u8, filename, filebase); - std.mem.copy(u8, filename[filebase.len..], ".h"); - - var file = dst_dir.createFile(filename, .{}) catch + var file = dst_dir.createFile(filebase ++ ".h", .{}) catch @panic("Failed to create header file for source: " ++ src_file); var res = Self{ .file = file }; From 39baeba3d4e5e00a2ba0aca0b86e32f0b84cac6d Mon Sep 17 00:00:00 2001 From: "Pedro M. Silva" Date: Mon, 7 Jun 2021 19:55:48 +0100 Subject: [PATCH 10/13] Update to Zig 0.8 --- src/deps_graph.zig | 108 +++++++++--------- src/runtime.zig | 270 +++++++++++++++++++++++++++++++++++---------- 2 files changed, 265 insertions(+), 113 deletions(-) diff --git a/src/deps_graph.zig b/src/deps_graph.zig index 2378557..acbf610 100644 --- a/src/deps_graph.zig +++ b/src/deps_graph.zig @@ -36,10 +36,10 @@ pub fn DepsGraph(comptime T: type) type { var s_iter = self.symbols.iterator(); while (s_iter.next()) |entry| { // Here entry.value is a *Symbol, so we deinit the symbol - entry.value.deinit(self.allocator); + entry.value_ptr.*.deinit(self.allocator); // And free the pointer - self.allocator.destroy(entry.value); + self.allocator.destroy(entry.value_ptr.*); } self.symbols.deinit(); @@ -48,7 +48,7 @@ pub fn DepsGraph(comptime T: type) type { while (d_iter.next()) |entry| { // Here entry.value is an ArrayList(*Symbol), so we simply // deinit the array list (since the pointers were freed already) - entry.value.deinit(); + entry.value_ptr.*.deinit(); } self.dependants_of.deinit(); @@ -76,7 +76,7 @@ pub fn DepsGraph(comptime T: type) type { pub const BeginSymbolError = error{ DuplicateSymbol, OutOfMemory }; pub fn beginSymbol(self: *Self, name: []const u8, payload: T) BeginSymbolError!void { - const result = try self.symbols.getOrPut(name); + var result = try self.symbols.getOrPut(name); if (result.found_existing) { return error.DuplicateSymbol; @@ -84,13 +84,13 @@ pub fn DepsGraph(comptime T: type) type { // Since the allocation can fail, we do not want to leave the state // inconsistent (with a KV whose value is empty) - errdefer self.symbols.removeAssertDiscard(name); + errdefer std.debug.assert(self.symbols.remove(name)); - result.entry.value = try self.allocator.create(Symbol); + result.value_ptr.* = try self.allocator.create(Symbol); - result.entry.value.* = Symbol.init(self.allocator, name, payload); + result.value_ptr.*.* = Symbol.init(self.allocator, name, payload); - self.current_symbol = result.entry.value; + self.current_symbol = result.value_ptr.*; } pub const AddDependencyError = error{ NoSymbol, OutOfMemory }; @@ -113,20 +113,20 @@ pub fn DepsGraph(comptime T: type) type { // Creates or retrieves the array list that contains what symbols // depend on dependency_name. Also checks if this symbol is already there if (result.found_existing) { - for (result.entry.value.items) |symbol| { + for (result.value_ptr.items) |symbol| { if (symbol == current_symbol) { already_added = true; } } } else { - result.entry.value = ArrayList(*Symbol).init(self.allocator); + result.value_ptr.* = ArrayList(*Symbol).init(self.allocator); } if (!already_added) { - try result.entry.value.append(current_symbol); + try result.value_ptr.append(current_symbol); if (self.dependants_of.getEntry(current_symbol.name)) |dependants| { - for (dependants.value.items) |dep| { + for (dependants.value_ptr.items) |dep| { if (std.mem.eql(u8, dep.name, dependency_name)) { try dep.addDependency(.{ .Circular = current_symbol.name }); @@ -176,7 +176,7 @@ pub fn DepsGraph(comptime T: type) type { const symbol = symbol_node.data.symbol; if (self.dependants_of.getEntry(symbol.name)) |kv| { - for (kv.value.items) |dependant| { + for (kv.value_ptr.items) |dependant| { if (dependant.removeDependency(symbol.name)) |dep| { const unblock_dep = (!dependant.emitted and !dependant.hasDependenciesOfType(.Linear)) or !dependant.hasDependencies(); @@ -306,7 +306,7 @@ pub fn DepsGraph(comptime T: type) type { return self.dependencies.items.len > 0; } - pub fn hasDependenciesOfType(self: *Symbol, tag: @TagType(Dependency)) bool { + pub fn hasDependenciesOfType(self: *Symbol, tag: std.meta.TagType(Dependency)) bool { for (self.dependencies.items) |dep| { if (dep == tag) return true; } @@ -328,8 +328,8 @@ pub fn DepsGraph(comptime T: type) type { pub fn next(self: *BlockedSymbolsIterator) ?*Symbol { while (self.hash_iter.next()) |symbol| { - if (symbol.value.hasDependenciesOfType(.Linear)) { - return symbol.value; + if (symbol.value_ptr.*.hasDependenciesOfType(.Linear)) { + return symbol.value_ptr.*; } } @@ -343,10 +343,10 @@ const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; const expectEqualStrings = std.testing.expectEqualStrings; -fn expectSymbol(emitted: ?DepsGraph(void).EmittedSymbol, expected_name: []const u8, expected_partial: bool) void { - expect(emitted != null); - expectEqualStrings(expected_name, emitted.?.symbol.name); - expectEqual(expected_partial, emitted.?.partial); +fn expectSymbol(emitted: ?DepsGraph(void).EmittedSymbol, expected_name: []const u8, expected_partial: bool) !void { + try expect(emitted != null); + try expectEqualStrings(expected_name, emitted.?.symbol.name); + try expectEqual(expected_partial, emitted.?.partial); } test "Simple dependency graph with circular dependencies" { @@ -357,42 +357,42 @@ test "Simple dependency graph with circular dependencies" { try deps.beginSymbol("SourceMap", {}); try deps.addDependency("TextSpan"); try deps.endSymbol(); - expect(deps.readEmitted() == null); + try expect(deps.readEmitted() == null); try deps.beginSymbol("TextSpan", {}); try deps.addDependency("TextPosition"); try deps.endSymbol(); - expect(deps.readEmitted() == null); + try expect(deps.readEmitted() == null); try deps.beginSymbol("TextPosition", {}); try deps.addDependency("TextSpan"); try deps.endSymbol(); - expect(deps.emitted.first != null); + try expect(deps.emitted.first != null); if (deps.readEmitted()) |s| { - expectEqualStrings(s.symbol.name, "TextPosition"); - expectEqual(s.partial, true); + try expectEqualStrings(s.symbol.name, "TextPosition"); + try expectEqual(s.partial, true); } - expect(deps.emitted.first != null); + try expect(deps.emitted.first != null); if (deps.readEmitted()) |s| { - expectEqualStrings(s.symbol.name, "TextSpan"); - expectEqual(s.partial, false); + try expectEqualStrings(s.symbol.name, "TextSpan"); + try expectEqual(s.partial, false); } - expect(deps.emitted.first != null); + try expect(deps.emitted.first != null); if (deps.readEmitted()) |s| { - expectEqualStrings(s.symbol.name, "SourceMap"); - expectEqual(s.partial, false); + try expectEqualStrings(s.symbol.name, "SourceMap"); + try expectEqual(s.partial, false); } - expect(deps.emitted.first != null); + try expect(deps.emitted.first != null); if (deps.readEmitted()) |s| { - expectEqualStrings(s.symbol.name, "TextPosition"); - expectEqual(s.partial, false); + try expectEqualStrings(s.symbol.name, "TextPosition"); + try expectEqual(s.partial, false); } - expect(deps.readEmitted() == null); + try expect(deps.readEmitted() == null); deps.deinit(); } @@ -405,33 +405,33 @@ test "Blocked symbols iterator" { try deps.beginSymbol("SourceMap", {}); try deps.addDependency("TextSpan"); try deps.endSymbol(); - expect(deps.readEmitted() == null); + try expect(deps.readEmitted() == null); try deps.beginSymbol("TextSpan", {}); try deps.endSymbol(); - expect(deps.emitted.first != null); + try expect(deps.emitted.first != null); if (deps.readEmitted()) |s| { - expectEqualStrings(s.symbol.name, "TextSpan"); - expectEqual(s.partial, false); + try expectEqualStrings(s.symbol.name, "TextSpan"); + try expectEqual(s.partial, false); } - expect(deps.emitted.first != null); + try expect(deps.emitted.first != null); if (deps.readEmitted()) |s| { - expectEqualStrings(s.symbol.name, "SourceMap"); - expectEqual(s.partial, false); + try expectEqualStrings(s.symbol.name, "SourceMap"); + try expectEqual(s.partial, false); } - expect(deps.readEmitted() == null); + try expect(deps.readEmitted() == null); try deps.beginSymbol("TextPosition", {}); try deps.addDependency("Cursor"); try deps.endSymbol(); - expect(deps.readEmitted() == null); + try expect(deps.readEmitted() == null); var iter = deps.blockedIterator(); var symbol = iter.next(); - expect(symbol != null); - expectEqualStrings(symbol.?.name, "TextPosition"); - expect(iter.next() == null); + try expect(symbol != null); + try expectEqualStrings(symbol.?.name, "TextPosition"); + try expect(iter.next() == null); deps.deinit(); } @@ -457,14 +457,14 @@ test "Three tier circular dependencies" { try deps.addDependency("LameType"); try deps.endSymbol(); - expectSymbol(deps.readEmitted(), "LookMaAnEnum", false); - expectSymbol(deps.readEmitted(), "WhatsAUnion", true); - expectSymbol(deps.readEmitted(), "LameType", true); - expectSymbol(deps.readEmitted(), "WackType", false); - expectSymbol(deps.readEmitted(), "WhatsAUnion", false); - expectSymbol(deps.readEmitted(), "LameType", false); + try expectSymbol(deps.readEmitted(), "LookMaAnEnum", false); + try expectSymbol(deps.readEmitted(), "WhatsAUnion", true); + try expectSymbol(deps.readEmitted(), "LameType", true); + try expectSymbol(deps.readEmitted(), "WackType", false); + try expectSymbol(deps.readEmitted(), "WhatsAUnion", false); + try expectSymbol(deps.readEmitted(), "LameType", false); - expect(deps.readEmitted() == null); + try expect(deps.readEmitted() == null); deps.deinit(); } diff --git a/src/runtime.zig b/src/runtime.zig index 5b95537..eb5302b 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -38,16 +38,19 @@ pub const TypeInfo = union(enum) { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Int = struct { - is_signed: bool, + signedness: Signedness, bits: i32, pub fn init(comptime m: std.builtin.TypeInfo.Int) Int { return comptime .{ - .is_signed = m.is_signed, + .signedness = @intToEnum(Signedness, @enumToInt(m.signedness)), .bits = m.bits, }; } }; + comptime { + validateSymbolInSync(Int, std.builtin.TypeInfo.Int, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -60,6 +63,9 @@ pub const TypeInfo = union(enum) { }; } }; + comptime { + validateSymbolInSync(Float, std.builtin.TypeInfo.Float, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -101,6 +107,11 @@ pub const TypeInfo = union(enum) { allocator.destroy(self.child); } }; + comptime { + validateSymbolInSync(Pointer, std.builtin.TypeInfo.Pointer, .{ + .ignore_fields = .{"sentinel"}, + }); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -125,6 +136,11 @@ pub const TypeInfo = union(enum) { allocator.destroy(self.child); } }; + comptime { + validateSymbolInSync(Array, std.builtin.TypeInfo.Array, .{ + .ignore_fields = .{"sentinel"}, + }); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -133,6 +149,9 @@ pub const TypeInfo = union(enum) { Extern, Packed, }; + comptime { + validateSymbolInSync(ContainerLayout, std.builtin.TypeInfo.ContainerLayout, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -160,6 +179,11 @@ pub const TypeInfo = union(enum) { allocator.destroy(self.field_type); } }; + comptime { + validateSymbolInSync(StructField, std.builtin.TypeInfo.StructField, .{ + .ignore_fields = .{"default_value"}, + }); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -197,6 +221,9 @@ pub const TypeInfo = union(enum) { .is_tuple = m.is_tuple, }; } + comptime { + validateSymbolInSync(Struct, std.builtin.TypeInfo.Struct, .{}); + } pub fn deinit(self: *const Struct, allocator: *Allocator) void { for (self.fields) |f| f.deinit(allocator); @@ -224,6 +251,9 @@ pub const TypeInfo = union(enum) { allocator.destroy(self.child); } }; + comptime { + validateSymbolInSync(Optional, std.builtin.TypeInfo.Optional, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -246,6 +276,9 @@ pub const TypeInfo = union(enum) { allocator.destroy(self.payload); } }; + comptime { + validateSymbolInSync(ErrorUnion, std.builtin.TypeInfo.ErrorUnion, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -256,6 +289,9 @@ pub const TypeInfo = union(enum) { allocator.free(self.name); } }; + comptime { + validateSymbolInSync(Error, std.builtin.TypeInfo.Error, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -278,6 +314,9 @@ pub const TypeInfo = union(enum) { allocator.free(self.name); } }; + comptime { + validateSymbolInSync(EnumField, std.builtin.TypeInfo.EnumField, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -329,6 +368,9 @@ pub const TypeInfo = union(enum) { allocator.destroy(self.tag_type); } }; + comptime { + validateSymbolInSync(Enum, std.builtin.TypeInfo.Enum, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -359,6 +401,9 @@ pub const TypeInfo = union(enum) { } } }; + comptime { + validateSymbolInSync(UnionField, std.builtin.TypeInfo.UnionField, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -411,6 +456,9 @@ pub const TypeInfo = union(enum) { } } }; + comptime { + validateSymbolInSync(Union, std.builtin.TypeInfo.Union, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -435,6 +483,9 @@ pub const TypeInfo = union(enum) { } } }; + comptime { + validateSymbolInSync(FnArg, std.builtin.TypeInfo.FnArg, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -477,6 +528,9 @@ pub const TypeInfo = union(enum) { allocator.free(self.args); } }; + comptime { + validateSymbolInSync(Fn, std.builtin.TypeInfo.Fn, .{}); + } pub const Opaque = struct { decls: []const Declaration, @@ -495,12 +549,20 @@ pub const TypeInfo = union(enum) { }; } }; + comptime { + validateSymbolInSync(Opaque, std.builtin.TypeInfo.Opaque, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. pub const Frame = struct { // function: anytype, }; + comptime { + validateSymbolInSync(Frame, std.builtin.TypeInfo.Frame, .{ + .ignore_fields = .{"function"}, + }); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -521,6 +583,9 @@ pub const TypeInfo = union(enum) { } } }; + comptime { + validateSymbolInSync(AnyFrame, std.builtin.TypeInfo.AnyFrame, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -541,6 +606,9 @@ pub const TypeInfo = union(enum) { allocator.destroy(self.child); } }; + comptime { + validateSymbolInSync(Vector, std.builtin.TypeInfo.Vector, .{}); + } /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. @@ -584,7 +652,7 @@ pub const TypeInfo = union(enum) { /// therefore must be kept in sync with the compiler implementation. pub const FnDecl = struct { fn_type: *const TypeInfo, - inline_type: Inline, + is_noinline: bool, is_var_args: bool, is_extern: bool, is_export: bool, @@ -592,18 +660,10 @@ pub const TypeInfo = union(enum) { return_type: *const TypeInfo, arg_names: []const []const u8, - /// This data structure is used by the Zig language code generation and - /// therefore must be kept in sync with the compiler implementation. - pub const Inline = enum { - Auto, - Always, - Never, - }; - pub fn init(comptime t: std.builtin.TypeInfo.Declaration.Data.FnDecl) FnDecl { return comptime .{ .fn_type = &TypeInfo.init(t.fn_type), - .inline_type = @intToEnum(TypeInfo.Declaration.Data.FnDecl.Inline, @enumToInt(t.inline_type)), + .is_noinline = t.is_noinline, .is_var_args = t.is_var_args, .is_extern = t.is_extern, .is_export = t.is_export, @@ -628,6 +688,9 @@ pub const TypeInfo = union(enum) { } } }; + comptime { + validateSymbolInSync(FnDecl, std.builtin.TypeInfo.Declaration.Data.FnDecl, .{}); + } pub fn deinit(self: *const Data, allocator: *Allocator) void { switch (self.*) { @@ -640,6 +703,34 @@ pub const TypeInfo = union(enum) { } } }; + comptime { + validateSymbolInSync(Data, std.builtin.TypeInfo.Declaration.Data, .{}); + } + }; + comptime { + validateSymbolInSync(Declaration, std.builtin.TypeInfo.Declaration, .{}); + } + + // Validate the whole TypeInfo sync + comptime { + @setEvalBranchQuota(2000); + validateSymbolInSync(TypeInfo, std.builtin.TypeInfo, .{}); + } + + usingnamespace comptime blk: { + var uniqueIdCounter: usize = 0; + + break :blk struct { + pub fn uniqueId(comptime T: type) usize { + comptime { + var id = uniqueIdCounter; + + uniqueIdCounter += 1; + + return id; + } + } + }; }; pub fn alloc(comptime T: type) *TypeInfoSingleton { @@ -735,9 +826,9 @@ pub const TypeInfo = union(enum) { pub const CallingConvention = enum { Unspecified, C, - Cold, Naked, Async, + Inline, Interrupt, Signal, Stdcall, @@ -747,8 +838,75 @@ pub const CallingConvention = enum { APCS, AAPCS, AAPCSVFP, + SysV, }; +pub const Signedness = enum { + signed, + unsigned, +}; + +pub fn hasField(comptime T: type, comptime field_name: []const u8) bool { + inline for (comptime std.meta.fields(T)) |field| { + if (std.mem.eql(u8, field.name, field_name) == true) { + return true; + } + } + + return false; +} + +/// Function to be run in compile time, responsible for verifying if the +/// structures/enums/unions defined in this file to represent the TypeInfo at +/// runtime in sync with the current Zig version's comptime structures/enums/unions +pub fn validateSymbolInSync(comptime runtime_type: type, comptime builtin_type: type, comptime options: anytype) void { + const builtin_type_info = @typeInfo(builtin_type); + const runtime_type_info = @typeInfo(runtime_type); + + // Make sure that the runtime type is a struct as well + if (std.mem.eql(u8, @tagName(builtin_type_info), @tagName(runtime_type_info)) == false) { + @compileError( + "Type of " ++ @typeName(builtin_type) ++ + " is " ++ @tagName(builtin_type_info) ++ + " but runtime type is " ++ @tagName(runtime_type_info), + ); + } + + switch (builtin_type_info) { + .Struct, .Enum, .Union => { + // Compare the fields + inline for (std.meta.fields(builtin_type)) |builtin_field| { + var missing_field: bool = false; + + if (hasField(runtime_type, builtin_field.name) == false) { + missing_field = true; + + if (@hasField(@TypeOf(options), "ignore_fields")) { + inline for (options.ignore_fields) |ignore_field| { + if (std.mem.eql(u8, ignore_field, builtin_field.name) == true) { + missing_field = false; + break; + } + } + } + + if (missing_field == true) { + @compileError( + "Field " ++ builtin_field.name ++ + " is missing in type " ++ @typeName(runtime_type), + ); + } + } + } + }, + else => @compileError( + "Cannot validate symbol in sync " ++ @typeName(builtin_type) ++ + " because type " ++ @tagName(builtin_type_info) ++ + " is not supported", + ), + } +} + const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; const expectEqualStrings = std.testing.expectEqualStrings; @@ -759,54 +917,54 @@ const talloc = std.testing.allocator; test "Runtime TypeInfo.Void" { var info_void = TypeInfo.init(void); - expect(info_void == .Void); + try expect(info_void == .Void); } test "Runtime TypeInfo.Bool" { var info_bool = TypeInfo.init(bool); - expect(info_bool == .Bool); + try expect(info_bool == .Bool); } // TODO .NoReturn test "Runtime TypeInfo.Int" { var info_i32 = TypeInfo.init(i32); - expect(info_i32 == .Int); - expectEqual(@as(i32, 32), info_i32.Int.bits); - expectEqual(true, info_i32.Int.is_signed); + try expect(info_i32 == .Int); + try expectEqual(@as(i32, 32), info_i32.Int.bits); + try expectEqual(true, info_i32.Int.signedness == .signed); } test "Runtime TypeInfo.Float" { var info_f64 = TypeInfo.init(f64); - expect(info_f64 == .Float); - expectEqual(@as(i32, 64), info_f64.Float.bits); + try expect(info_f64 == .Float); + try expectEqual(@as(i32, 64), info_f64.Float.bits); } test "Runtime TypeInfo.Pointer" { var info_pointer_f64 = TypeInfo.init(*f64); - expect(info_pointer_f64 == .Pointer); - expectEqual(TypeInfo.Pointer.Size.One, info_pointer_f64.Pointer.size); - expectEqual(false, info_pointer_f64.Pointer.is_const); - expectEqual(false, info_pointer_f64.Pointer.is_volatile); - expectEqual(@as(i32, 8), info_pointer_f64.Pointer.alignment); - expect(info_pointer_f64.Pointer.child.* == .Float); - expectEqual(false, info_pointer_f64.Pointer.is_allowzero); + try expect(info_pointer_f64 == .Pointer); + try expectEqual(TypeInfo.Pointer.Size.One, info_pointer_f64.Pointer.size); + try expectEqual(false, info_pointer_f64.Pointer.is_const); + try expectEqual(false, info_pointer_f64.Pointer.is_volatile); + try expectEqual(@as(i32, 8), info_pointer_f64.Pointer.alignment); + try expect(info_pointer_f64.Pointer.child.* == .Float); + try expectEqual(false, info_pointer_f64.Pointer.is_allowzero); var info_pointer_many = TypeInfo.init([*]f64); - expect(info_pointer_many == .Pointer); - expectEqual(TypeInfo.Pointer.Size.Many, info_pointer_many.Pointer.size); - expectEqual(false, info_pointer_many.Pointer.is_const); - expectEqual(false, info_pointer_many.Pointer.is_volatile); - expectEqual(@as(i32, 8), info_pointer_many.Pointer.alignment); - expect(info_pointer_many.Pointer.child.* == .Float); - expectEqual(false, info_pointer_many.Pointer.is_allowzero); + try expect(info_pointer_many == .Pointer); + try expectEqual(TypeInfo.Pointer.Size.Many, info_pointer_many.Pointer.size); + try expectEqual(false, info_pointer_many.Pointer.is_const); + try expectEqual(false, info_pointer_many.Pointer.is_volatile); + try expectEqual(@as(i32, 8), info_pointer_many.Pointer.alignment); + try expect(info_pointer_many.Pointer.child.* == .Float); + try expectEqual(false, info_pointer_many.Pointer.is_allowzero); } test "Runtime TypeInfo.Array" { var info_array = TypeInfo.init([2]i32); - expect(info_array == .Array); - expectEqual(@as(i32, 2), info_array.Array.len); - expect(info_array.Array.child.* == .Int); + try expect(info_array == .Array); + try expectEqual(@as(i32, 2), info_array.Array.len); + try expect(info_array.Array.child.* == .Int); } test "Runtime TypeInfo.Struct" { @@ -817,21 +975,21 @@ test "Runtime TypeInfo.Struct" { }; var info_struct = TypeInfo.init(FooStruct); - expect(info_struct == .Struct); - expect(info_struct.Struct.layout == .Auto); - expectEqual(@as(usize, 1), info_struct.Struct.fields.len); - expectEqualStrings("int", info_struct.Struct.fields[0].name); - expect(info_struct.Struct.fields[0].field_type.* == .Int); + try expect(info_struct == .Struct); + try expect(info_struct.Struct.layout == .Auto); + try expectEqual(@as(usize, 1), info_struct.Struct.fields.len); + try expectEqualStrings("int", info_struct.Struct.fields[0].name); + try expect(info_struct.Struct.fields[0].field_type.* == .Int); } test "Runtime TypeInfo.ComptimeFloat" { var info_comptime_float = TypeInfo.init(comptime_float); - expect(info_comptime_float == .ComptimeFloat); + try expect(info_comptime_float == .ComptimeFloat); } test "Runtime TypeInfo.ComptimeInt" { var info_comptime_int = TypeInfo.init(comptime_int); - expect(info_comptime_int == .ComptimeInt); + try expect(info_comptime_int == .ComptimeInt); } // // TODO .Undefined @@ -839,43 +997,37 @@ test "Runtime TypeInfo.ComptimeInt" { test "Runtime TypeInfo.Optional" { var info_optional = TypeInfo.init(?i32); - expect(info_optional == .Optional); - expect(info_optional.Optional.child.* == .Int); + try expect(info_optional == .Optional); + try expect(info_optional.Optional.child.* == .Int); } // // TODO .ErrorUnion // // TODO .ErrorSet test "Runtime TypeInfo.Enum" { - const FooEnum = enum { - Foo, Bar - }; + const FooEnum = enum { Foo, Bar }; var info_enum = TypeInfo.init(FooEnum); - expect(info_enum == .Enum); + try expect(info_enum == .Enum); } test "Runtime TypeInfo.Union" { - const FooUnion = union { - Foo: void, Bar: i32 - }; + const FooUnion = union { Foo: void, Bar: i32 }; var info_union = TypeInfo.init(FooUnion); - expect(info_union == .Union); + try expect(info_union == .Union); } test "Runtime TypeInfo.Fn" { // .Fn var info_fn = TypeInfo.init(fn () void); - expect(info_fn == .Fn); + try expect(info_fn == .Fn); } test "Runtime TypeInfo.Struct declarations" { // .Fn var info_fn = TypeInfo.init(struct { - const WackType = packed struct { - mr_field: *LameType, ola: u8 - }; + const WackType = packed struct { mr_field: *LameType, ola: u8 }; const LameType = struct { blah: **WackType, @@ -885,7 +1037,7 @@ test "Runtime TypeInfo.Struct declarations" { return one == 1; } }); - expect(info_fn == .Struct); + try expect(info_fn == .Struct); } // TODO .BoundFn From 3825a4df4ac6336be2d54cc24af762c551d181ea Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Mon, 9 Jan 2023 12:22:58 -0300 Subject: [PATCH 11/13] init refactoring --- .gitignore | 2 +- README.md | 2 +- build.zig | 2 +- src/deps_graph.zig | 5 +- src/example/exports.zig | 7 ++- src/example/main.zig | 2 +- src/generators/c.zig | 16 +++--- src/generators/ordered.zig | 21 ++++---- src/generators/python.zig | 11 ++-- src/header_gen.zig | 7 ++- src/runtime.zig | 100 +++++++++++++++++++------------------ 11 files changed, 93 insertions(+), 82 deletions(-) diff --git a/.gitignore b/.gitignore index acd2c4a..541e1b4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ *.swp -zig-cache/ +zig-* headers/ diff --git a/README.md b/README.md index 19e2f08..4358683 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ const std = @import("std"); export fn print_msg(msg_ptr: ?[*]const u8, len: usize) bool { if (msg_ptr) |raw_msg| { const msg = raw_msg[0 .. len - 1]; - std.debug.warn("Msg is: {}", .{msg}); + std.debug.print("Msg is: {}", .{msg}); return true; } return false; diff --git a/build.zig b/build.zig index 9582d94..6e0b60b 100644 --- a/build.zig +++ b/build.zig @@ -1,7 +1,7 @@ const Builder = @import("std").build.Builder; const std = @import("std"); -const warn = std.debug.warn; +const warn = std.debug.print; // This build.zig is only used as an example of using header_gen diff --git a/src/deps_graph.zig b/src/deps_graph.zig index acbf610..e3dece3 100644 --- a/src/deps_graph.zig +++ b/src/deps_graph.zig @@ -177,7 +177,7 @@ pub fn DepsGraph(comptime T: type) type { if (self.dependants_of.getEntry(symbol.name)) |kv| { for (kv.value_ptr.items) |dependant| { - if (dependant.removeDependency(symbol.name)) |dep| { + if (dependant.removeDependency(symbol.name)) |_| { const unblock_dep = (!dependant.emitted and !dependant.hasDependenciesOfType(.Linear)) or !dependant.hasDependencies(); if (!unblock_dep) continue; @@ -257,6 +257,7 @@ pub fn DepsGraph(comptime T: type) type { } pub fn deinit(self: *Symbol, allocator: *Allocator) void { + _ = allocator; self.dependencies.deinit(); } @@ -273,6 +274,7 @@ pub fn DepsGraph(comptime T: type) type { } pub fn removeDependency(self: *Symbol, dependency_name: []const u8) ?Dependency { + _ = dependency_name; var maybe_dep_index: ?usize = null; for (self.dependencies.items) |dependency, i| { @@ -293,6 +295,7 @@ pub fn DepsGraph(comptime T: type) type { } pub fn getDependency(self: *Symbol, dependency_name: []const u8) ?Dependency { + _ = dependency_name; for (self.dependencies.items) |dependency| { if (dependency.eqlName(dependency)) { return dependency; diff --git a/src/example/exports.zig b/src/example/exports.zig index 4738210..72af2d1 100644 --- a/src/example/exports.zig +++ b/src/example/exports.zig @@ -1,10 +1,13 @@ const header_gen = @import("header_gen"); export fn thing(one: usize, two: *LameType, three: [*]u16) bool { + _ = three; + _ = two; return one == 1; } export fn break_point(v: [*]u8) callconv(.Naked) void { + _ = v; @breakpoint(); } @@ -25,7 +28,7 @@ const ThisWillBeVoid = struct { a: u64, }; -const LookMaAnEnum = extern enum { +const LookMaAnEnum = enum(c_int) { one = 1, three = 3, four, @@ -33,7 +36,7 @@ const LookMaAnEnum = extern enum { }; pub fn main () void { - const gen = header_gen.HeaderGen(@This(), "lib").init(); + comptime var gen = header_gen.HeaderGen(@This(), "lib").init(); gen.exec(header_gen.C_Generator); gen.exec(header_gen.Ordered_Generator(header_gen.Python_Generator)); diff --git a/src/example/main.zig b/src/example/main.zig index c6a70af..7c1f53d 100644 --- a/src/example/main.zig +++ b/src/example/main.zig @@ -1,5 +1,5 @@ const std = @import("std"); pub fn main() anyerror!void { - std.debug.warn("All your codebase are belong to us.\n", .{}); + std.debug.print("All your codebase are belong to us.\n", .{}); } diff --git a/src/generators/c.zig b/src/generators/c.zig index eaeaa83..6f22e4b 100644 --- a/src/generators/c.zig +++ b/src/generators/c.zig @@ -1,11 +1,11 @@ const std = @import("std"); const Dir = std.fs.Dir; -const FnMeta = std.builtin.TypeInfo.Fn; -const FnDecl = std.builtin.TypeInfo.Declaration.Data.FnDecl; -const StructMeta = std.builtin.TypeInfo.Struct; -const EnumMeta = std.builtin.TypeInfo.Enum; -const UnionMeta = std.builtin.TypeInfo.Union; -const warn = std.debug.warn; +const FnMeta = std.builtin.Type.Fn; +const FnDecl = std.builtin.Type.Declaration.Data.FnDecl; +const StructMeta = std.builtin.Type.Struct; +const EnumMeta = std.builtin.Type.Enum; +const UnionMeta = std.builtin.Type.Union; +const warn = std.debug.print; pub const C_Generator = struct { file: std.fs.File, @@ -13,8 +13,8 @@ pub const C_Generator = struct { const Self = @This(); pub fn init(comptime src_file: []const u8, dst_dir: *Dir) Self { - comptime const filebaseext = std.fs.path.basename(src_file); - comptime const filebase = filebaseext[0 .. filebaseext.len - 4]; + const filebaseext = std.fs.path.basename(src_file); + const filebase = filebaseext[0 .. filebaseext.len - 4]; var file = dst_dir.createFile(filebase ++ ".h", .{}) catch @panic("Failed to create header file for source: " ++ src_file); diff --git a/src/generators/ordered.zig b/src/generators/ordered.zig index e212c5d..e45862c 100644 --- a/src/generators/ordered.zig +++ b/src/generators/ordered.zig @@ -1,11 +1,11 @@ const std = @import("std"); const StringHashMap = std.StringHashMap; const Allocator = std.mem.Allocator; -const FnMeta = std.builtin.TypeInfo.Fn; -const FnDecl = std.builtin.TypeInfo.Declaration.Data.FnDecl; -const StructMeta = std.builtin.TypeInfo.Struct; -const EnumMeta = std.builtin.TypeInfo.Enum; -const UnionMeta = std.builtin.TypeInfo.Union; +const FnMeta = std.builtin.Type.Fn; +const FnDecl = std.builtin.Type.Declaration.Data.FnDecl; +const StructMeta = std.builtin.Type.Struct; +const EnumMeta = std.builtin.Type.Enum; +const UnionMeta = std.builtin.Type.Union; const Dir = std.fs.Dir; const DepsGraph = @import("../deps_graph.zig").DepsGraph; const rt = @import("../runtime.zig"); @@ -38,7 +38,7 @@ fn isSymbolDependency(comptime symbol_type: type) bool { } fn getTypeName(comptime T: type) []const u8 { - comptime const type_info = @typeInfo(T); + const type_info = @typeInfo(T); return switch (type_info) { .Pointer => |p| getTypeName(p.child), @@ -104,6 +104,7 @@ pub fn Ordered_Generator(comptime Generator: type) type { fn flush(self: *Self) void { while (self.symbols.readEmitted()) |emitted| { const partial = if (emitted.symbol.payload == .Fn) false else emitted.partial; + _ = partial; var phase = self.getNextPhaseFor(emitted.symbol.name, emitted.partial) catch unreachable orelse continue; @@ -117,7 +118,7 @@ pub fn Ordered_Generator(comptime Generator: type) type { } pub fn gen_func(self: *Self, comptime name: []const u8, comptime meta: FnMeta) void { - comptime const decl: SymbolDeclaration = SymbolDeclaration{ + const decl: SymbolDeclaration = SymbolDeclaration{ .Fn = rt.TypeInfo.Fn.init(meta), }; @@ -138,7 +139,7 @@ pub fn Ordered_Generator(comptime Generator: type) type { } pub fn gen_struct(self: *Self, comptime name: []const u8, comptime meta: StructMeta) void { - comptime const decl: SymbolDeclaration = SymbolDeclaration{ + const decl: SymbolDeclaration = SymbolDeclaration{ .Struct = rt.TypeInfo.Struct.init(meta, name), }; @@ -154,7 +155,7 @@ pub fn Ordered_Generator(comptime Generator: type) type { } pub fn gen_enum(self: *Self, comptime name: []const u8, comptime meta: EnumMeta) void { - comptime const decl: SymbolDeclaration = SymbolDeclaration{ + const decl: SymbolDeclaration = SymbolDeclaration{ .Enum = rt.TypeInfo.Enum.init(meta, name), }; @@ -166,7 +167,7 @@ pub fn Ordered_Generator(comptime Generator: type) type { } pub fn gen_union(self: *Self, comptime name: []const u8, comptime meta: UnionMeta) void { - comptime const decl: SymbolDeclaration = SymbolDeclaration{ + const decl: SymbolDeclaration = SymbolDeclaration{ .Union = rt.TypeInfo.Union.init(meta, name), }; diff --git a/src/generators/python.zig b/src/generators/python.zig index e181acc..c3d9ceb 100644 --- a/src/generators/python.zig +++ b/src/generators/python.zig @@ -1,6 +1,6 @@ const std = @import("std"); const Dir = std.fs.Dir; -const warn = std.debug.warn; +const warn = std.debug.print; const rt = @import("../runtime.zig"); const FnDecl = rt.TypeInfo.Declaration.Data.FnDecl; const FnMeta = rt.TypeInfo.Fn; @@ -17,9 +17,9 @@ pub const Python_Generator = struct { const Self = @This(); pub fn init(comptime src_file: []const u8, dst_dir: *Dir) Self { - comptime const filebaseext = std.fs.path.basename(src_file); + const filebaseext = std.fs.path.basename(src_file); // The .len - 4 assumes a .zig extension - comptime const filebase = filebaseext[0 .. filebaseext.len - 4]; + const filebase = filebaseext[0 .. filebaseext.len - 4]; var file = dst_dir.createFile(filebase ++ ".py", .{}) catch @panic("Failed to create header file for source: " ++ src_file); @@ -68,7 +68,7 @@ pub const Python_Generator = struct { } pub fn _gen_fields(self: *Self, name: []const u8, fields: anytype, phase: SymbolPhase) void { - comptime const prefix = "\t "; + const prefix = "\t "; if (phase == .Body) { self.print("{}._fields_ = [", .{name}); @@ -114,9 +114,10 @@ pub const Python_Generator = struct { } pub fn gen_enum(self: *Self, name: []const u8, meta: EnumMeta, phase: SymbolPhase) void { + _ = phase; self.print("class {}(enum.IntEnum):\n", .{name}); - for (meta.fields) |field, i| { + for (meta.fields) |field| { self.write("\t"); self.writeScreamingSnakeCase(field.name); self.print(" = {}\n", .{field.value}); diff --git a/src/header_gen.zig b/src/header_gen.zig index 89047f1..b5885bf 100644 --- a/src/header_gen.zig +++ b/src/header_gen.zig @@ -1,8 +1,8 @@ const std = @import("std"); const builtin = std.builtin; -const TypeInfo = builtin.TypeInfo; +const TypeInfo = builtin.Type; const Declaration = TypeInfo.Declaration; -const warn = std.debug.warn; +const warn = std.debug.print; // Provided generators pub const C_Generator = @import("generators/c.zig").C_Generator; @@ -18,7 +18,6 @@ const GeneratorInterface = struct { fn gen_union() void {} }; - fn includeSymbol(comptime decl: Declaration) bool { if (decl.data == .Type) { const T = decl.data.Type; @@ -28,7 +27,7 @@ fn includeSymbol(comptime decl: Declaration) bool { .Struct => |s| s.layout == .Extern or s.layout == .Packed, .Union => |u| u.layout == .Extern, .Enum => |e| e.layout == .Extern, - else => false + else => false, }; } diff --git a/src/runtime.zig b/src/runtime.zig index eb5302b..7443686 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -1,7 +1,7 @@ const std = @import("std"); const Allocator = std.mem.Allocator; -pub const TypeId = @TagType(TypeInfo); +pub const TypeId = std.builtin.TypeId(TypeInfo); const TypeInfoSingleton = struct { resolved: bool = false, @@ -41,7 +41,7 @@ pub const TypeInfo = union(enum) { signedness: Signedness, bits: i32, - pub fn init(comptime m: std.builtin.TypeInfo.Int) Int { + pub fn init(comptime m: std.builtin.Type.Int) Int { return comptime .{ .signedness = @intToEnum(Signedness, @enumToInt(m.signedness)), .bits = m.bits, @@ -49,7 +49,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(Int, std.builtin.TypeInfo.Int, .{}); + validateSymbolInSync(Int, std.builtin.Type.Int, .{}); } /// This data structure is used by the Zig language code generation and @@ -57,14 +57,14 @@ pub const TypeInfo = union(enum) { pub const Float = struct { bits: i32, - pub fn init(comptime m: std.builtin.TypeInfo.Float) Float { + pub fn init(comptime m: std.builtin.Type.Float) Float { return comptime .{ .bits = m.bits, }; } }; comptime { - validateSymbolInSync(Float, std.builtin.TypeInfo.Float, .{}); + validateSymbolInSync(Float, std.builtin.Type.Float, .{}); } /// This data structure is used by the Zig language code generation and @@ -90,7 +90,7 @@ pub const TypeInfo = union(enum) { C, }; - pub fn init(comptime m: std.builtin.TypeInfo.Pointer) Pointer { + pub fn init(comptime m: std.builtin.Type.Pointer) Pointer { return comptime .{ .size = @intToEnum(TypeInfo.Pointer.Size, @enumToInt(m.size)), .is_const = m.is_const, @@ -108,7 +108,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(Pointer, std.builtin.TypeInfo.Pointer, .{ + validateSymbolInSync(Pointer, std.builtin.Type.Pointer, .{ .ignore_fields = .{"sentinel"}, }); } @@ -123,7 +123,7 @@ pub const TypeInfo = union(enum) { /// the value of the `child` field in this struct. However there is no way /// to refer to that type here, so we use `var`. // sentinel: anytype, - pub fn init(comptime m: std.builtin.TypeInfo.Array) Array { + pub fn init(comptime m: std.builtin.Type.Array) Array { return comptime .{ .len = m.len, .child = &TypeInfo.init(m.child), @@ -137,7 +137,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(Array, std.builtin.TypeInfo.Array, .{ + validateSymbolInSync(Array, std.builtin.Type.Array, .{ .ignore_fields = .{"sentinel"}, }); } @@ -150,7 +150,7 @@ pub const TypeInfo = union(enum) { Packed, }; comptime { - validateSymbolInSync(ContainerLayout, std.builtin.TypeInfo.ContainerLayout, .{}); + validateSymbolInSync(ContainerLayout, std.builtin.Type.ContainerLayout, .{}); } /// This data structure is used by the Zig language code generation and @@ -162,7 +162,7 @@ pub const TypeInfo = union(enum) { is_comptime: bool, alignment: i32, - pub fn init(comptime f: std.builtin.TypeInfo.StructField) StructField { + pub fn init(comptime f: std.builtin.Type.StructField) StructField { return comptime .{ .name = f.name, .field_type = &TypeInfo.init(f.field_type), @@ -180,7 +180,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(StructField, std.builtin.TypeInfo.StructField, .{ + validateSymbolInSync(StructField, std.builtin.Type.StructField, .{ .ignore_fields = .{"default_value"}, }); } @@ -196,7 +196,7 @@ pub const TypeInfo = union(enum) { decls: []const Declaration, is_tuple: bool, - pub fn init(comptime m: std.builtin.TypeInfo.Struct, comptime name: []const u8) Struct { + pub fn init(comptime m: std.builtin.Type.Struct, comptime name: []const u8) Struct { return comptime .{ .name = name, .layout = @intToEnum(TypeInfo.ContainerLayout, @enumToInt(m.layout)), @@ -222,7 +222,7 @@ pub const TypeInfo = union(enum) { }; } comptime { - validateSymbolInSync(Struct, std.builtin.TypeInfo.Struct, .{}); + validateSymbolInSync(Struct, std.builtin.Type.Struct, .{}); } pub fn deinit(self: *const Struct, allocator: *Allocator) void { @@ -239,7 +239,7 @@ pub const TypeInfo = union(enum) { pub const Optional = struct { child: *const TypeInfo, - pub fn init(comptime m: std.builtin.TypeInfo.Optional) Optional { + pub fn init(comptime m: std.builtin.Type.Optional) Optional { return comptime .{ .child = &TypeInfo.init(m.child), }; @@ -252,7 +252,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(Optional, std.builtin.TypeInfo.Optional, .{}); + validateSymbolInSync(Optional, std.builtin.Type.Optional, .{}); } /// This data structure is used by the Zig language code generation and @@ -261,7 +261,7 @@ pub const TypeInfo = union(enum) { error_set: *const TypeInfo, payload: *const TypeInfo, - pub fn init(comptime m: std.builtin.TypeInfo.ErrorUnion) ErrorUnion { + pub fn init(comptime m: std.builtin.Type.ErrorUnion) ErrorUnion { return comptime .{ .error_set = &TypeInfo.init(m.error_set), .payload = &TypeInfo.init(m.payload), @@ -277,7 +277,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(ErrorUnion, std.builtin.TypeInfo.ErrorUnion, .{}); + validateSymbolInSync(ErrorUnion, std.builtin.Type.ErrorUnion, .{}); } /// This data structure is used by the Zig language code generation and @@ -290,7 +290,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(Error, std.builtin.TypeInfo.Error, .{}); + validateSymbolInSync(Error, std.builtin.Type.Error, .{}); } /// This data structure is used by the Zig language code generation and @@ -303,7 +303,7 @@ pub const TypeInfo = union(enum) { name: []const u8, value: i32, - pub fn init(comptime f: std.builtin.TypeInfo.EnumField) EnumField { + pub fn init(comptime f: std.builtin.Type.EnumField) EnumField { return comptime .{ .name = f.name, .value = f.value, @@ -315,7 +315,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(EnumField, std.builtin.TypeInfo.EnumField, .{}); + validateSymbolInSync(EnumField, std.builtin.Type.EnumField, .{}); } /// This data structure is used by the Zig language code generation and @@ -330,7 +330,7 @@ pub const TypeInfo = union(enum) { decls: []const Declaration, is_exhaustive: bool, - pub fn init(comptime m: std.builtin.TypeInfo.Enum, comptime name: []const u8) Enum { + pub fn init(comptime m: std.builtin.Type.Enum, comptime name: []const u8) Enum { return comptime .{ .name = name, .layout = @intToEnum(TypeInfo.ContainerLayout, @enumToInt(m.layout)), @@ -369,7 +369,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(Enum, std.builtin.TypeInfo.Enum, .{}); + validateSymbolInSync(Enum, std.builtin.Type.Enum, .{}); } /// This data structure is used by the Zig language code generation and @@ -381,7 +381,7 @@ pub const TypeInfo = union(enum) { field_type: *const TypeInfo, alignment: i32, - pub fn init(comptime f: std.builtin.TypeInfo.UnionField) UnionField { + pub fn init(comptime f: std.builtin.Type.UnionField) UnionField { return comptime .{ .name = f.name, .field_type = &TypeInfo.init(f.field_type), @@ -402,7 +402,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(UnionField, std.builtin.TypeInfo.UnionField, .{}); + validateSymbolInSync(UnionField, std.builtin.Type.UnionField, .{}); } /// This data structure is used by the Zig language code generation and @@ -416,7 +416,7 @@ pub const TypeInfo = union(enum) { fields: []const UnionField, decls: []const Declaration, - pub fn init(comptime m: std.builtin.TypeInfo.Union, comptime name: []const u8) Union { + pub fn init(comptime m: std.builtin.Type.Union, comptime name: []const u8) Union { return comptime .{ .name = name, .layout = @intToEnum(TypeInfo.ContainerLayout, @enumToInt(m.layout)), @@ -457,7 +457,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(Union, std.builtin.TypeInfo.Union, .{}); + validateSymbolInSync(Union, std.builtin.Type.Union, .{}); } /// This data structure is used by the Zig language code generation and @@ -467,7 +467,7 @@ pub const TypeInfo = union(enum) { is_noalias: bool, arg_type: ?*const TypeInfo, - pub fn init(comptime f: std.builtin.TypeInfo.FnArg) FnArg { + pub fn init(comptime f: std.builtin.Type.FnArg) FnArg { return comptime .{ .is_generic = f.is_generic, .is_noalias = f.is_noalias, @@ -484,7 +484,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(FnArg, std.builtin.TypeInfo.FnArg, .{}); + validateSymbolInSync(FnArg, std.builtin.Type.FnArg, .{}); } /// This data structure is used by the Zig language code generation and @@ -497,7 +497,7 @@ pub const TypeInfo = union(enum) { return_type: ?*const TypeInfo, args: []const FnArg, - pub fn init(comptime m: std.builtin.TypeInfo.Fn) Fn { + pub fn init(comptime m: std.builtin.Type.Fn) Fn { return comptime .{ .calling_convention = @intToEnum(CallingConvention, @enumToInt(m.calling_convention)), .alignment = m.alignment, @@ -529,13 +529,13 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(Fn, std.builtin.TypeInfo.Fn, .{}); + validateSymbolInSync(Fn, std.builtin.Type.Fn, .{}); } pub const Opaque = struct { decls: []const Declaration, - pub fn init(comptime m: std.builtin.TypeInfo.Opaque) Opaque { + pub fn init(comptime m: std.builtin.Type.Opaque) Opaque { return comptime .{ .decls = decls: { comptime var arr: [m.decls.len]Declaration = undefined; @@ -550,7 +550,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(Opaque, std.builtin.TypeInfo.Opaque, .{}); + validateSymbolInSync(Opaque, std.builtin.Type.Opaque, .{}); } /// This data structure is used by the Zig language code generation and @@ -559,7 +559,7 @@ pub const TypeInfo = union(enum) { // function: anytype, }; comptime { - validateSymbolInSync(Frame, std.builtin.TypeInfo.Frame, .{ + validateSymbolInSync(Frame, std.builtin.Type.Frame, .{ .ignore_fields = .{"function"}, }); } @@ -569,7 +569,7 @@ pub const TypeInfo = union(enum) { pub const AnyFrame = struct { child: ?*const TypeInfo, - pub fn init(comptime m: std.builtin.TypeInfo.AnyFrame) AnyFrame { + pub fn init(comptime m: std.builtin.Type.AnyFrame) AnyFrame { return comptime .{ .child = if (m.child) |t| &TypeInfo.init(t) else null, }; @@ -584,7 +584,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(AnyFrame, std.builtin.TypeInfo.AnyFrame, .{}); + validateSymbolInSync(AnyFrame, std.builtin.Type.AnyFrame, .{}); } /// This data structure is used by the Zig language code generation and @@ -593,7 +593,7 @@ pub const TypeInfo = union(enum) { len: i32, child: *const TypeInfo, - pub fn init(comptime m: std.builtin.TypeInfo.Vector) Vector { + pub fn init(comptime m: std.builtin.Type.Vector) Vector { return comptime .{ .len = m.len, .child = &TypeInfo.init(m.child), @@ -607,7 +607,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(Vector, std.builtin.TypeInfo.Vector, .{}); + validateSymbolInSync(Vector, std.builtin.Type.Vector, .{}); } /// This data structure is used by the Zig language code generation and @@ -617,7 +617,7 @@ pub const TypeInfo = union(enum) { is_pub: bool, data: Data, - pub fn init(comptime f: std.builtin.TypeInfo.Declaration) Declaration { + pub fn init(comptime f: std.builtin.Type.Declaration) Declaration { return comptime .{ .name = f.name, .is_pub = f.is_pub, @@ -638,7 +638,7 @@ pub const TypeInfo = union(enum) { Var: *const TypeInfo, Fn: FnDecl, - pub fn init(comptime d: std.builtin.TypeInfo.Declaration.Data) Data { + pub fn init(comptime d: std.builtin.Type.Declaration.Data) Data { return comptime switch (d) { .Type => |t| .{ .Type = &TypeInfo.init(t) }, .Var => |t| .{ @@ -660,7 +660,7 @@ pub const TypeInfo = union(enum) { return_type: *const TypeInfo, arg_names: []const []const u8, - pub fn init(comptime t: std.builtin.TypeInfo.Declaration.Data.FnDecl) FnDecl { + pub fn init(comptime t: std.builtin.Type.Declaration.Data.FnDecl) FnDecl { return comptime .{ .fn_type = &TypeInfo.init(t.fn_type), .is_noinline = t.is_noinline, @@ -689,7 +689,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(FnDecl, std.builtin.TypeInfo.Declaration.Data.FnDecl, .{}); + validateSymbolInSync(FnDecl, std.builtin.Type.Declaration.Data.FnDecl, .{}); } pub fn deinit(self: *const Data, allocator: *Allocator) void { @@ -704,24 +704,25 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(Data, std.builtin.TypeInfo.Declaration.Data, .{}); + validateSymbolInSync(Data, std.builtin.Type.Declaration.Data, .{}); } }; comptime { - validateSymbolInSync(Declaration, std.builtin.TypeInfo.Declaration, .{}); + validateSymbolInSync(Declaration, std.builtin.Type.Declaration, .{}); } // Validate the whole TypeInfo sync comptime { @setEvalBranchQuota(2000); - validateSymbolInSync(TypeInfo, std.builtin.TypeInfo, .{}); + validateSymbolInSync(TypeInfo, std.builtin.Type, .{}); } - usingnamespace comptime blk: { + usingnamespace blk: { var uniqueIdCounter: usize = 0; break :blk struct { pub fn uniqueId(comptime T: type) usize { + _ = T; comptime { var id = uniqueIdCounter; @@ -734,6 +735,7 @@ pub const TypeInfo = union(enum) { }; pub fn alloc(comptime T: type) *TypeInfoSingleton { + _ = T; comptime var ptr = TypeInfoSingleton{}; return &ptr; @@ -752,7 +754,7 @@ pub const TypeInfo = union(enum) { ptr.resolved = true; - comptime const info = @typeInfo(T); + const info = @typeInfo(T); ptr.info = comptime switch (info) { .Type => .{ .Type = {} }, @@ -856,7 +858,7 @@ pub fn hasField(comptime T: type, comptime field_name: []const u8) bool { return false; } -/// Function to be run in compile time, responsible for verifying if the +/// Function to be run in compile time, responsible for verifying if the /// structures/enums/unions defined in this file to represent the TypeInfo at /// runtime in sync with the current Zig version's comptime structures/enums/unions pub fn validateSymbolInSync(comptime runtime_type: type, comptime builtin_type: type, comptime options: anytype) void { @@ -1034,6 +1036,8 @@ test "Runtime TypeInfo.Struct declarations" { }; pub fn thing(one: usize, two: *LameType, three: [*]u16) bool { + _ = three; + _ = two; return one == 1; } }); From 3f62391a414a4ee68d57a6f81743b7da9389b1bc Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Mon, 9 Jan 2023 12:46:50 -0300 Subject: [PATCH 12/13] more changes --- src/deps_graph.zig | 10 +++++----- src/generators/c.zig | 11 +++++++---- src/generators/ordered.zig | 4 ++-- src/generators/python.zig | 13 +++++++------ src/header_gen.zig | 16 ++++++++-------- src/runtime.zig | 38 +++++++++++++++++++------------------- 6 files changed, 48 insertions(+), 44 deletions(-) diff --git a/src/deps_graph.zig b/src/deps_graph.zig index e3dece3..03fd0f7 100644 --- a/src/deps_graph.zig +++ b/src/deps_graph.zig @@ -6,7 +6,7 @@ const TailQueue = std.TailQueue; pub fn DepsGraph(comptime T: type) type { return struct { - allocator: *Allocator, + allocator: Allocator, // All the pointers to symbols inside this struct are owned by this struct // More specifically, they sould be freed when removed from the symbols // hash map. And they should only be removed from there when there are @@ -22,7 +22,7 @@ pub fn DepsGraph(comptime T: type) type { const Self = @This(); - pub fn init(allocator: *Allocator) Self { + pub fn init(allocator: Allocator) Self { return .{ .allocator = allocator, .symbols = StringHashMap(*Symbol).init(allocator), @@ -147,7 +147,7 @@ pub fn DepsGraph(comptime T: type) type { pub const EndSymbolError = error{OutOfMemory}; - pub fn createNode(comptime V: type, data: V, allocator: *Allocator) !*TailQueue(V).Node { + pub fn createNode(comptime V: type, data: V, allocator: Allocator) !*TailQueue(V).Node { var node = try allocator.create(TailQueue(V).Node); node.* = .{ .data = data }; return node; @@ -248,7 +248,7 @@ pub fn DepsGraph(comptime T: type) type { emitted: bool = false, payload: T, - pub fn init(allocator: *Allocator, name: []const u8, payload: T) Symbol { + pub fn init(allocator: Allocator, name: []const u8, payload: T) Symbol { return .{ .name = name, .dependencies = ArrayList(Dependency).init(allocator), @@ -256,7 +256,7 @@ pub fn DepsGraph(comptime T: type) type { }; } - pub fn deinit(self: *Symbol, allocator: *Allocator) void { + pub fn deinit(self: *Symbol, allocator: Allocator) void { _ = allocator; self.dependencies.deinit(); } diff --git a/src/generators/c.zig b/src/generators/c.zig index 6f22e4b..3ce6880 100644 --- a/src/generators/c.zig +++ b/src/generators/c.zig @@ -13,21 +13,24 @@ pub const C_Generator = struct { const Self = @This(); pub fn init(comptime src_file: []const u8, dst_dir: *Dir) Self { - const filebaseext = std.fs.path.basename(src_file); - const filebase = filebaseext[0 .. filebaseext.len - 4]; - var file = dst_dir.createFile(filebase ++ ".h", .{}) catch + var file = dst_dir.createFile(comptime filebase(src_file) ++ ".h", .{}) catch @panic("Failed to create header file for source: " ++ src_file); var res = Self{ .file = file }; // write the header's header, lol - res.write("#ifndef _" ++ filebase ++ "_H\n\n#define _" ++ filebase ++ "_H\n"); + res.write("#ifndef _" ++ comptime filebase(src_file) ++ "_H\n\n#define _" ++ filebase(src_file) ++ "_H\n"); res.write("#include \n#include \n#include \n\n"); return res; } + fn filebase(src_file: []const u8) []const u8 { + const filebaseext = std.fs.path.basename(src_file); + return filebaseext[0 .. filebaseext.len - 4]; + } + pub fn deinit(self: *Self) void { self.write("\n#endif\n"); self.file.close(); diff --git a/src/generators/ordered.zig b/src/generators/ordered.zig index e45862c..33f91d9 100644 --- a/src/generators/ordered.zig +++ b/src/generators/ordered.zig @@ -16,7 +16,7 @@ const SymbolDeclaration = union(enum) { Enum: rt.TypeInfo.Enum, Fn: rt.TypeInfo.Fn, - pub fn deinit(self: SymbolDeclaration, allocator: *Allocator) void { + pub fn deinit(self: SymbolDeclaration, allocator: Allocator) void { switch (self) { .Struct => |s| s.deinit(allocator), .Union => |u| u.deinit(allocator), @@ -54,7 +54,7 @@ pub const SymbolPhase = enum { pub fn Ordered_Generator(comptime Generator: type) type { return struct { inner_gen: Generator, - allocator: *Allocator, + allocator: Allocator, symbols: DepsGraph(SymbolDeclaration), emitted_phase: StringHashMap(SymbolPhase), diff --git a/src/generators/python.zig b/src/generators/python.zig index c3d9ceb..4a5ebe0 100644 --- a/src/generators/python.zig +++ b/src/generators/python.zig @@ -17,11 +17,7 @@ pub const Python_Generator = struct { const Self = @This(); pub fn init(comptime src_file: []const u8, dst_dir: *Dir) Self { - const filebaseext = std.fs.path.basename(src_file); - // The .len - 4 assumes a .zig extension - const filebase = filebaseext[0 .. filebaseext.len - 4]; - - var file = dst_dir.createFile(filebase ++ ".py", .{}) catch + var file = dst_dir.createFile(comptime filebase(src_file) ++ ".py", .{}) catch @panic("Failed to create header file for source: " ++ src_file); var res = Self{ .file = file }; @@ -32,11 +28,16 @@ pub const Python_Generator = struct { \\ ); - res.write("lib = ctypes.cdll.LoadLibrary(\"" ++ filebase ++ ".dll\")\n\n"); + res.write("lib = ctypes.cdll.LoadLibrary(\"" ++ comptime filebase(src_file) ++ ".dll\")\n\n"); return res; } + fn filebase(src_file: []const u8) []const u8 { + const filebaseext = std.fs.path.basename(src_file); + return filebaseext[0 .. filebaseext.len - 4]; + } + pub fn deinit(self: *Self) void { self.file.close(); } diff --git a/src/header_gen.zig b/src/header_gen.zig index b5885bf..c3f9fb4 100644 --- a/src/header_gen.zig +++ b/src/header_gen.zig @@ -80,8 +80,8 @@ pub fn HeaderGen(comptime S: type, comptime libname: []const u8) type { // iterate exported enums // do this first in case target lang needs enums defined before use inline for (self.decls) |decl| { - if (decl.data == .Type) { - const T = decl.data.Type; + if (@typeInfo(S) == .Type) { + const T = S; const info = @typeInfo(T); if (info == .Enum) { const layout = info.Enum.layout; @@ -94,8 +94,8 @@ pub fn HeaderGen(comptime S: type, comptime libname: []const u8) type { // iterate exported structs inline for (self.decls) |decl| { - if (decl.data == .Type) { - const T = decl.data.Type; + if (@typeInfo(S) == .Type) { + const T = S; const info = @typeInfo(T); if (info == .Struct) { const layout = info.Struct.layout; @@ -107,7 +107,7 @@ pub fn HeaderGen(comptime S: type, comptime libname: []const u8) type { } inline for (self.decls) |decl| { - if (decl.data == .Type) { + if (@typeInfo(S) == .Type) { const T = decl.data.Type; const info = @typeInfo(T); if (info == .Union) { @@ -121,15 +121,15 @@ pub fn HeaderGen(comptime S: type, comptime libname: []const u8) type { // iterate exported fns inline for (self.decls) |decl| { - if (decl.data == .Fn) { + if (@typeInfo(S) == .Fn) { const func = decl.data.Fn; if (func.is_export) { //TODO: Look into parsing file for argument names const fn_meta = @typeInfo(func.fn_type).Fn; gen.gen_func(decl.name, fn_meta); } - } else if (decl.data == .Var) { - const fn_meta = @typeInfo(decl.data.Var); + } else if (@typeInfo(S) == .Type) { + const fn_meta = @typeInfo(decl.data.Type); if (fn_meta == .Fn) { gen.gen_func(decl.name, fn_meta.Fn); diff --git a/src/runtime.zig b/src/runtime.zig index 7443686..c49ce6a 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -101,7 +101,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const Pointer, allocator: *Allocator) void { + pub fn deinit(self: *const Pointer, allocator: Allocator) void { self.child.deinit(allocator); allocator.destroy(self.child); @@ -130,7 +130,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const Array, allocator: *Allocator) void { + pub fn deinit(self: *const Array, allocator: Allocator) void { self.child.deinit(allocator); allocator.destroy(self.child); @@ -171,7 +171,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const StructField, allocator: *Allocator) void { + pub fn deinit(self: *const StructField, allocator: Allocator) void { allocator.free(self.name); self.field_type.deinit(allocator); @@ -225,7 +225,7 @@ pub const TypeInfo = union(enum) { validateSymbolInSync(Struct, std.builtin.Type.Struct, .{}); } - pub fn deinit(self: *const Struct, allocator: *Allocator) void { + pub fn deinit(self: *const Struct, allocator: Allocator) void { for (self.fields) |f| f.deinit(allocator); for (self.decls) |f| f.deinit(allocator); @@ -245,7 +245,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const Optional, allocator: *Allocator) void { + pub fn deinit(self: *const Optional, allocator: Allocator) void { self.child.deinit(allocator); allocator.destroy(self.child); @@ -268,7 +268,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const ErrorUnion, allocator: *Allocator) void { + pub fn deinit(self: *const ErrorUnion, allocator: Allocator) void { self.error_set.deinit(allocator); allocator.destroy(self.error_set); @@ -285,7 +285,7 @@ pub const TypeInfo = union(enum) { pub const Error = struct { name: []const u8, - pub fn deinit(self: *const Error, allocator: *Allocator) void { + pub fn deinit(self: *const Error, allocator: Allocator) void { allocator.free(self.name); } }; @@ -310,7 +310,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const EnumField, allocator: *Allocator) void { + pub fn deinit(self: *const EnumField, allocator: Allocator) void { allocator.free(self.name); } }; @@ -357,7 +357,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const Enum, allocator: *Allocator) void { + pub fn deinit(self: *const Enum, allocator: Allocator) void { for (self.fields) |f| f.deinit(allocator); for (self.decls) |f| f.deinit(allocator); @@ -389,7 +389,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const UnionField, allocator: *Allocator) void { + pub fn deinit(self: *const UnionField, allocator: Allocator) void { allocator.free(self.name); self.field_type.deinit(allocator); @@ -442,7 +442,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const Union, allocator: *Allocator) void { + pub fn deinit(self: *const Union, allocator: Allocator) void { for (self.fields) |f| f.deinit(allocator); for (self.decls) |f| f.deinit(allocator); @@ -475,7 +475,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const FnArg, allocator: *Allocator) void { + pub fn deinit(self: *const FnArg, allocator: Allocator) void { if (self.arg_type) |t| { t.deinit(allocator); @@ -516,7 +516,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const Fn, allocator: *Allocator) void { + pub fn deinit(self: *const Fn, allocator: Allocator) void { if (self.return_type) |r| { r.deinit(allocator); @@ -575,7 +575,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const AnyFrame, allocator: *Allocator) void { + pub fn deinit(self: *const AnyFrame, allocator: Allocator) void { if (self.child) |child| { child.deinit(allocator); @@ -600,7 +600,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const Vector, allocator: *Allocator) void { + pub fn deinit(self: *const Vector, allocator: Allocator) void { self.child.deinit(allocator); allocator.destroy(self.child); @@ -625,7 +625,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const Declaration, allocator: *Allocator) void { + pub fn deinit(self: *const Declaration, allocator: Allocator) void { self.data.deinit(allocator); allocator.free(self.name); @@ -673,7 +673,7 @@ pub const TypeInfo = union(enum) { }; } - pub fn deinit(self: *const FnDecl, allocator: *Allocator) void { + pub fn deinit(self: *const FnDecl, allocator: Allocator) void { self.fn_type.deinit(allocator); self.return_type.deinit(allocator); @@ -692,7 +692,7 @@ pub const TypeInfo = union(enum) { validateSymbolInSync(FnDecl, std.builtin.Type.Declaration.Data.FnDecl, .{}); } - pub fn deinit(self: *const Data, allocator: *Allocator) void { + pub fn deinit(self: *const Data, allocator: Allocator) void { switch (self.*) { .Type, .Var => |t| { t.deinit(allocator); @@ -801,7 +801,7 @@ pub const TypeInfo = union(enum) { return &ptr.info; } - pub fn deinit(self: *TypeInfo, allocator: *Allocator) void { + pub fn deinit(self: *TypeInfo, allocator: Allocator) void { switch (self.*) { .Array => |a| a.deinit(allocator), .Pointer => |p| p.deinit(allocator), From b8e0a2de77cbf4c065b8afcce594faeb04704a0c Mon Sep 17 00:00:00 2001 From: Matheus Catarino Date: Mon, 9 Jan 2023 13:24:51 -0300 Subject: [PATCH 13/13] remove DataType --- src/generators/c.zig | 6 +-- src/generators/ordered.zig | 10 ++-- src/generators/python.zig | 22 ++++---- src/runtime.zig | 105 ++++++------------------------------- 4 files changed, 35 insertions(+), 108 deletions(-) diff --git a/src/generators/c.zig b/src/generators/c.zig index 3ce6880..bdeb428 100644 --- a/src/generators/c.zig +++ b/src/generators/c.zig @@ -48,11 +48,11 @@ pub const C_Generator = struct { self.writeType(meta.return_type.?); self.write(" " ++ name ++ "("); - inline for (meta.args) |arg, i| { - self.writeType(arg.arg_type.?); + inline for (meta.params) |arg, i| { + self.writeType(arg.type.?); //TODO: Figure out how to get arg names; for now just do arg0..argN _ = self.file.writer().print(" arg{}", .{i}) catch unreachable; - if (i != meta.args.len - 1) + if (i != meta.params.len - 1) self.write(", "); } diff --git a/src/generators/ordered.zig b/src/generators/ordered.zig index 33f91d9..c37f30a 100644 --- a/src/generators/ordered.zig +++ b/src/generators/ordered.zig @@ -85,14 +85,14 @@ pub fn Ordered_Generator(comptime Generator: type) type { var result = try self.emitted_phase.getOrPut(symbol_name); if (!result.found_existing) { - result.entry.value = if (partial) .Signature else .Full; + result.value_ptr.* = if (partial) .Signature else .Full; - return result.entry.value; - } else if (result.entry.value == .Signature) { + return result.value_ptr.*; + } else if (result.value_ptr.* == .Signature) { if (partial) { return null; } else { - result.entry.value = .Full; + result.value_ptr.* = .Full; return .Body; } @@ -123,7 +123,7 @@ pub fn Ordered_Generator(comptime Generator: type) type { }; self.symbols.beginSymbol(name, decl) catch |err| @panic(@errorName(err)); - inline for (meta.args) |f| { + inline for (meta.params) |f| { if (f.arg_type != null and comptime isSymbolDependency(f.arg_type.?)) { self.symbols.addDependency(getTypeName(f.arg_type.?)) catch |err| @panic(@errorName(err)); } diff --git a/src/generators/python.zig b/src/generators/python.zig index 4a5ebe0..667f12a 100644 --- a/src/generators/python.zig +++ b/src/generators/python.zig @@ -43,23 +43,23 @@ pub const Python_Generator = struct { } pub fn gen_func(self: *Self, name: []const u8, meta: FnMeta) void { - self.print("lib.{}.argtypes = [", .{name}); + self.print("lib.{s}.argtypes = [", .{name}); - for (meta.args) |arg, i| { - if (arg.arg_type) |t| { + for (meta.params) |arg, i| { + if (arg.type) |t| { self.writeType(t.*); } else { self.write("None"); } - if (i != meta.args.len - 1) { + if (i != meta.params.len - 1) { self.write(", "); } } self.write("]\n"); - self.print("lib.{}.restype = ", .{name}); + self.print("lib.{s}.restype = ", .{name}); if (meta.return_type) |return_type| { self.writeType(return_type.*); } else { @@ -72,7 +72,7 @@ pub const Python_Generator = struct { const prefix = "\t "; if (phase == .Body) { - self.print("{}._fields_ = [", .{name}); + self.print("{s}._fields_ = [", .{name}); } else { self.write("\t_fields_ = ["); } @@ -82,7 +82,7 @@ pub const Python_Generator = struct { self.write(prefix); } - self.print("(\"{}\", ", .{field.name}); + self.print("(\"{s}\", ", .{field.name}); self.writeType(field.field_type.*); @@ -98,7 +98,7 @@ pub const Python_Generator = struct { pub fn gen_struct(self: *Self, name: []const u8, meta: StructMeta, phase: SymbolPhase) void { if (phase != .Body) { - self.print("class {}(ctypes.Structure):\n", .{name}); + self.print("class {s}(ctypes.Structure):\n", .{name}); if (meta.layout == .Packed) { self.write("\t_pack_ = 1\n"); @@ -116,7 +116,7 @@ pub const Python_Generator = struct { pub fn gen_enum(self: *Self, name: []const u8, meta: EnumMeta, phase: SymbolPhase) void { _ = phase; - self.print("class {}(enum.IntEnum):\n", .{name}); + self.print("class {s}(enum.IntEnum):\n", .{name}); for (meta.fields) |field| { self.write("\t"); @@ -133,7 +133,7 @@ pub const Python_Generator = struct { pub fn gen_union(self: *Self, name: []const u8, meta: UnionMeta, phase: SymbolPhase) void { if (phase != .Body) { - self.print("class {}(ctypes.Union):\n", .{name}); + self.print("class {s}(ctypes.Union):\n", .{name}); } if (phase != .Signature) { @@ -152,7 +152,7 @@ pub const Python_Generator = struct { // .usize => self.writeCtype("c_usize"), // TODO // .isize => self.writeCtype("c_isize"), // TODO .Int => |i| { - switch (i.is_signed) { + switch (i.signedness == .signed) { true => self.print("ctypes.c_int{}", .{i.bits}), false => self.print("ctypes.c_uint{}", .{i.bits}), } diff --git a/src/runtime.zig b/src/runtime.zig index c49ce6a..4be9056 100644 --- a/src/runtime.zig +++ b/src/runtime.zig @@ -74,6 +74,7 @@ pub const TypeInfo = union(enum) { is_const: bool, is_volatile: bool, alignment: i32, + address_space: std.builtin.AddressSpace, child: *const TypeInfo, is_allowzero: bool, /// This field is an optional type. @@ -158,7 +159,8 @@ pub const TypeInfo = union(enum) { pub const StructField = struct { name: []const u8, field_type: *const TypeInfo, - // default_value: anytype, + type: ?*const TypeInfo, + default_value: ?*const anyopaque, is_comptime: bool, alignment: i32, @@ -192,6 +194,7 @@ pub const TypeInfo = union(enum) { name: ?[]const u8, layout: ContainerLayout, + backing_integer: ?*const TypeInfo = null, fields: []const StructField, decls: []const Declaration, is_tuple: bool, @@ -377,7 +380,7 @@ pub const TypeInfo = union(enum) { pub const UnionField = struct { // Additional Field name: []const u8, - + type: ?*const TypeInfo, field_type: *const TypeInfo, alignment: i32, @@ -462,20 +465,20 @@ pub const TypeInfo = union(enum) { /// This data structure is used by the Zig language code generation and /// therefore must be kept in sync with the compiler implementation. - pub const FnArg = struct { + pub const Param = struct { is_generic: bool, is_noalias: bool, - arg_type: ?*const TypeInfo, + type: ?*const TypeInfo, - pub fn init(comptime f: std.builtin.Type.FnArg) FnArg { + pub fn init(comptime f: std.builtin.Type.Param) Param { return comptime .{ .is_generic = f.is_generic, .is_noalias = f.is_noalias, - .arg_type = if (f.arg_type) |t| &TypeInfo.init(t) else null, + .type = if (f.type) |t| &TypeInfo.init(t) else null, }; } - pub fn deinit(self: *const FnArg, allocator: Allocator) void { + pub fn deinit(self: *const Param, allocator: Allocator) void { if (self.arg_type) |t| { t.deinit(allocator); @@ -484,7 +487,7 @@ pub const TypeInfo = union(enum) { } }; comptime { - validateSymbolInSync(FnArg, std.builtin.Type.FnArg, .{}); + validateSymbolInSync(Param, std.builtin.Type.Fn.Param, .{}); } /// This data structure is used by the Zig language code generation and @@ -495,7 +498,7 @@ pub const TypeInfo = union(enum) { is_generic: bool, is_var_args: bool, return_type: ?*const TypeInfo, - args: []const FnArg, + params: []const Param, pub fn init(comptime m: std.builtin.Type.Fn) Fn { return comptime .{ @@ -505,10 +508,10 @@ pub const TypeInfo = union(enum) { .is_var_args = m.is_var_args, .return_type = if (m.return_type) |t| &TypeInfo.init(t) else null, .args = args: { - comptime var arr: [m.args.len]FnArg = undefined; + comptime var arr: [m.args.len]Param = undefined; inline for (m.args) |f, i| { - arr[i] = FnArg.init(f); + arr[i] = Param.init(f); } break :args &arr; @@ -615,13 +618,13 @@ pub const TypeInfo = union(enum) { pub const Declaration = struct { name: []const u8, is_pub: bool, - data: Data, + // data: Data, pub fn init(comptime f: std.builtin.Type.Declaration) Declaration { return comptime .{ .name = f.name, .is_pub = f.is_pub, - .data = Data.init(f.data), + // .data = Data.init(f.data), }; } @@ -630,82 +633,6 @@ pub const TypeInfo = union(enum) { allocator.free(self.name); } - - /// This data structure is used by the Zig language code generation and - /// therefore must be kept in sync with the compiler implementation. - pub const Data = union(enum) { - Type: *const TypeInfo, - Var: *const TypeInfo, - Fn: FnDecl, - - pub fn init(comptime d: std.builtin.Type.Declaration.Data) Data { - return comptime switch (d) { - .Type => |t| .{ .Type = &TypeInfo.init(t) }, - .Var => |t| .{ - .Var = &TypeInfo.init(t), - }, - .Fn => |t| .{ .Fn = FnDecl.init(t) }, - }; - } - - /// This data structure is used by the Zig language code generation and - /// therefore must be kept in sync with the compiler implementation. - pub const FnDecl = struct { - fn_type: *const TypeInfo, - is_noinline: bool, - is_var_args: bool, - is_extern: bool, - is_export: bool, - lib_name: ?[]const u8, - return_type: *const TypeInfo, - arg_names: []const []const u8, - - pub fn init(comptime t: std.builtin.Type.Declaration.Data.FnDecl) FnDecl { - return comptime .{ - .fn_type = &TypeInfo.init(t.fn_type), - .is_noinline = t.is_noinline, - .is_var_args = t.is_var_args, - .is_extern = t.is_extern, - .is_export = t.is_export, - .lib_name = t.lib_name, - .return_type = &TypeInfo.init(t.return_type), - .arg_names = t.arg_names, - }; - } - - pub fn deinit(self: *const FnDecl, allocator: Allocator) void { - self.fn_type.deinit(allocator); - self.return_type.deinit(allocator); - - allocator.destroy(self.fn_type); - allocator.destroy(self.return_type); - - for (self.arg_names) |a| allocator.free(a); - allocator.free(self.arg_names); - - if (self.lib_name) |lib_name| { - allocator.free(lib_name); - } - } - }; - comptime { - validateSymbolInSync(FnDecl, std.builtin.Type.Declaration.Data.FnDecl, .{}); - } - - pub fn deinit(self: *const Data, allocator: Allocator) void { - switch (self.*) { - .Type, .Var => |t| { - t.deinit(allocator); - - allocator.destroy(t); - }, - .Fn => |f| f.deinit(allocator), - } - } - }; - comptime { - validateSymbolInSync(Data, std.builtin.Type.Declaration.Data, .{}); - } }; comptime { validateSymbolInSync(Declaration, std.builtin.Type.Declaration, .{});