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 }