value.zig (3111B)
1 const std = @import("std"); 2 3 const array = @import("lib::array.zig"); 4 const utils = @import("lib::utils.zig"); 5 6 const Obj = @import("gc.zig").GC.Obj; 7 8 pub const Value = union(enum) { 9 number: f64, 10 char: u8, 11 bool: bool, 12 nil: void, 13 obj: *Obj, 14 15 const Self = @This(); 16 pub const Tag = std.meta.Tag(Self); 17 18 pub fn format(self: Self, writer: *std.Io.Writer) !void { 19 switch (self) { 20 .number => |val| try writer.print("{d}", .{val}), 21 .char => |val| try writer.writeAll(&[_]u8{val}), 22 .bool => |val| try writer.writeAll(if (val) "true" else "false"), 23 .nil => try writer.writeAll("nil"), 24 .obj => |o| switch (o.type) { 25 inline else => |tp| if (@hasDecl(tp.get(), "format")) 26 try (o.cast(tp) catch unreachable).format(writer) 27 else 28 try o.format(writer), 29 }, 30 } 31 } 32 33 pub fn tagNameOf(T: type) []const u8 { 34 return @tagName(utils.tagFromType(Self, T)); 35 } 36 37 pub fn typeName(self: Self) []const u8 { 38 return switch (self) { 39 .obj => |o| @tagName(o.type), 40 inline else => |tp| tagNameOf(@TypeOf(tp)), 41 }; 42 } 43 44 pub fn init(val: anytype) Self { 45 return @unionInit(Self, tagNameOf(@TypeOf(val)), val); 46 } 47 48 fn toTag(comptime from: anytype) Tag { 49 return if (@TypeOf(from) == Obj.Type) 50 .obj 51 else 52 from; 53 } 54 55 pub fn is(self: Self, comptime tag: anytype) bool { 56 return switch (self) { 57 toTag(tag) => @TypeOf(tag) == Tag or self.obj.is(tag), 58 else => false, 59 }; 60 } 61 62 pub fn cast_if(self: Self, comptime tag: anytype) if (@TypeOf(tag) == Tag) ?utils.typeFromTag(Self, tag) else ?*Obj.Type.get(tag) { 63 return switch (self) { 64 toTag(tag) => if (@TypeOf(tag) == Tag) self.get(tag) else self.obj.cast_if(tag), 65 else => null, 66 }; 67 } 68 69 pub fn get(self: Self, comptime tag: anytype) tagType(tag) { 70 return @field(self, @tagName(toTag(tag))); 71 } 72 73 pub fn set(self: *Self, comptime tag: anytype, value: tagType(tag)) void { 74 @field(self, @tagName(toTag(tag))) = value; 75 } 76 77 pub fn tagType(comptime tag: anytype) type { 78 return utils.typeFromTag(Self, toTag(tag)); 79 } 80 81 pub const ParseNumberError = std.fmt.ParseFloatError; 82 83 pub fn parseNumber(str: []const u8) ParseNumberError!Self { 84 return Self{ .number = try std.fmt.parseFloat(tagType(Value.number), str) }; 85 } 86 87 pub fn isTruthy(self: Self) bool { 88 return switch (self) { 89 .nil => false, 90 .bool => |val| val, 91 else => true, 92 }; 93 } 94 95 pub fn eql(self: Self, other: Self) bool { 96 if (@intFromEnum(self) != @intFromEnum(other)) return false; 97 return switch (self) { 98 .number => |x| x == other.number, 99 .char => |x| x == other.char, 100 .bool => |x| x == other.bool, 101 .nil => true, 102 .obj => |x| x.eql(other.obj), 103 }; 104 } 105 };