aboutsummaryrefslogtreecommitdiff
path: root/src/value.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/value.zig')
-rw-r--r--src/value.zig599
1 files changed, 363 insertions, 236 deletions
diff --git a/src/value.zig b/src/value.zig
index f26c8d8772..91b21511d4 100644
--- a/src/value.zig
+++ b/src/value.zig
@@ -84,11 +84,16 @@ pub const Value = extern union {
function,
extern_fn,
variable,
+ /// Represents a pointer to another immutable value.
ref_val,
+ /// Represents a pointer to a decl, not the value of the decl.
decl_ref,
elem_ptr,
+ /// A slice of u8 whose memory is managed externally.
bytes,
- repeated, // the value is a value repeated some number of times
+ /// This value is repeated some number of times. The amount of times to repeat
+ /// is stored externally.
+ repeated,
float_16,
float_32,
float_64,
@@ -99,6 +104,106 @@ pub const Value = extern union {
pub const last_no_payload_tag = Tag.bool_false;
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
+
+ pub fn Type(comptime t: Tag) type {
+ return switch (t) {
+ .u8_type,
+ .i8_type,
+ .u16_type,
+ .i16_type,
+ .u32_type,
+ .i32_type,
+ .u64_type,
+ .i64_type,
+ .usize_type,
+ .isize_type,
+ .c_short_type,
+ .c_ushort_type,
+ .c_int_type,
+ .c_uint_type,
+ .c_long_type,
+ .c_ulong_type,
+ .c_longlong_type,
+ .c_ulonglong_type,
+ .c_longdouble_type,
+ .f16_type,
+ .f32_type,
+ .f64_type,
+ .f128_type,
+ .c_void_type,
+ .bool_type,
+ .void_type,
+ .type_type,
+ .anyerror_type,
+ .comptime_int_type,
+ .comptime_float_type,
+ .noreturn_type,
+ .null_type,
+ .undefined_type,
+ .fn_noreturn_no_args_type,
+ .fn_void_no_args_type,
+ .fn_naked_noreturn_no_args_type,
+ .fn_ccc_void_no_args_type,
+ .single_const_pointer_to_comptime_int_type,
+ .const_slice_u8_type,
+ .enum_literal_type,
+ .anyframe_type,
+ .undef,
+ .zero,
+ .one,
+ .void_value,
+ .unreachable_value,
+ .empty_struct_value,
+ .empty_array,
+ .null_value,
+ .bool_true,
+ .bool_false,
+ => @compileError("Value Tag " ++ @tagName(t) ++ " has no payload"),
+
+ .int_big_positive,
+ .int_big_negative,
+ => Payload.BigInt,
+
+ .extern_fn,
+ .decl_ref,
+ => Payload.Decl,
+
+ .ref_val,
+ .repeated,
+ => Payload.SubValue,
+
+ .bytes,
+ .enum_literal,
+ => Payload.Bytes,
+
+ .ty => Payload.Ty,
+ .int_type => Payload.IntType,
+ .int_u64 => Payload.U64,
+ .int_i64 => Payload.I64,
+ .function => Payload.Function,
+ .variable => Payload.Variable,
+ .elem_ptr => Payload.ElemPtr,
+ .float_16 => Payload.Float_16,
+ .float_32 => Payload.Float_32,
+ .float_64 => Payload.Float_64,
+ .float_128 => Payload.Float_128,
+ .error_set => Payload.ErrorSet,
+ .@"error" => Payload.Error,
+ };
+ }
+
+ pub fn create(comptime t: Tag, ally: *Allocator, data: Data(t)) error{OutOfMemory}!Value {
+ const ptr = try ally.create(t.Type());
+ ptr.* = .{
+ .base = .{ .tag = t },
+ .data = data,
+ };
+ return Value{ .ptr_otherwise = &ptr.base };
+ }
+
+ pub fn Data(comptime t: Tag) type {
+ return std.meta.fieldInfo(t.Type(), "data").field_type;
+ }
};
pub fn initTag(small_tag: Tag) Value {
@@ -119,15 +224,36 @@ pub const Value = extern union {
}
}
+ /// Prefer `castTag` to this.
pub fn cast(self: Value, comptime T: type) ?*T {
- if (self.tag_if_small_enough < Tag.no_payload_count)
+ if (@hasField(T, "base_tag")) {
+ return base.castTag(T.base_tag);
+ }
+ if (self.tag_if_small_enough < Tag.no_payload_count) {
return null;
+ }
+ inline for (@typeInfo(Tag).Enum.fields) |field| {
+ if (field.value < Tag.no_payload_count)
+ continue;
+ const t = @intToEnum(Tag, field.value);
+ if (self.ptr_otherwise.tag == t) {
+ if (T == t.Type()) {
+ return @fieldParentPtr(T, "base", self.ptr_otherwise);
+ }
+ return null;
+ }
+ }
+ unreachable;
+ }
- const expected_tag = std.meta.fieldInfo(T, "base").default_value.?.tag;
- if (self.ptr_otherwise.tag != expected_tag)
+ pub fn castTag(self: Value, comptime t: Tag) ?*t.Type() {
+ if (self.tag_if_small_enough < Tag.no_payload_count)
return null;
- return @fieldParentPtr(T, "base", self.ptr_otherwise);
+ if (self.ptr_otherwise.tag == t)
+ return @fieldParentPtr(t.Type(), "base", self.ptr_otherwise);
+
+ return null;
}
pub fn copy(self: Value, allocator: *Allocator) error{OutOfMemory}!Value {
@@ -188,17 +314,17 @@ pub const Value = extern union {
=> unreachable,
.ty => {
- const payload = @fieldParentPtr(Payload.Ty, "base", self.ptr_otherwise);
+ const payload = self.castTag(.ty).?;
const new_payload = try allocator.create(Payload.Ty);
new_payload.* = .{
.base = payload.base,
- .ty = try payload.ty.copy(allocator),
+ .data = try payload.data.copy(allocator),
};
return Value{ .ptr_otherwise = &new_payload.base };
},
.int_type => return self.copyPayloadShallow(allocator, Payload.IntType),
- .int_u64 => return self.copyPayloadShallow(allocator, Payload.Int_u64),
- .int_i64 => return self.copyPayloadShallow(allocator, Payload.Int_i64),
+ .int_u64 => return self.copyPayloadShallow(allocator, Payload.U64),
+ .int_i64 => return self.copyPayloadShallow(allocator, Payload.I64),
.int_big_positive => {
@panic("TODO implement copying of big ints");
},
@@ -206,35 +332,37 @@ pub const Value = extern union {
@panic("TODO implement copying of big ints");
},
.function => return self.copyPayloadShallow(allocator, Payload.Function),
- .extern_fn => return self.copyPayloadShallow(allocator, Payload.ExternFn),
+ .extern_fn => return self.copyPayloadShallow(allocator, Payload.Decl),
.variable => return self.copyPayloadShallow(allocator, Payload.Variable),
.ref_val => {
- const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
- const new_payload = try allocator.create(Payload.RefVal);
+ const payload = self.castTag(.ref_val).?;
+ const new_payload = try allocator.create(Payload.SubValue);
new_payload.* = .{
.base = payload.base,
- .val = try payload.val.copy(allocator),
+ .data = try payload.data.copy(allocator),
};
return Value{ .ptr_otherwise = &new_payload.base };
},
- .decl_ref => return self.copyPayloadShallow(allocator, Payload.DeclRef),
+ .decl_ref => return self.copyPayloadShallow(allocator, Payload.Decl),
.elem_ptr => {
- const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise);
+ const payload = self.castTag(.elem_ptr).?;
const new_payload = try allocator.create(Payload.ElemPtr);
new_payload.* = .{
.base = payload.base,
- .array_ptr = try payload.array_ptr.copy(allocator),
- .index = payload.index,
+ .data = .{
+ .array_ptr = try payload.data.array_ptr.copy(allocator),
+ .index = payload.data.index,
+ },
};
return Value{ .ptr_otherwise = &new_payload.base };
},
.bytes => return self.copyPayloadShallow(allocator, Payload.Bytes),
.repeated => {
- const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
- const new_payload = try allocator.create(Payload.Repeated);
+ const payload = self.castTag(.repeated).?;
+ const new_payload = try allocator.create(Payload.SubValue);
new_payload.* = .{
.base = payload.base,
- .val = try payload.val.copy(allocator),
+ .data = try payload.data.copy(allocator),
};
return Value{ .ptr_otherwise = &new_payload.base };
},
@@ -243,7 +371,7 @@ pub const Value = extern union {
.float_64 => return self.copyPayloadShallow(allocator, Payload.Float_64),
.float_128 => return self.copyPayloadShallow(allocator, Payload.Float_128),
.enum_literal => {
- const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise);
+ const payload = self.castTag(.enum_literal).?;
const new_payload = try allocator.create(Payload.Bytes);
new_payload.* = .{
.base = payload.base,
@@ -259,7 +387,7 @@ pub const Value = extern union {
}
fn copyPayloadShallow(self: Value, allocator: *Allocator, comptime T: type) error{OutOfMemory}!Value {
- const payload = @fieldParentPtr(T, "base", self.ptr_otherwise);
+ const payload = self.cast(T).?;
const new_payload = try allocator.create(T);
new_payload.* = payload.*;
return Value{ .ptr_otherwise = &new_payload.base };
@@ -326,45 +454,45 @@ pub const Value = extern union {
.unreachable_value => return out_stream.writeAll("unreachable"),
.bool_true => return out_stream.writeAll("true"),
.bool_false => return out_stream.writeAll("false"),
- .ty => return val.cast(Payload.Ty).?.ty.format("", options, out_stream),
+ .ty => return val.castTag(.ty).?.data.format("", options, out_stream),
.int_type => {
- const int_type = val.cast(Payload.IntType).?;
+ const int_type = val.castTag(.int_type).?.data;
return out_stream.print("{}{}", .{
if (int_type.signed) "s" else "u",
int_type.bits,
});
},
- .int_u64 => return std.fmt.formatIntValue(val.cast(Payload.Int_u64).?.int, "", options, out_stream),
- .int_i64 => return std.fmt.formatIntValue(val.cast(Payload.Int_i64).?.int, "", options, out_stream),
- .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),
- .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}),
+ .int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", options, out_stream),
+ .int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", options, out_stream),
+ .int_big_positive => return out_stream.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}),
+ .int_big_negative => return out_stream.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}),
.function => return out_stream.writeAll("(function)"),
.extern_fn => return out_stream.writeAll("(extern function)"),
.variable => return out_stream.writeAll("(variable)"),
.ref_val => {
- const ref_val = val.cast(Payload.RefVal).?;
+ const ref_val = val.castTag(.ref_val).?.data;
try out_stream.writeAll("&const ");
- val = ref_val.val;
+ val = ref_val;
},
.decl_ref => return out_stream.writeAll("(decl ref)"),
.elem_ptr => {
- const elem_ptr = val.cast(Payload.ElemPtr).?;
+ const elem_ptr = val.castTag(.elem_ptr).?.data;
try out_stream.print("&[{}] ", .{elem_ptr.index});
val = elem_ptr.array_ptr;
},
.empty_array => return out_stream.writeAll(".{}"),
- .enum_literal => return out_stream.print(".{z}", .{self.cast(Payload.Bytes).?.data}),
- .bytes => return out_stream.print("\"{Z}\"", .{self.cast(Payload.Bytes).?.data}),
+ .enum_literal => return out_stream.print(".{z}", .{self.castTag(.enum_literal).?.data}),
+ .bytes => return out_stream.print("\"{Z}\"", .{self.castTag(.bytes).?.data}),
.repeated => {
try out_stream.writeAll("(repeated) ");
- val = val.cast(Payload.Repeated).?.val;
+ val = val.castTag(.repeated).?.data;
},
- .float_16 => return out_stream.print("{}", .{val.cast(Payload.Float_16).?.val}),
- .float_32 => return out_stream.print("{}", .{val.cast(Payload.Float_32).?.val}),
- .float_64 => return out_stream.print("{}", .{val.cast(Payload.Float_64).?.val}),
- .float_128 => return out_stream.print("{}", .{val.cast(Payload.Float_128).?.val}),
+ .float_16 => return out_stream.print("{}", .{val.castTag(.float_16).?.data}),
+ .float_32 => return out_stream.print("{}", .{val.castTag(.float_32).?.data}),
+ .float_64 => return out_stream.print("{}", .{val.castTag(.float_64).?.data}),
+ .float_128 => return out_stream.print("{}", .{val.castTag(.float_128).?.data}),
.error_set => {
- const error_set = val.cast(Payload.ErrorSet).?;
+ const error_set = val.castTag(.error_set).?.data;
try out_stream.writeAll("error{");
var it = error_set.fields.iterator();
while (it.next()) |entry| {
@@ -372,21 +500,24 @@ pub const Value = extern union {
}
return out_stream.writeAll("}");
},
- .@"error" => return out_stream.print("error.{}", .{val.cast(Payload.Error).?.name}),
+ .@"error" => return out_stream.print("error.{}", .{val.castTag(.@"error").?.data.name}),
};
}
/// Asserts that the value is representable as an array of bytes.
/// Copies the value into a freshly allocated slice of memory, which is owned by the caller.
pub fn toAllocatedBytes(self: Value, allocator: *Allocator) ![]u8 {
- if (self.cast(Payload.Bytes)) |bytes| {
- return std.mem.dupe(allocator, u8, bytes.data);
+ if (self.castTag(.bytes)) |payload| {
+ return std.mem.dupe(allocator, u8, payload.data);
}
- if (self.cast(Payload.Repeated)) |repeated| {
+ if (self.castTag(.enum_literal)) |payload| {
+ return std.mem.dupe(allocator, u8, payload.data);
+ }
+ if (self.castTag(.repeated)) |payload| {
@panic("TODO implement toAllocatedBytes for this Value tag");
}
- if (self.cast(Payload.DeclRef)) |declref| {
- const val = try declref.decl.value();
+ if (self.castTag(.decl_ref)) |payload| {
+ const val = try payload.data.value();
return val.toAllocatedBytes(allocator);
}
unreachable;
@@ -395,7 +526,7 @@ pub const Value = extern union {
/// Asserts that the value is representable as a type.
pub fn toType(self: Value, allocator: *Allocator) !Type {
return switch (self.tag()) {
- .ty => self.cast(Payload.Ty).?.ty,
+ .ty => self.castTag(.ty).?.data,
.u8_type => Type.initTag(.u8),
.i8_type => Type.initTag(.i8),
.u16_type => Type.initTag(.u16),
@@ -439,7 +570,7 @@ pub const Value = extern union {
.anyframe_type => Type.initTag(.@"anyframe"),
.int_type => {
- const payload = self.cast(Payload.IntType).?;
+ const payload = self.castTag(.int_type).?.data;
const new = try allocator.create(Type.Payload.Bits);
new.* = .{
.base = .{
@@ -450,7 +581,7 @@ pub const Value = extern union {
return Type.initPayload(&new.base);
},
.error_set => {
- const payload = self.cast(Payload.ErrorSet).?;
+ const payload = self.castTag(.error_set).?.data;
return Type.Tag.error_set.create(allocator, payload.decl);
},
@@ -564,10 +695,10 @@ pub const Value = extern union {
.bool_true,
=> return BigIntMutable.init(&space.limbs, 1).toConst(),
- .int_u64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_u64).?.int).toConst(),
- .int_i64 => return BigIntMutable.init(&space.limbs, self.cast(Payload.Int_i64).?.int).toConst(),
- .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt(),
- .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt(),
+ .int_u64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_u64).?.data).toConst(),
+ .int_i64 => return BigIntMutable.init(&space.limbs, self.castTag(.int_i64).?.data).toConst(),
+ .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt(),
+ .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt(),
}
}
@@ -649,10 +780,10 @@ pub const Value = extern union {
.bool_true,
=> return 1,
- .int_u64 => return self.cast(Payload.Int_u64).?.int,
- .int_i64 => return @intCast(u64, self.cast(Payload.Int_i64).?.int),
- .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(u64) catch unreachable,
- .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(u64) catch unreachable,
+ .int_u64 => return self.castTag(.int_u64).?.data,
+ .int_i64 => return @intCast(u64, self.castTag(.int_i64).?.data),
+ .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(u64) catch unreachable,
+ .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(u64) catch unreachable,
}
}
@@ -734,10 +865,10 @@ pub const Value = extern union {
.bool_true,
=> return 1,
- .int_u64 => return @intCast(i64, self.cast(Payload.Int_u64).?.int),
- .int_i64 => return self.cast(Payload.Int_i64).?.int,
- .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().to(i64) catch unreachable,
- .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().to(i64) catch unreachable,
+ .int_u64 => return @intCast(i64, self.castTag(.int_u64).?.data),
+ .int_i64 => return self.castTag(.int_i64).?.data,
+ .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().to(i64) catch unreachable,
+ .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().to(i64) catch unreachable,
}
}
@@ -753,14 +884,14 @@ pub const Value = extern union {
pub fn toFloat(self: Value, comptime T: type) T {
return switch (self.tag()) {
.float_16 => @panic("TODO soft float"),
- .float_32 => @floatCast(T, self.cast(Payload.Float_32).?.val),
- .float_64 => @floatCast(T, self.cast(Payload.Float_64).?.val),
- .float_128 => @floatCast(T, self.cast(Payload.Float_128).?.val),
+ .float_32 => @floatCast(T, self.castTag(.float_32).?.data),
+ .float_64 => @floatCast(T, self.castTag(.float_64).?.data),
+ .float_128 => @floatCast(T, self.castTag(.float_128).?.data),
.zero => 0,
.one => 1,
- .int_u64 => @intToFloat(T, self.cast(Payload.Int_u64).?.int),
- .int_i64 => @intToFloat(T, self.cast(Payload.Int_i64).?.int),
+ .int_u64 => @intToFloat(T, self.castTag(.int_u64).?.data),
+ .int_i64 => @intToFloat(T, self.castTag(.int_i64).?.data),
.int_big_positive, .int_big_negative => @panic("big int to f128"),
else => unreachable,
@@ -846,15 +977,15 @@ pub const Value = extern union {
=> return 1,
.int_u64 => {
- const x = self.cast(Payload.Int_u64).?.int;
+ const x = self.castTag(.int_u64).?.data;
if (x == 0) return 0;
return @intCast(usize, std.math.log2(x) + 1);
},
.int_i64 => {
@panic("TODO implement i64 intBitCountTwosComp");
},
- .int_big_positive => return self.cast(Payload.IntBigPositive).?.asBigInt().bitCountTwosComp(),
- .int_big_negative => return self.cast(Payload.IntBigNegative).?.asBigInt().bitCountTwosComp(),
+ .int_big_positive => return self.castTag(.int_big_positive).?.asBigInt().bitCountTwosComp(),
+ .int_big_negative => return self.castTag(.int_big_negative).?.asBigInt().bitCountTwosComp(),
}
}
@@ -943,7 +1074,7 @@ pub const Value = extern union {
.int_u64 => switch (ty.zigTypeTag()) {
.Int => {
- const x = self.cast(Payload.Int_u64).?.int;
+ const x = self.castTag(.int_u64).?.data;
if (x == 0) return true;
const info = ty.intInfo(target);
const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
@@ -954,7 +1085,7 @@ pub const Value = extern union {
},
.int_i64 => switch (ty.zigTypeTag()) {
.Int => {
- const x = self.cast(Payload.Int_i64).?.int;
+ const x = self.castTag(.int_i64).?.data;
if (x == 0) return true;
const info = ty.intInfo(target);
if (info.signedness == .unsigned and x < 0)
@@ -967,7 +1098,7 @@ pub const Value = extern union {
.int_big_positive => switch (ty.zigTypeTag()) {
.Int => {
const info = ty.intInfo(target);
- return self.cast(Payload.IntBigPositive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
+ return self.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
},
.ComptimeInt => return true,
else => unreachable,
@@ -975,7 +1106,7 @@ pub const Value = extern union {
.int_big_negative => switch (ty.zigTypeTag()) {
.Int => {
const info = ty.intInfo(target);
- return self.cast(Payload.IntBigNegative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
+ return self.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
},
.ComptimeInt => return true,
else => unreachable,
@@ -986,42 +1117,28 @@ pub const Value = extern union {
/// Converts an integer or a float to a float.
/// Returns `error.Overflow` if the value does not fit in the new type.
pub fn floatCast(self: Value, allocator: *Allocator, ty: Type, target: Target) !Value {
- const dest_bit_count = switch (ty.tag()) {
- .comptime_float => 128,
- else => ty.floatBits(target),
- };
- switch (dest_bit_count) {
- 16, 32, 64, 128 => {},
- else => std.debug.panic("TODO float cast bit count {}\n", .{dest_bit_count}),
- }
- if (ty.isInt()) {
- @panic("TODO int to float");
- }
-
- switch (dest_bit_count) {
- 16 => {
- @panic("TODO soft float");
- // var res_payload = Value.Payload.Float_16{.val = self.toFloat(f16)};
- // if (!self.eql(Value.initPayload(&res_payload.base)))
- // return error.Overflow;
- // return Value.initPayload(&res_payload.base).copy(allocator);
+ switch (ty.tag()) {
+ .f16 => {
+ @panic("TODO add __trunctfhf2 to compiler-rt");
+ //const res = try Value.Tag.float_16.create(allocator, self.toFloat(f16));
+ //if (!self.eql(res))
+ // return error.Overflow;
+ //return res;
},
- 32 => {
- var res_payload = Value.Payload.Float_32{ .val = self.toFloat(f32) };
- if (!self.eql(Value.initPayload(&res_payload.base)))
+ .f32 => {
+ const res = try Value.Tag.float_32.create(allocator, self.toFloat(f32));
+ if (!self.eql(res))
return error.Overflow;
- return Value.initPayload(&res_payload.base).copy(allocator);
+ return res;
},
- 64 => {
- var res_payload = Value.Payload.Float_64{ .val = self.toFloat(f64) };
- if (!self.eql(Value.initPayload(&res_payload.base)))
+ .f64 => {
+ const res = try Value.Tag.float_64.create(allocator, self.toFloat(f64));
+ if (!self.eql(res))
return error.Overflow;
- return Value.initPayload(&res_payload.base).copy(allocator);
+ return res;
},
- 128 => {
- const float_payload = try allocator.create(Value.Payload.Float_128);
- float_payload.* = .{ .val = self.toFloat(f128) };
- return Value.initPayload(&float_payload.base);
+ .f128, .comptime_float, .c_longdouble => {
+ return Value.Tag.float_128.create(allocator, self.toFloat(f128));
},
else => unreachable,
}
@@ -1102,10 +1219,10 @@ pub const Value = extern union {
.one,
=> false,
- .float_16 => @rem(self.cast(Payload.Float_16).?.val, 1) != 0,
- .float_32 => @rem(self.cast(Payload.Float_32).?.val, 1) != 0,
- .float_64 => @rem(self.cast(Payload.Float_64).?.val, 1) != 0,
- // .float_128 => @rem(self.cast(Payload.Float_128).?.val, 1) != 0,
+ .float_16 => @rem(self.castTag(.float_16).?.data, 1) != 0,
+ .float_32 => @rem(self.castTag(.float_32).?.data, 1) != 0,
+ .float_64 => @rem(self.castTag(.float_64).?.data, 1) != 0,
+ // .float_128 => @rem(self.castTag(.float_128).?.data, 1) != 0,
.float_128 => @panic("TODO lld: error: undefined symbol: fmodl"),
};
}
@@ -1182,15 +1299,15 @@ pub const Value = extern union {
.bool_true,
=> .gt,
- .int_u64 => std.math.order(lhs.cast(Payload.Int_u64).?.int, 0),
- .int_i64 => std.math.order(lhs.cast(Payload.Int_i64).?.int, 0),
- .int_big_positive => lhs.cast(Payload.IntBigPositive).?.asBigInt().orderAgainstScalar(0),
- .int_big_negative => lhs.cast(Payload.IntBigNegative).?.asBigInt().orderAgainstScalar(0),
+ .int_u64 => std.math.order(lhs.castTag(.int_u64).?.data, 0),
+ .int_i64 => std.math.order(lhs.castTag(.int_i64).?.data, 0),
+ .int_big_positive => lhs.castTag(.int_big_positive).?.asBigInt().orderAgainstScalar(0),
+ .int_big_negative => lhs.castTag(.int_big_negative).?.asBigInt().orderAgainstScalar(0),
- .float_16 => std.math.order(lhs.cast(Payload.Float_16).?.val, 0),
- .float_32 => std.math.order(lhs.cast(Payload.Float_32).?.val, 0),
- .float_64 => std.math.order(lhs.cast(Payload.Float_64).?.val, 0),
- .float_128 => std.math.order(lhs.cast(Payload.Float_128).?.val, 0),
+ .float_16 => std.math.order(lhs.castTag(.float_16).?.data, 0),
+ .float_32 => std.math.order(lhs.castTag(.float_32).?.data, 0),
+ .float_64 => std.math.order(lhs.castTag(.float_64).?.data, 0),
+ .float_128 => std.math.order(lhs.castTag(.float_128).?.data, 0),
};
}
@@ -1208,10 +1325,10 @@ pub const Value = extern union {
if (lhs_float and rhs_float) {
if (lhs_tag == rhs_tag) {
return switch (lhs.tag()) {
- .float_16 => return std.math.order(lhs.cast(Payload.Float_16).?.val, rhs.cast(Payload.Float_16).?.val),
- .float_32 => return std.math.order(lhs.cast(Payload.Float_32).?.val, rhs.cast(Payload.Float_32).?.val),
- .float_64 => return std.math.order(lhs.cast(Payload.Float_64).?.val, rhs.cast(Payload.Float_64).?.val),
- .float_128 => return std.math.order(lhs.cast(Payload.Float_128).?.val, rhs.cast(Payload.Float_128).?.val),
+ .float_16 => return std.math.order(lhs.castTag(.float_16).?.data, rhs.castTag(.float_16).?.data),
+ .float_32 => return std.math.order(lhs.castTag(.float_32).?.data, rhs.castTag(.float_32).?.data),
+ .float_64 => return std.math.order(lhs.castTag(.float_64).?.data, rhs.castTag(.float_64).?.data),
+ .float_128 => return std.math.order(lhs.castTag(.float_128).?.data, rhs.castTag(.float_128).?.data),
else => unreachable,
};
}
@@ -1244,8 +1361,8 @@ pub const Value = extern union {
if (a.tag() == .void_value or a.tag() == .null_value) {
return true;
} else if (a.tag() == .enum_literal) {
- const a_name = @fieldParentPtr(Payload.Bytes, "base", a.ptr_otherwise).data;
- const b_name = @fieldParentPtr(Payload.Bytes, "base", b.ptr_otherwise).data;
+ const a_name = a.castTag(.enum_literal).?.data;
+ const b_name = b.castTag(.enum_literal).?.data;
return std.mem.eql(u8, a_name, b_name);
}
}
@@ -1313,11 +1430,11 @@ pub const Value = extern union {
},
.error_set => {
// Payload.decl should be same for all instances of the type.
- const payload = @fieldParentPtr(Payload.ErrorSet, "base", self.ptr_otherwise);
+ const payload = self.castTag(.error_set).?.data;
std.hash.autoHash(&hasher, payload.decl);
},
.int_type => {
- const payload = self.cast(Payload.IntType).?;
+ const payload = self.castTag(.int_type).?.data;
var int_payload = Type.Payload.Bits{
.base = .{
.tag = if (payload.signed) .int_signed else .int_unsigned,
@@ -1341,25 +1458,29 @@ pub const Value = extern union {
.one, .bool_true => std.hash.autoHash(&hasher, @as(u64, 1)),
.float_16, .float_32, .float_64, .float_128 => {},
- .enum_literal, .bytes => {
- const payload = @fieldParentPtr(Payload.Bytes, "base", self.ptr_otherwise);
+ .enum_literal => {
+ const payload = self.castTag(.enum_literal).?;
+ hasher.update(payload.data);
+ },
+ .bytes => {
+ const payload = self.castTag(.bytes).?;
hasher.update(payload.data);
},
.int_u64 => {
- const payload = @fieldParentPtr(Payload.Int_u64, "base", self.ptr_otherwise);
- std.hash.autoHash(&hasher, payload.int);
+ const payload = self.castTag(.int_u64).?;
+ std.hash.autoHash(&hasher, payload.data);
},
.int_i64 => {
- const payload = @fieldParentPtr(Payload.Int_i64, "base", self.ptr_otherwise);
- std.hash.autoHash(&hasher, payload.int);
+ const payload = self.castTag(.int_i64).?;
+ std.hash.autoHash(&hasher, payload.data);
},
.repeated => {
- const payload = @fieldParentPtr(Payload.Repeated, "base", self.ptr_otherwise);
- std.hash.autoHash(&hasher, payload.val.hash());
+ const payload = self.castTag(.repeated).?;
+ std.hash.autoHash(&hasher, payload.data.hash());
},
.ref_val => {
- const payload = @fieldParentPtr(Payload.RefVal, "base", self.ptr_otherwise);
- std.hash.autoHash(&hasher, payload.val.hash());
+ const payload = self.castTag(.ref_val).?;
+ std.hash.autoHash(&hasher, payload.data.hash());
},
.int_big_positive, .int_big_negative => {
var space: BigIntSpace = undefined;
@@ -1379,28 +1500,28 @@ pub const Value = extern union {
}
},
.elem_ptr => {
- const payload = @fieldParentPtr(Payload.ElemPtr, "base", self.ptr_otherwise);
+ const payload = self.castTag(.elem_ptr).?.data;
std.hash.autoHash(&hasher, payload.array_ptr.hash());
std.hash.autoHash(&hasher, payload.index);
},
.decl_ref => {
- const payload = @fieldParentPtr(Payload.DeclRef, "base", self.ptr_otherwise);
- std.hash.autoHash(&hasher, payload.decl);
+ const decl = self.castTag(.decl_ref).?.data;
+ std.hash.autoHash(&hasher, decl);
},
.function => {
- const payload = @fieldParentPtr(Payload.Function, "base", self.ptr_otherwise);
- std.hash.autoHash(&hasher, payload.func);
+ const func = self.castTag(.function).?.data;
+ std.hash.autoHash(&hasher, func);
},
.extern_fn => {
- const payload = @fieldParentPtr(Payload.ExternFn, "base", self.ptr_otherwise);
- std.hash.autoHash(&hasher, payload.decl);
+ const decl = self.castTag(.extern_fn).?.data;
+ std.hash.autoHash(&hasher, decl);
},
.variable => {
- const payload = @fieldParentPtr(Payload.Variable, "base", self.ptr_otherwise);
- std.hash.autoHash(&hasher, payload.variable);
+ const variable = self.castTag(.variable).?.data;
+ std.hash.autoHash(&hasher, variable);
},
.@"error" => {
- const payload = @fieldParentPtr(Payload.Error, "base", self.ptr_otherwise);
+ const payload = self.castTag(.@"error").?.data;
hasher.update(payload.name);
std.hash.autoHash(&hasher, payload.value);
},
@@ -1483,10 +1604,10 @@ pub const Value = extern union {
.empty_struct_value,
=> unreachable,
- .ref_val => self.cast(Payload.RefVal).?.val,
- .decl_ref => self.cast(Payload.DeclRef).?.decl.value(),
+ .ref_val => self.castTag(.ref_val).?.data,
+ .decl_ref => self.castTag(.decl_ref).?.data.value(),
.elem_ptr => {
- const elem_ptr = self.cast(Payload.ElemPtr).?;
+ const elem_ptr = self.castTag(.elem_ptr).?.data;
const array_val = try elem_ptr.array_ptr.pointerDeref(allocator);
return array_val.elemValue(allocator, elem_ptr.index);
},
@@ -1570,26 +1691,26 @@ pub const Value = extern union {
.empty_array => unreachable, // out of bounds array index
- .bytes => {
- const int_payload = try allocator.create(Payload.Int_u64);
- int_payload.* = .{ .int = self.cast(Payload.Bytes).?.data[index] };
- return Value.initPayload(&int_payload.base);
- },
+ .bytes => return Tag.int_u64.create(allocator, self.castTag(.bytes).?.data[index]),
// No matter the index; all the elements are the same!
- .repeated => return self.cast(Payload.Repeated).?.val,
+ .repeated => return self.castTag(.repeated).?.data,
}
}
/// Returns a pointer to the element value at the index.
pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value {
- const payload = try allocator.create(Payload.ElemPtr);
- if (self.cast(Payload.ElemPtr)) |elem_ptr| {
- payload.* = .{ .array_ptr = elem_ptr.array_ptr, .index = elem_ptr.index + index };
- } else {
- payload.* = .{ .array_ptr = self, .index = index };
+ if (self.castTag(.elem_ptr)) |elem_ptr| {
+ return Tag.elem_ptr.create(allocator, .{
+ .array_ptr = elem_ptr.data.array_ptr,
+ .index = elem_ptr.data.index + index,
+ });
}
- return Value.initPayload(&payload.base);
+
+ return Tag.elem_ptr.create(allocator, .{
+ .array_ptr = self,
+ .index = index,
+ });
}
pub fn isUndef(self: Value) bool {
@@ -1776,131 +1897,128 @@ pub const Value = extern union {
pub const Payload = struct {
tag: Tag,
- pub const Int_u64 = struct {
- base: Payload = Payload{ .tag = .int_u64 },
- int: u64,
+ pub const U64 = struct {
+ base: Payload,
+ data: u64,
};
- pub const Int_i64 = struct {
- base: Payload = Payload{ .tag = .int_i64 },
- int: i64,
- };
-
- pub const IntBigPositive = struct {
- base: Payload = Payload{ .tag = .int_big_positive },
- limbs: []const std.math.big.Limb,
-
- pub fn asBigInt(self: IntBigPositive) BigIntConst {
- return BigIntConst{ .limbs = self.limbs, .positive = true };
- }
+ pub const I64 = struct {
+ base: Payload,
+ data: i64,
};
- pub const IntBigNegative = struct {
- base: Payload = Payload{ .tag = .int_big_negative },
- limbs: []const std.math.big.Limb,
+ pub const BigInt = struct {
+ base: Payload,
+ data: []const std.math.big.Limb,
- pub fn asBigInt(self: IntBigNegative) BigIntConst {
- return BigIntConst{ .limbs = self.limbs, .positive = false };
+ pub fn asBigInt(self: BigInt) BigIntConst {
+ const positive = switch (self.base.tag) {
+ .int_big_positive => true,
+ .int_big_negative => false,
+ else => unreachable,
+ };
+ return BigIntConst{ .limbs = self.data, .positive = positive };
}
};
pub const Function = struct {
- base: Payload = Payload{ .tag = .function },
- func: *Module.Fn,
+ base: Payload,
+ data: *Module.Fn,
};
- pub const ExternFn = struct {
- base: Payload = Payload{ .tag = .extern_fn },
- decl: *Module.Decl,
+ pub const Decl = struct {
+ base: Payload,
+ data: *Module.Decl,
};
pub const Variable = struct {
- base: Payload = Payload{ .tag = .variable },
- variable: *Module.Var,
- };
-
- pub const ArraySentinel0_u8_Type = struct {
- base: Payload = Payload{ .tag = .array_sentinel_0_u8_type },
- len: u64,
- };
-
- /// Represents a pointer to another immutable value.
- pub const RefVal = struct {
- base: Payload = Payload{ .tag = .ref_val },
- val: Value,
+ base: Payload,
+ data: *Module.Var,
};
- /// Represents a pointer to a decl, not the value of the decl.
- pub const DeclRef = struct {
- base: Payload = Payload{ .tag = .decl_ref },
- decl: *Module.Decl,
+ pub const SubValue = struct {
+ base: Payload,
+ data: Value,
};
pub const ElemPtr = struct {
- base: Payload = Payload{ .tag = .elem_ptr },
- array_ptr: Value,
- index: usize,
+ pub const base_tag = Tag.elem_ptr;
+
+ base: Payload = Payload{ .tag = base_tag },
+ data: struct {
+ array_ptr: Value,
+ index: usize,
+ },
};
pub const Bytes = struct {
- base: Payload = Payload{ .tag = .bytes },
+ base: Payload,
data: []const u8,
};
pub const Ty = struct {
- base: Payload = Payload{ .tag = .ty },
- ty: Type,
+ base: Payload,
+ data: Type,
};
pub const IntType = struct {
- base: Payload = Payload{ .tag = .int_type },
- bits: u16,
- signed: bool,
- };
+ pub const base_tag = Tag.int_type;
- pub const Repeated = struct {
- base: Payload = Payload{ .tag = .ty },
- /// This value is repeated some number of times. The amount of times to repeat
- /// is stored externally.
- val: Value,
+ base: Payload = Payload{ .tag = base_tag },
+ data: struct {
+ bits: u16,
+ signed: bool,
+ },
};
pub const Float_16 = struct {
- base: Payload = .{ .tag = .float_16 },
- val: f16,
+ pub const base_tag = Tag.float_16;
+
+ base: Payload = .{ .tag = base_tag },
+ data: f16,
};
pub const Float_32 = struct {
- base: Payload = .{ .tag = .float_32 },
- val: f32,
+ pub const base_tag = Tag.float_32;
+
+ base: Payload = .{ .tag = base_tag },
+ data: f32,
};
pub const Float_64 = struct {
- base: Payload = .{ .tag = .float_64 },
- val: f64,
+ pub const base_tag = Tag.float_64;
+
+ base: Payload = .{ .tag = base_tag },
+ data: f64,
};
pub const Float_128 = struct {
- base: Payload = .{ .tag = .float_128 },
- val: f128,
+ pub const base_tag = Tag.float_128;
+
+ base: Payload = .{ .tag = base_tag },
+ data: f128,
};
pub const ErrorSet = struct {
- base: Payload = .{ .tag = .error_set },
+ pub const base_tag = Tag.error_set;
- // TODO revisit this when we have the concept of the error tag type
- fields: std.StringHashMapUnmanaged(u16),
- decl: *Module.Decl,
+ base: Payload = .{ .tag = base_tag },
+ data: struct {
+ // TODO revisit this when we have the concept of the error tag type
+ fields: std.StringHashMapUnmanaged(u16),
+ decl: *Module.Decl,
+ },
};
pub const Error = struct {
base: Payload = .{ .tag = .@"error" },
-
- // TODO revisit this when we have the concept of the error tag type
- /// `name` is owned by `Module` and will be valid for the entire
- /// duration of the compilation.
- name: []const u8,
- value: u16,
+ data: struct {
+ // TODO revisit this when we have the concept of the error tag type
+ /// `name` is owned by `Module` and will be valid for the entire
+ /// duration of the compilation.
+ name: []const u8,
+ value: u16,
+ },
};
};
@@ -1914,15 +2032,24 @@ pub const Value = extern union {
test "hash same value different representation" {
const zero_1 = Value.initTag(.zero);
- var payload_1 = Value.Payload.Int_u64{ .int = 0 };
+ var payload_1 = Value.Payload.U64{
+ .base = .{ .tag = .int_u64 },
+ .data = 0,
+ };
const zero_2 = Value.initPayload(&payload_1.base);
std.testing.expectEqual(zero_1.hash(), zero_2.hash());
- var payload_2 = Value.Payload.Int_i64{ .int = 0 };
+ var payload_2 = Value.Payload.I64{
+ .base = .{ .tag = .int_i64 },
+ .data = 0,
+ };
const zero_3 = Value.initPayload(&payload_2.base);
std.testing.expectEqual(zero_2.hash(), zero_3.hash());
- var payload_3 = Value.Payload.IntBigNegative{ .limbs = &[_]std.math.big.Limb{0} };
+ var payload_3 = Value.Payload.BigInt{
+ .base = .{ .tag = .int_big_negative },
+ .data = &[_]std.math.big.Limb{0},
+ };
const zero_4 = Value.initPayload(&payload_3.base);
std.testing.expectEqual(zero_3.hash(), zero_4.hash());
}