From 11a1bd09b2ef3b91ed0b738df40347d7600b23f9 Mon Sep 17 00:00:00 2001 From: bgk- Date: Tue, 9 Jul 2024 20:13:45 -0700 Subject: [PATCH] Add extern enum support --- build.zig | 11 ++++++----- build.zig.zon | 2 +- src/compiler.zig | 1 + src/export-value.zig | 9 +++++++++ src/export.zig | 27 +++++++++++++++++++++++++-- src/state.zig | 12 ++++++++---- 6 files changed, 50 insertions(+), 12 deletions(-) diff --git a/build.zig b/build.zig index 934ff33..df5b92f 100644 --- a/build.zig +++ b/build.zig @@ -11,18 +11,19 @@ pub fn build(b: *std.Build) void { const build_options = b.addOptions(); build_options.addOption([]const u8, "version", version); - _ = b.addModule("topi", .{ - .root_source_file = b.path("src/topi.zig"), - }); + _ = b.addModule("topi", .{ + .root_source_file = b.path("src/topi.zig"), + }); - const topidll = b.addSharedLibrary(.{ + const topilib = b.addSharedLibrary(.{ .name = "topi", .root_source_file = b.path("src/export.zig"), .target = target, .optimize = optimize, }); - b.installArtifact(topidll); + const art = b.addInstallArtifact(topilib, .{ .dest_dir = .{ .override = .lib } }); + b.getInstallStep().dependOn(&art.step); const exe = b.addExecutable(.{ .name = "topi", diff --git a/build.zig.zon b/build.zig.zon index 6d18e63..8047d17 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -1,6 +1,6 @@ .{ .name = "topiary", - .version = "0.13.2", + .version = "0.13.3", .paths = .{""}, .dependencies = .{}, } diff --git a/src/compiler.zig b/src/compiler.zig index 86f3844..8670409 100644 --- a/src/compiler.zig +++ b/src/compiler.zig @@ -508,6 +508,7 @@ pub const Compiler = struct { } obj.* = .{ + .id = UUID.fromString(e.name), .data = .{ .@"enum" = .{ .is_seq = e.is_seq, diff --git a/src/export-value.zig b/src/export-value.zig index 96f6ba6..54c2359 100644 --- a/src/export-value.zig +++ b/src/export-value.zig @@ -10,6 +10,7 @@ const Tag = enum(u8) { list, set, map, + enum_value, }; pub const ExportValue = extern struct { @@ -23,6 +24,10 @@ pub const ExportValue = extern struct { items: [*c]ExportValue, count: u16, }, + enum_value: extern struct { + enum_name: [*c]const u8, + value_name: [*c]const u8, + }, }, pub const Nil: ExportValue = .{ .tag = Tag.nil, .data = .{ .nil = {} } }; @@ -33,6 +38,10 @@ pub const ExportValue = extern struct { return switch (value) { .bool => |b| if (b) True else False, .number => |n| .{ .tag = Tag.number, .data = .{ .number = n } }, + .enum_value => |e| .{ .tag = Tag.enum_value, .data = .{ .enum_value = .{ + .enum_name = e.base.data.@"enum".name.ptr, + .value_name = e.base.data.@"enum".values[e.index].ptr, + } } }, .obj => |o| switch (o.data) { // We're mixing memory management here, which is a very bad idea, // Tried passing in a "ExportAllocator" and copying the values to the memory diff --git a/src/export.zig b/src/export.zig index dd92790..e378a4d 100644 --- a/src/export.zig +++ b/src/export.zig @@ -179,9 +179,10 @@ export fn start(vm_ptr: usize, path_ptr: [*]const u8, path_len: usize) void { } export fn run(vm_ptr: usize) void { - log("Running VM", .{}, .info); + log("Running Vm", .{}, .debug); var vm: *Vm = @ptrFromInt(vm_ptr); - vm.run() catch { + vm.run() catch |err| { + log("Vm Error: {s}", .{ @errorName(err) }, .err); if (vm.err.msg) |msg| { log("Error at line {}: {s}", .{ vm.err.line, msg }, .err); } @@ -246,6 +247,28 @@ export fn setExternNumber(vm_ptr: usize, name_ptr: [*c]const u8, name_length: us }; } +export fn setExternEnum(vm_ptr: usize, name_ptr: [*c]const u8, name_length: usize, enum_name_ptr: [*c]const u8, enum_name_length: usize, enum_value_ptr: [*c]const u8, enum_value_length: usize) void { + var vm: *Vm = @ptrFromInt(vm_ptr); + const name = name_ptr[0..name_length]; + const enum_name = enum_name_ptr[0..enum_name_length]; + const enum_value = enum_value_ptr[0..enum_value_length]; + for (vm.bytecode.constants) |c| { + if (c != .obj or c.obj.data != .@"enum") continue; + const e = c.obj.data.@"enum"; + if (!std.mem.eql(u8, e.name, enum_name)) continue; + for (e.values, 0..) |v, i| { + if (!std.mem.eql(u8, v, enum_value)) continue; + vm.setExtern(name, .{ .enum_value = .{ .base = c.obj, .index = @intCast(i) }}) catch |err| { + log("Could not set Export value \"{s}\": {s}", .{ name, @errorName(err) }, .err); + return; + }; + log("Set extern enum \"{s}\" to {s}.{s} ({})", .{ name, enum_name, enum_value, i}, .debug); + return; + } + } + log("Could not set extern enum \"{s}\" {s}.{s}", .{ name, enum_name, enum_value }, .err); +} + export fn setExternBool(vm_ptr: usize, name_ptr: [*c]const u8, name_length: usize, value: bool) void { var vm: *Vm = @ptrFromInt(vm_ptr); const name = name_ptr[0..name_length]; diff --git a/src/state.zig b/src/state.zig index 882809c..3a6d698 100644 --- a/src/state.zig +++ b/src/state.zig @@ -53,12 +53,12 @@ pub const State = struct { if (seen.contains(value.obj.id)) continue; try seen.put(value.obj.id, {}); try stream.objectField(&value.obj.id); - try serializeObj(value, &stream, &references); + try serializeObj(vm.allocator, value, &stream, &references); } try stream.endObject(); } - fn serializeObj(value: Value, stream: anytype, references: *std.ArrayList(Value)) !void { + fn serializeObj(allocator: std.mem.Allocator, value: Value, stream: anytype, references: *std.ArrayList(Value)) !void { try stream.beginObject(); try stream.objectField(@tagName(value.obj.data)); switch (value.obj.data) { @@ -101,7 +101,9 @@ pub const State = struct { try stream.objectField("arity"); try stream.write(f.arity); try stream.objectField("inst"); - try stream.write(&f.instructions); + const buf = try allocator.alloc(u8, std.base64.standard.Encoder.calcSize(f.instructions.len)); + defer allocator.free(buf); + try stream.write(std.base64.standard.Encoder.encode(buf, f.instructions)); try stream.objectField("lines"); try stream.beginArray(); for (f.lines) |l| try stream.write(l); @@ -292,9 +294,11 @@ pub const State = struct { for (lines_items, 0..) |t, i| lines[i] = @intCast(t.integer); const locals = v.object.get("locals_count").?.integer; const is_method = v.object.get("is_method").?.bool; + const inst_alloc = try vm.allocator.alloc(u8, try std.base64.standard.Decoder.calcSizeForSlice(inst)); + try std.base64.standard.Decoder.decode(inst_alloc, inst); var result = try vm.gc.create(vm, .{ .function = .{ .arity = @intCast(arity), - .instructions = try vm.allocator.dupe(u8, inst), + .instructions = inst_alloc, .lines = try vm.allocator.dupe(u32, lines), .locals_count = @intCast(locals), .is_method = is_method,