DzLox

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

obj.zig (4521B)


      1 const std = @import("std");
      2 
      3 const utils = @import("lib::utils.zig");
      4 const Value = @import("value.zig").Value;
      5 
      6 pub fn Obj(Fields: type) type {
      7     return packed struct {
      8         const Self = @This();
      9 
     10         type: Type,
     11         fields: Fields = Fields{},
     12 
     13         pub const List = @import("obj::list.zig").List(Fields);
     14         pub const String = @import("obj::string.zig").String(Fields);
     15         pub const Table = @import("obj::table.zig").Table(Fields);
     16         pub const Function = @import("obj::function.zig").Function(Fields);
     17         pub const Native = @import("obj::native.zig").Native(Fields);
     18         pub const Chunk = @import("obj::chunk.zig").Chunk(Fields);
     19         pub const Upvalue = @import("obj::upvalue.zig").Upvalue(Fields);
     20         pub const Class = @import("obj::class.zig").Class(Fields);
     21         pub const Instance = @import("obj::instance.zig").Instance(Fields);
     22 
     23         pub const Error = error{IllegalCastError} //
     24             || List.Error //
     25             || String.Error //
     26             || Table.Error //
     27             || Function.Error //
     28             || Native.Error //
     29             || List.Error //
     30             || Chunk.Error //
     31             || Upvalue.Error //
     32             || Class.Error //
     33             || Instance.Error;
     34 
     35         pub const Type = enum(u8) {
     36             String,
     37             Table,
     38             Function,
     39             Native,
     40             List,
     41             Chunk,
     42             Upvalue,
     43             Class,
     44             Instance,
     45 
     46             pub fn get(self: @This()) type {
     47                 return @field(Self, @tagName(self));
     48             }
     49         };
     50 
     51         fn child_name(fqn: []const u8) []const u8 {
     52             var lastDot = 0;
     53             for (fqn, 0..) |c, i| {
     54                 if (c == '.') lastDot = i + 1;
     55                 if (c == '(') return fqn[lastDot..i];
     56             }
     57             return fqn;
     58         }
     59 
     60         pub fn is_child(T: type) bool {
     61             inline for (std.meta.tags(Type)) |tag| {
     62                 if (*tag.get() == T) return true;
     63             }
     64             return false;
     65         }
     66 
     67         pub fn make(child: type) Self {
     68             return Self{
     69                 .type = @field(Type, child_name(@typeName(child))),
     70             };
     71         }
     72 
     73         pub fn init(comptime tp: Type, arg: tp.get().Arg, allocator: std.mem.Allocator) !*Self {
     74             return (try tp.get().init(arg, allocator)).cast();
     75         }
     76 
     77         pub fn format(self: anytype, writer: *std.Io.Writer) !void {
     78             _ = try writer.write("<");
     79             switch (self.type) {
     80                 inline else => |tp| {
     81                     _ = try writer.write(@tagName(tp)[0..2]);
     82                     if (@hasDecl(tp.get(), "format")) {
     83                         _ = try writer.write(":");
     84                         try self._cast(tp).format(writer);
     85                     }
     86                 },
     87             }
     88             if (@hasDecl(Fields, "format")) {
     89                 try self.fields.format(writer);
     90             }
     91             _ = try writer.write(">");
     92         }
     93 
     94         pub fn eql(self: *const Self, other: *const Self) bool {
     95             if (!self.is(other.type)) return false;
     96 
     97             return switch (self.type) {
     98                 inline else => |tp| if (@hasDecl(tp.get(), "eql")) self._cast(tp).eql(other._cast(tp)) else false,
     99             };
    100         }
    101 
    102         pub fn free(obj: *Self, allocator: std.mem.Allocator) void {
    103             return switch (obj.type) {
    104                 inline else => |tp| obj._cast(tp).free(allocator),
    105             };
    106         }
    107 
    108         pub fn from(arg: anytype) ?*Self {
    109             const T = @TypeOf(arg);
    110 
    111             return switch (T) {
    112                 Value => switch (arg) {
    113                     .obj => |o| Self.from(o),
    114                     else => null,
    115                 },
    116                 *Self => arg,
    117                 else => if (comptime Self.is_child(T)) arg.cast() else null,
    118             };
    119         }
    120 
    121         pub fn is(self: *const Self, tp: Type) bool {
    122             return self.type == tp;
    123         }
    124 
    125         pub fn cast(self: anytype, comptime tp: Type) Error!utils.copy_const(@TypeOf(self), *tp.get()) {
    126             return if (self.is(tp)) self._cast(tp) else Error.IllegalCastError;
    127         }
    128 
    129         pub fn cast_if(self: anytype, comptime tp: Type) ?utils.copy_const(@TypeOf(self), *tp.get()) {
    130             return if (self.is(tp)) self._cast(tp) else null;
    131         }
    132 
    133         fn _cast(self: anytype, comptime tp: Type) utils.copy_const(@TypeOf(self), *tp.get()) {
    134             return @ptrCast(@alignCast(self));
    135         }
    136     };
    137 }