From c471e2993ffb48bc22a65c8bcaf901d2e22942ec Mon Sep 17 00:00:00 2001 From: bgk- Date: Sun, 25 Feb 2024 21:21:00 -0800 Subject: [PATCH] Refactor enums --- src/compiler.zig | 29 +++++++++++++------------- src/enum.zig | 7 +++---- src/values.zig | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ src/vm.test.zig | 31 ++++++++++++++++++++++++++++ src/vm.zig | 13 ++++++++++++ 5 files changed, 114 insertions(+), 19 deletions(-) diff --git a/src/compiler.zig b/src/compiler.zig index 727a2d9..3da793e 100644 --- a/src/compiler.zig +++ b/src/compiler.zig @@ -408,24 +408,23 @@ pub const Compiler = struct { try self.setSymbol(symbol, token, true); }, .@"enum" => |e| { - var values = std.ArrayList(Enum.Value).init(self.allocator); + var names = std.ArrayList([]const u8).init(self.allocator); + defer names.deinit(); const obj = try self.allocator.create(Value.Obj); - obj.* = .{ .data = .{ - .@"enum" = .{ - .allocator = self.allocator, - .name = try self.allocator.dupe(u8, e.name), - .values = try values.toOwnedSlice(), - }, - } }; - - for (e.values, 0..) |value, i| { - try values.append(.{ - .index = i, - .name = try self.allocator.dupe(u8, value), - .base = &obj.data.@"enum", - }); + for (e.values) |value| { + try names.append(try self.allocator.dupe(u8, value)); } + + obj.* = .{ + .data = .{ + .@"enum" = .{ + .allocator = self.allocator, + .name = try self.allocator.dupe(u8, e.name), + .values = try names.toOwnedSlice(), + }, + }, + }; const i = try self.addConstant(.{ .obj = obj }); try self.writeOp(.constant, token); _ = try self.writeInt(OpCode.Size(.constant), i, token); diff --git a/src/enum.zig b/src/enum.zig index d0d6d75..378c475 100644 --- a/src/enum.zig +++ b/src/enum.zig @@ -3,11 +3,10 @@ const std = @import("std"); pub const Enum = struct { allocator: std.mem.Allocator, name: []const u8, - values: []Value, + values: [][]const u8, pub const Value = struct { - index: usize, - name: []const u8, - base: *Enum, + index: u8, + base: *const Enum, }; }; diff --git a/src/values.zig b/src/values.zig index 00152bd..745ffab 100644 --- a/src/values.zig +++ b/src/values.zig @@ -26,6 +26,7 @@ pub const Type = enum(u8) { obj, map_pair, visit, + enum_value, }; pub const Iterator = struct { @@ -52,6 +53,7 @@ pub const Value = union(Type) { value: *Value, }, visit: u32, + enum_value: Enum.Value, pub const Obj = struct { is_marked: bool = false, @@ -157,6 +159,7 @@ pub const Value = union(Type) { .range => "range", .map_pair => "map_pair", .visit => "visit", + .enum_value => "enum_value", .obj => |o| switch (o.data) { .string => "string", .list => "list", @@ -249,6 +252,10 @@ pub const Value = union(Type) { .visit => |v| { try writer.writeInt(u32, v, .little); }, + .enum_value => |e| { + try writer.writeByte(e.index); + // try writer.writeInt(OpCode.SizeOf(.constant)); + }, .obj => |o| { try writer.writeByte(@intFromEnum(@as(Obj.DataType, o.data))); try writer.writeAll(&o.id); @@ -283,6 +290,15 @@ pub const Value = union(Type) { try writer.writeInt(u16, @as(u16, @intCast(f.lines.len)), .little); for (f.lines) |l| try writer.writeInt(u32, l, .little); }, + .@"enum" => |e| { + try writer.writeByte(@intCast(e.name.len)); + try writer.writeAll(e.name); + try writer.writeByte(@intCast(e.values.len)); + for (e.values) |val| { + try writer.writeByte(@intCast(val.len)); + try writer.writeAll(val); + } + }, else => {}, } }, @@ -305,6 +321,10 @@ pub const Value = union(Type) { .visit => { return .{ .visit = try reader.readInt(u32, .little) }; }, + .enum_value => { + const index = try reader.readByte(); + return .{ .enum_value = .{ .index = index, .base = undefined }}; + }, .obj => { const data_type: Obj.DataType = @enumFromInt(try reader.readByte()); var id: ID = undefined; @@ -378,6 +398,29 @@ pub const Value = union(Type) { } }; return .{ .obj = obj }; }, + .@"enum" => { + const name_length = try reader.readByte(); + const name_buf = try allocator.alloc(u8, name_length); + try reader.readNoEof(name_buf); + const values_length = try reader.readByte(); + const obj = try allocator.create(Value.Obj); + obj.* = .{ + .data = .{ + .@"enum" = .{ + .allocator = allocator, + .name = name_buf, + .values = try allocator.alloc([]const u8, values_length) + } + } + }; + for (0..values_length) |i| { + const value_name_length = try reader.readByte(); + const value_name_buf = try allocator.alloc(u8, value_name_length); + try reader.readNoEof(value_name_buf); + obj.data.@"enum".values[i] = value_name_buf; + } + return .{ .obj = obj }; + }, else => return error.Unknown, } }, @@ -391,6 +434,7 @@ pub const Value = union(Type) { .bool => |b| writer.print("{}", .{b}), .nil => writer.print("nil", .{}), .visit => |v| writer.print("{d}", .{v}), + .enum_value => |e| writer.print("{s}.{s}", .{e.base.name, e.base.values[e.index]}), .obj => |o| { switch (o.data) { .string => |s| writer.print("{s}", .{s}), @@ -449,6 +493,15 @@ pub const Value = union(Type) { } writer.print("}}", .{}); }, + .@"enum" => |e| { + writer.print("{s}{{", .{e.name}); + for(e.values, 0..) |val, i| { + writer.print("{s}", .{val}); + if (i != e.values.len - 1) + writer.print(", ", .{}); + } + writer.print("}}", .{}); + }, else => { writer.print("{s}", .{@tagName(o.data)}); }, diff --git a/src/vm.test.zig b/src/vm.test.zig index f9083ae..369a2c4 100644 --- a/src/vm.test.zig +++ b/src/vm.test.zig @@ -797,6 +797,37 @@ test "Instance" { try vm.interpret(); } +test "Enums" { + const input = + \\ enum TimeOfDay = { + \\ Morning, + \\ Afternoon, + \\ Evening, + \\ Night + \\ } + \\ + \\ switch (5) { + \\ 0..4: print(TimeOfDay.Night), + \\ 5..11: print(TimeOfDay.Morning), + \\ 12..16: print(TimeOfDay.Afternoon), + \\ 16..21: print(TimeOfDay.Evening), + \\ 22..24: print(TimeOfDay.Night), + \\ else: print(TimeOfDay.Morning) + \\ } + \\ + \\ print(timeOfDay(5)) + \\ +; + + var mod = Module.create(allocator); + defer mod.deinit(); + defer mod.entry.source_loaded = false; + var vm = try initTestVm(input, &mod, true); + defer vm.deinit(); + defer vm.bytecode.free(testing.allocator); + try vm.interpret(); +} + test "Boughs" { const test_cases = .{ .{ .input = diff --git a/src/vm.zig b/src/vm.zig index 7d27d26..d0cbc0b 100644 --- a/src/vm.zig +++ b/src/vm.zig @@ -708,6 +708,19 @@ pub const Vm = struct { } } else return self.fail("Unknown field \"{s}\" on instance of {s}.", .{ index.obj.data.string, i.class.name }); }, + .@"enum" => |e| { + if (index != .obj) + return self.fail("Can only query instance fields by string name, not {s}", .{@tagName(index)}); + if (index.obj.data != .string) + return self.fail("Can only query instance fields by string name, not {s}", .{@tagName(index.obj.data)}); + for (e.values, 0..) |name, i| { + if (std.mem.eql(u8, name, index.obj.data.string)) { + try self.push(.{ .enum_value = .{ .index = @intCast(i), .base = &e }}); + continue; + } + } + return self.fail("Unknown value \"{s}\" on enum {s}", .{ index.obj.data.string, e.name }); + }, else => return self.fail("Unknown target type {s} to index. Only lists, maps, sets, or instances can be indexed.", .{@tagName(target)}), }, .map_pair => |mp| {