zig/src/TypedValue.zig
Andrew Kelley 593130ce0a stage2: lazy @alignOf
Add a `target` parameter to every function that deals with Type and
Value.
2022-03-22 15:45:58 -07:00

339 lines
15 KiB
Zig

const std = @import("std");
const Type = @import("type.zig").Type;
const Value = @import("value.zig").Value;
const Allocator = std.mem.Allocator;
const TypedValue = @This();
const Target = std.Target;
ty: Type,
val: Value,
/// Memory management for TypedValue. The main purpose of this type
/// is to be small and have a deinit() function to free associated resources.
pub const Managed = struct {
/// If the tag value is less than Tag.no_payload_count, then no pointer
/// dereference is needed.
typed_value: TypedValue,
/// If this is `null` then there is no memory management needed.
arena: ?*std.heap.ArenaAllocator.State = null,
pub fn deinit(self: *Managed, allocator: Allocator) void {
if (self.arena) |a| a.promote(allocator).deinit();
self.* = undefined;
}
};
/// Assumes arena allocation. Does a recursive copy.
pub fn copy(self: TypedValue, arena: Allocator) error{OutOfMemory}!TypedValue {
return TypedValue{
.ty = try self.ty.copy(arena),
.val = try self.val.copy(arena),
};
}
pub fn eql(a: TypedValue, b: TypedValue, target: std.Target) bool {
if (!a.ty.eql(b.ty, target)) return false;
return a.val.eql(b.val, a.ty, target);
}
pub fn hash(tv: TypedValue, hasher: *std.hash.Wyhash, target: std.Target) void {
return tv.val.hash(tv.ty, hasher, target);
}
pub fn enumToInt(tv: TypedValue, buffer: *Value.Payload.U64) Value {
return tv.val.enumToInt(tv.ty, buffer);
}
const max_aggregate_items = 100;
const FormatContext = struct {
tv: TypedValue,
target: Target,
};
pub fn format(
ctx: FormatContext,
comptime fmt: []const u8,
options: std.fmt.FormatOptions,
writer: anytype,
) !void {
_ = options;
comptime std.debug.assert(fmt.len == 0);
return ctx.tv.print(writer, 3, ctx.target);
}
/// Prints the Value according to the Type, not according to the Value Tag.
pub fn print(
tv: TypedValue,
writer: anytype,
level: u8,
target: std.Target,
) @TypeOf(writer).Error!void {
var val = tv.val;
var ty = tv.ty;
while (true) switch (val.tag()) {
.u1_type => return writer.writeAll("u1"),
.u8_type => return writer.writeAll("u8"),
.i8_type => return writer.writeAll("i8"),
.u16_type => return writer.writeAll("u16"),
.i16_type => return writer.writeAll("i16"),
.u32_type => return writer.writeAll("u32"),
.i32_type => return writer.writeAll("i32"),
.u64_type => return writer.writeAll("u64"),
.i64_type => return writer.writeAll("i64"),
.u128_type => return writer.writeAll("u128"),
.i128_type => return writer.writeAll("i128"),
.isize_type => return writer.writeAll("isize"),
.usize_type => return writer.writeAll("usize"),
.c_short_type => return writer.writeAll("c_short"),
.c_ushort_type => return writer.writeAll("c_ushort"),
.c_int_type => return writer.writeAll("c_int"),
.c_uint_type => return writer.writeAll("c_uint"),
.c_long_type => return writer.writeAll("c_long"),
.c_ulong_type => return writer.writeAll("c_ulong"),
.c_longlong_type => return writer.writeAll("c_longlong"),
.c_ulonglong_type => return writer.writeAll("c_ulonglong"),
.c_longdouble_type => return writer.writeAll("c_longdouble"),
.f16_type => return writer.writeAll("f16"),
.f32_type => return writer.writeAll("f32"),
.f64_type => return writer.writeAll("f64"),
.f80_type => return writer.writeAll("f80"),
.f128_type => return writer.writeAll("f128"),
.anyopaque_type => return writer.writeAll("anyopaque"),
.bool_type => return writer.writeAll("bool"),
.void_type => return writer.writeAll("void"),
.type_type => return writer.writeAll("type"),
.anyerror_type => return writer.writeAll("anyerror"),
.comptime_int_type => return writer.writeAll("comptime_int"),
.comptime_float_type => return writer.writeAll("comptime_float"),
.noreturn_type => return writer.writeAll("noreturn"),
.null_type => return writer.writeAll("@Type(.Null)"),
.undefined_type => return writer.writeAll("@Type(.Undefined)"),
.fn_noreturn_no_args_type => return writer.writeAll("fn() noreturn"),
.fn_void_no_args_type => return writer.writeAll("fn() void"),
.fn_naked_noreturn_no_args_type => return writer.writeAll("fn() callconv(.Naked) noreturn"),
.fn_ccc_void_no_args_type => return writer.writeAll("fn() callconv(.C) void"),
.single_const_pointer_to_comptime_int_type => return writer.writeAll("*const comptime_int"),
.anyframe_type => return writer.writeAll("anyframe"),
.const_slice_u8_type => return writer.writeAll("[]const u8"),
.const_slice_u8_sentinel_0_type => return writer.writeAll("[:0]const u8"),
.anyerror_void_error_union_type => return writer.writeAll("anyerror!void"),
.enum_literal_type => return writer.writeAll("@Type(.EnumLiteral)"),
.manyptr_u8_type => return writer.writeAll("[*]u8"),
.manyptr_const_u8_type => return writer.writeAll("[*]const u8"),
.manyptr_const_u8_sentinel_0_type => return writer.writeAll("[*:0]const u8"),
.atomic_order_type => return writer.writeAll("std.builtin.AtomicOrder"),
.atomic_rmw_op_type => return writer.writeAll("std.builtin.AtomicRmwOp"),
.calling_convention_type => return writer.writeAll("std.builtin.CallingConvention"),
.address_space_type => return writer.writeAll("std.builtin.AddressSpace"),
.float_mode_type => return writer.writeAll("std.builtin.FloatMode"),
.reduce_op_type => return writer.writeAll("std.builtin.ReduceOp"),
.call_options_type => return writer.writeAll("std.builtin.CallOptions"),
.prefetch_options_type => return writer.writeAll("std.builtin.PrefetchOptions"),
.export_options_type => return writer.writeAll("std.builtin.ExportOptions"),
.extern_options_type => return writer.writeAll("std.builtin.ExternOptions"),
.type_info_type => return writer.writeAll("std.builtin.Type"),
.empty_struct_value => return writer.writeAll(".{}"),
.aggregate => {
if (level == 0) {
return writer.writeAll(".{ ... }");
}
const vals = val.castTag(.aggregate).?.data;
if (ty.zigTypeTag() == .Struct) {
try writer.writeAll(".{ ");
const struct_fields = ty.structFields();
const max_len = std.math.min(struct_fields.count(), max_aggregate_items);
const field_names = struct_fields.keys();
const fields = struct_fields.values();
var i: u32 = 0;
while (i < max_len) : (i += 1) {
if (i != 0) try writer.writeAll(", ");
try writer.print(".{s} = ", .{field_names[i]});
try print(.{
.ty = fields[i].ty,
.val = vals[i],
}, writer, level - 1, target);
}
return writer.writeAll(" }");
} else {
try writer.writeAll(".{ ");
const elem_ty = ty.elemType2();
const max_len = std.math.min(ty.arrayLen(), max_aggregate_items);
var i: u32 = 0;
while (i < max_len) : (i += 1) {
if (i != 0) try writer.writeAll(", ");
try print(.{
.ty = elem_ty,
.val = vals[i],
}, writer, level - 1, target);
}
return writer.writeAll(" }");
}
},
.@"union" => {
if (level == 0) {
return writer.writeAll(".{ ... }");
}
const union_val = val.castTag(.@"union").?.data;
try writer.writeAll(".{ ");
try print(.{
.ty = ty.unionTagType().?,
.val = union_val.tag,
}, writer, level - 1, target);
try writer.writeAll(" = ");
try print(.{
.ty = ty.unionFieldType(union_val.tag, target),
.val = union_val.val,
}, writer, level - 1, target);
return writer.writeAll(" }");
},
.null_value => return writer.writeAll("null"),
.undef => return writer.writeAll("undefined"),
.zero => return writer.writeAll("0"),
.one => return writer.writeAll("1"),
.void_value => return writer.writeAll("{}"),
.unreachable_value => return writer.writeAll("unreachable"),
.the_only_possible_value => {
val = ty.onePossibleValue().?;
},
.bool_true => return writer.writeAll("true"),
.bool_false => return writer.writeAll("false"),
.ty => return val.castTag(.ty).?.data.print(writer, target),
.int_type => {
const int_type = val.castTag(.int_type).?.data;
return writer.print("{s}{d}", .{
if (int_type.signed) "s" else "u",
int_type.bits,
});
},
.int_u64 => return std.fmt.formatIntValue(val.castTag(.int_u64).?.data, "", .{}, writer),
.int_i64 => return std.fmt.formatIntValue(val.castTag(.int_i64).?.data, "", .{}, writer),
.int_big_positive => return writer.print("{}", .{val.castTag(.int_big_positive).?.asBigInt()}),
.int_big_negative => return writer.print("{}", .{val.castTag(.int_big_negative).?.asBigInt()}),
.lazy_align => {
const sub_ty = val.castTag(.lazy_align).?.data;
const x = sub_ty.abiAlignment(target);
return writer.print("{d}", .{x});
},
.function => return writer.print("(function '{s}')", .{val.castTag(.function).?.data.owner_decl.name}),
.extern_fn => return writer.writeAll("(extern function)"),
.variable => return writer.writeAll("(variable)"),
.decl_ref_mut => {
const decl = val.castTag(.decl_ref_mut).?.data.decl;
if (level == 0) {
return writer.print("(decl ref mut '{s}')", .{decl.name});
}
return print(.{
.ty = decl.ty,
.val = decl.val,
}, writer, level - 1, target);
},
.decl_ref => {
const decl = val.castTag(.decl_ref).?.data;
if (level == 0) {
return writer.print("(decl ref '{s}')", .{decl.name});
}
return print(.{
.ty = decl.ty,
.val = decl.val,
}, writer, level - 1, target);
},
.elem_ptr => {
const elem_ptr = val.castTag(.elem_ptr).?.data;
try writer.writeAll("&");
try print(.{
.ty = elem_ptr.elem_ty,
.val = elem_ptr.array_ptr,
}, writer, level - 1, target);
return writer.print("[{}]", .{elem_ptr.index});
},
.field_ptr => {
const field_ptr = val.castTag(.field_ptr).?.data;
try writer.writeAll("&");
try print(.{
.ty = field_ptr.container_ty,
.val = field_ptr.container_ptr,
}, writer, level - 1, target);
if (field_ptr.container_ty.zigTypeTag() == .Struct) {
const field_name = field_ptr.container_ty.structFields().keys()[field_ptr.field_index];
return writer.print(".{s}", .{field_name});
} else if (field_ptr.container_ty.zigTypeTag() == .Union) {
const field_name = field_ptr.container_ty.unionFields().keys()[field_ptr.field_index];
return writer.print(".{s}", .{field_name});
} else unreachable;
},
.empty_array => return writer.writeAll(".{}"),
.enum_literal => return writer.print(".{}", .{std.zig.fmtId(val.castTag(.enum_literal).?.data)}),
.enum_field_index => {
return writer.print(".{s}", .{ty.enumFieldName(val.castTag(.enum_field_index).?.data)});
},
.bytes => return writer.print("\"{}\"", .{std.zig.fmtEscapes(val.castTag(.bytes).?.data)}),
.repeated => {
if (level == 0) {
return writer.writeAll(".{ ... }");
}
var i: u32 = 0;
try writer.writeAll(".{ ");
const elem_tv = TypedValue{
.ty = ty.elemType2(),
.val = val.castTag(.repeated).?.data,
};
while (i < max_aggregate_items) : (i += 1) {
if (i != 0) try writer.writeAll(", ");
try print(elem_tv, writer, level - 1, target);
}
return writer.writeAll(" }");
},
.empty_array_sentinel => {
if (level == 0) {
return writer.writeAll(".{ (sentinel) }");
}
try writer.writeAll(".{ ");
try print(.{
.ty = ty.elemType2(),
.val = ty.sentinel().?,
}, writer, level - 1, target);
return writer.writeAll(" }");
},
.slice => return writer.writeAll("(slice)"),
.float_16 => return writer.print("{}", .{val.castTag(.float_16).?.data}),
.float_32 => return writer.print("{}", .{val.castTag(.float_32).?.data}),
.float_64 => return writer.print("{}", .{val.castTag(.float_64).?.data}),
.float_80 => return writer.print("{}", .{val.castTag(.float_80).?.data}),
.float_128 => return writer.print("{}", .{val.castTag(.float_128).?.data}),
.@"error" => return writer.print("error.{s}", .{val.castTag(.@"error").?.data.name}),
.eu_payload => {
val = val.castTag(.eu_payload).?.data;
},
.opt_payload => {
val = val.castTag(.opt_payload).?.data;
},
.eu_payload_ptr => {
try writer.writeAll("&");
val = val.castTag(.eu_payload_ptr).?.data.container_ptr;
},
.opt_payload_ptr => {
try writer.writeAll("&");
val = val.castTag(.opt_payload_ptr).?.data.container_ptr;
},
// TODO these should not appear in this function
.inferred_alloc => return writer.writeAll("(inferred allocation value)"),
.inferred_alloc_comptime => return writer.writeAll("(inferred comptime allocation value)"),
.bound_fn => {
const bound_func = val.castTag(.bound_fn).?.data;
return writer.print("(bound_fn %{}(%{})", .{ bound_func.func_inst, bound_func.arg0_inst });
},
.generic_poison_type => return writer.writeAll("(generic poison type)"),
.generic_poison => return writer.writeAll("(generic poison)"),
};
}