DzLox

:)
git clone https://git.sr.ht/~ashymad/DzLox
Log | Files | Refs | Submodules | LICENSE

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 };