Skip to content

Commit

Permalink
Refactor enums
Browse files Browse the repository at this point in the history
  • Loading branch information
bgk- committed Feb 27, 2024
1 parent 6ab8199 commit c471e29
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 19 deletions.
29 changes: 14 additions & 15 deletions src/compiler.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
7 changes: 3 additions & 4 deletions src/enum.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
};
53 changes: 53 additions & 0 deletions src/values.zig
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub const Type = enum(u8) {
obj,
map_pair,
visit,
enum_value,
};

pub const Iterator = struct {
Expand All @@ -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,
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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 => {},
}
},
Expand All @@ -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;
Expand Down Expand Up @@ -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,
}
},
Expand All @@ -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}),
Expand Down Expand Up @@ -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)});
},
Expand Down
31 changes: 31 additions & 0 deletions src/vm.test.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down
13 changes: 13 additions & 0 deletions src/vm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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| {
Expand Down

0 comments on commit c471e29

Please sign in to comment.