refactor and basic struct/union value implementation

This commit is contained in:
Techatrix 2023-01-06 14:12:29 +01:00
parent 4b4aafb8ee
commit f0c888188a
3 changed files with 179 additions and 148 deletions

View File

@ -289,7 +289,7 @@ pub fn interpret(
});
const container_scope = @intCast(u32, interpreter.scopes.len - 1);
var fields = std.StringArrayHashMapUnmanaged(InternPool.Struct.Field){};
var fields = std.ArrayListUnmanaged(InternPool.Struct.Field){};
var buffer: [2]Ast.Node.Index = undefined;
const members = ast.declMembers(tree, node_idx, &buffer);
@ -315,21 +315,20 @@ pub fn interpret(
continue;
}
const name = tree.tokenSlice(container_field.ast.main_token);
const field: InternPool.Struct.Field = .{
.name = tree.tokenSlice(container_field.ast.main_token),
.ty = init_type_value.val,
.default_value = default_value,
.alignent = 0, // TODO,
.is_comptime = false, // TODO
};
try fields.put(interpreter.arena.allocator(), name, field);
try fields.append(interpreter.arena.allocator(), field);
}
const struct_type = try interpreter.ip.get(interpreter.allocator, IPKey{
.struct_type = .{
.fields = fields,
.fields = fields.items,
.namespace = .none, // TODO
.layout = .Auto, // TODO
.backing_int_ty = .none, // TODO
@ -695,7 +694,7 @@ pub fn interpret(
.interpreter = interpreter,
.node_idx = node_idx,
.ty = try interpreter.ip.get(interpreter.allocator, IPKey{ .struct_type = .{
.fields = .{},
.fields = &.{},
.namespace = .none,
.layout = .Auto,
.backing_int_ty = IPIndex.none,
@ -715,7 +714,7 @@ pub fn interpret(
.interpreter = interpreter,
.node_idx = node_idx,
.ty = try interpreter.ip.get(interpreter.allocator, IPKey{ .simple = .type }),
.val = try interpreter.ip.get(interpreter.allocator, IPKey{ .type_value = undefined }), // TODO
.val = undefined, // TODO
},
};
}
@ -728,7 +727,7 @@ pub fn interpret(
.interpreter = interpreter,
.node_idx = node_idx,
.ty = try interpreter.ip.get(interpreter.allocator, IPKey{ .simple = .type }),
.val = try interpreter.ip.get(interpreter.allocator, IPKey{ .type_value = value.ty }),
.val = value.ty,
} };
}
@ -953,7 +952,7 @@ pub fn interpret(
.interpreter = interpreter,
.node_idx = node_idx,
.ty = pointer_type,
.val = try interpreter.ip.get(interpreter.allocator, IPKey{ .one_pointer = value.val }),
.val = value.val,
} };
},
.deref => {
@ -967,13 +966,11 @@ pub fn interpret(
return error.InvalidOperation;
}
// TODO: Check if this is a one_ptr or not
return InterpretResult{ .value = .{
.interpreter = interpreter,
.node_idx = node_idx,
.ty = type_key.pointer_type.elem_type,
.val = interpreter.ip.indexToKey(value.val).one_pointer,
.val = value.val,
} };
},
else => {

View File

@ -48,16 +48,17 @@ pub const Array = struct {
};
pub const Struct = struct {
fields: std.StringArrayHashMapUnmanaged(Field),
fields: []const Field,
namespace: NamespaceIndex,
layout: std.builtin.Type.ContainerLayout,
layout: std.builtin.Type.ContainerLayout = .Auto,
backing_int_ty: Index,
pub const Field = struct {
name: []const u8,
ty: Index,
default_value: Index,
alignent: u16,
is_comptime: bool,
default_value: Index = .none,
alignment: u16 = 0,
is_comptime: bool = false,
};
};
@ -76,31 +77,30 @@ pub const ErrorUnion = struct {
pub const ErrorSet = struct {
/// must be sorted
names: std.StringArrayHashMapUnmanaged(void),
names: [][]const u8,
pub fn sort(self: *ErrorSet) void {
const Context = struct {
keys: [][]const u8,
pub fn lessThan(ctx: @This(), a_index: usize, b_index: usize) bool {
return std.mem.lessThan(u8, ctx.keys[a_index], ctx.keys[b_index]);
}
};
self.names.sort(Context{ .keys = self.names.keys() });
std.sort.sort([][]const u8, self.names, u8, std.mem.lessThan);
}
};
pub const Enum = struct {
tag_type: Index,
fields: std.StringArrayHashMapUnmanaged(Index),
fields: []const Field,
namespace: NamespaceIndex,
tag_type_infered: bool,
pub const Field = struct {
name: []const u8,
ty: Index,
};
};
pub const Fn = struct {
calling_convention: std.builtin.CallingConvention,
alignment: u16,
is_generic: bool,
is_var_args: bool,
calling_convention: std.builtin.CallingConvention = .Unspecified,
alignment: u16 = 0,
is_generic: bool = false,
is_var_args: bool = false,
return_type: Index,
args: []const Param,
@ -114,20 +114,21 @@ pub const Fn = struct {
pub const Union = struct {
tag_type: Index,
fields: std.StringArrayHashMapUnmanaged(Field),
fields: []const Field,
namespace: NamespaceIndex,
layout: std.builtin.Type.ContainerLayout,
layout: std.builtin.Type.ContainerLayout = .Auto,
pub const Field = struct {
name: []const u8,
ty: Index,
alignment: u16,
};
};
pub const Tuple = struct {
types: []Index,
types: []const Index,
/// unreachable_value elements are used to indicate runtime-known.
values: []Index,
values: []const Index,
};
pub const Vector = struct {
@ -142,6 +143,15 @@ pub const Bytes = struct {
data: []const u8,
};
pub const Aggregate = struct {
data: []const Index,
};
pub const UnionValue = struct {
tag: Index,
val: Index,
};
pub const Key = union(enum) {
simple: Simple,
@ -168,10 +178,12 @@ pub const Key = union(enum) {
float_64_value: f64,
float_80_value: f80,
float_128_value: f128,
type_value: Index,
// type_value: Index,
bytes: Bytes,
one_pointer: Index,
// one_pointer: Index,
aggregate: Aggregate,
union_value: UnionValue,
// slice
// error
@ -184,54 +196,12 @@ pub const Key = union(enum) {
var hasher = std.hash.Wyhash.init(0);
std.hash.autoHash(&hasher, std.meta.activeTag(key));
switch (key) {
.struct_type => |struct_info| {
var field_it = struct_info.fields.iterator();
while (field_it.next()) |item| {
hasher.update(item.key_ptr.*);
std.hash.autoHash(&hasher, item.value_ptr.*);
}
std.hash.autoHash(&hasher, struct_info.layout);
},
// .error_type => |error_info| hasher.update(error_info.name),
.error_set_type => |error_set_info| {
const names = error_set_info.names.keys();
std.debug.assert(std.sort.isSorted([]const u8, names, u8, std.mem.lessThan));
for (names) |error_name| {
hasher.update(error_name);
}
},
.enum_type => |enum_info| {
std.hash.autoHash(&hasher, enum_info.tag_type);
var field_it = enum_info.fields.iterator();
while (field_it.next()) |item| {
hasher.update(item.key_ptr.*);
std.hash.autoHash(&hasher, item.value_ptr.*);
}
std.hash.autoHash(&hasher, enum_info.tag_type_infered);
},
.function_type => |function_info| std.hash.autoHashStrat(&hasher, function_info, .Deep),
.union_type => |union_info| {
std.hash.autoHash(&hasher, union_info.tag_type);
var field_it = union_info.fields.iterator();
while (field_it.next()) |item| {
hasher.update(item.key_ptr.*);
std.hash.autoHash(&hasher, item.value_ptr.*);
}
std.hash.autoHash(&hasher, union_info.layout);
},
.tuple_type => |tuple_info| std.hash.autoHashStrat(&hasher, tuple_info, .Deep),
.int_big_value => |big_int| {
std.hash.autoHash(&hasher, big_int.positive);
hasher.update(std.mem.sliceAsBytes(big_int.limbs));
},
.float_16_value => |f| std.hash.autoHash(&hasher, @bitCast(u16, f)),
.float_32_value => |f| std.hash.autoHash(&hasher, @bitCast(u32, f)),
.float_64_value => |f| std.hash.autoHash(&hasher, @bitCast(u64, f)),
.float_80_value => |f| std.hash.autoHash(&hasher, @bitCast(u80, f)),
.float_128_value => |f| std.hash.autoHash(&hasher, @bitCast(u128, f)),
.bytes => |bytes| hasher.update(bytes.data),
inline else => |info| std.hash.autoHash(&hasher, info), // TODO sad stage1 noises :(
inline else => |info| std.hash.autoHashStrat(&hasher, info, .Deep), // TODO sad stage1 noises :(
}
return @truncate(u32, hasher.final());
}
@ -244,17 +214,17 @@ pub const Key = union(enum) {
return switch (a) {
.struct_type => |struct_info| {
if (struct_info.layout != b.struct_type.layout) return false;
if (struct_info.fields.count() != b.struct_type.fields.count()) return false;
@panic("TODO: implement field equality check");
if (struct_info.fields.len != b.struct_type.fields.len) return false;
for (struct_info.fields) |field, i| {
if (!std.meta.eql(field, b.struct_type.fields[i])) return false;
}
return true;
},
// .error_type => |error_info| std.mem.eql(u8, error_info.name, b.error_type.name),
.error_set_type => |error_set_info| {
const a_names = error_set_info.names.keys();
const b_names = b.error_set_type.names.keys();
if (a_names.len != b_names.len) return false;
for (a_names) |a_name, i| {
const b_name = b_names[i];
if (error_set_info.names.len != b.error_set_type.names.len) return false;
for (error_set_info.names) |a_name, i| {
const b_name = b.error_set_type.names[i];
if (!std.mem.eql(u8, a_name, b_name)) return false;
}
return true;
@ -262,7 +232,7 @@ pub const Key = union(enum) {
.enum_type => |enum_info| {
if (enum_info.tag_type != b.enum_type.tag_type) return false;
if (enum_info.tag_type_infered != b.enum_type.tag_type_infered) return false;
if (enum_info.fields.count() != b.enum_type.fields.count()) return false;
if (enum_info.fields.len != b.enum_type.fields.len) return false;
@panic("TODO: implement field equality check");
},
.function_type => |function_info| {
@ -281,8 +251,11 @@ pub const Key = union(enum) {
.union_type => |union_info| {
if (union_info.tag_type != b.union_type.tag_type) return false;
if (union_info.layout != b.union_type.layout) return false;
if (union_info.fields.count() != b.union_type.fields.count()) return false;
@panic("TODO: implement union equality");
if (union_info.fields.len != b.union_type.fields.len) return false;
for (union_info.fields) |field, i| {
if (!std.meta.eql(field, b.union_type.fields[i])) return false;
}
return true;
},
.tuple_type => |tuple_info| {
std.debug.assert(tuple_info.types.len == tuple_info.values.len);
@ -296,6 +269,14 @@ pub const Key = union(enum) {
}
return true;
},
.bytes => |bytes| std.mem.eql(u8, bytes.data, b.bytes.data),
.aggregate => |aggregate| {
if (aggregate.data.len != b.aggregate.data.len) return false;
for (aggregate.data) |ty, i| {
if (ty != b.aggregate.data[i]) return false;
}
return true;
},
else => std.meta.eql(a, b),
};
}
@ -328,10 +309,12 @@ pub const Key = union(enum) {
.float_64_value => .float_f64,
.float_80_value => .float_f80,
.float_128_value => .float_f128,
.type_value => .type,
// .type_value => .type,
.bytes => .bytes,
.one_pointer => .one_pointer,
// .one_pointer => .one_pointer,
.aggregate => .aggregate,
.union_value => .union_value,
};
}
@ -402,11 +385,13 @@ pub const Key = union(enum) {
.float_64_value,
.float_80_value,
.float_128_value,
.type_value,
// .type_value,
=> unreachable,
.bytes,
.one_pointer,
// .one_pointer,
.aggregate,
.union_value,
=> unreachable,
};
}
@ -455,7 +440,6 @@ pub const Key = union(enum) {
/// Asserts the type is a fixed-size float or comptime_float.
/// Returns 128 for comptime_float types.
pub fn floatBits(ty: Key, target: std.Target) u16 {
std.debug.assert(ty == .simple);
_ = target;
return switch (ty.simple) {
.f16 => 16,
@ -464,31 +448,12 @@ pub const Key = union(enum) {
.f80 => 80,
.f128, .comptime_float => 128,
// TODO correctly resolve size based on `target`
.c_longdouble => 80,
.c_longdouble => @bitSizeOf(c_longdouble),
else => unreachable,
};
}
pub fn isCType(ty: Key) bool {
return switch (ty) {
.simple => |simple| switch (simple) {
.c_short,
.c_ushort,
.c_int,
.c_uint,
.c_long,
.c_ulong,
.c_longlong,
.c_ulonglong,
.c_longdouble,
=> true,
else => false,
},
else => false,
};
}
pub fn isConstPtr(ty: Key) bool {
return switch (ty) {
.pointer_type => |pointer_info| pointer_info.is_const,
@ -496,20 +461,11 @@ pub const Key = union(enum) {
};
}
pub fn isSlice(ty: Key) bool {
return switch (ty) {
.pointer_type => |pointer_info| pointer_info.size == .Slice,
else => false,
};
}
/// For pointer-like optionals, returns true, otherwise returns the allowzero property
/// of pointers.
pub fn ptrAllowsZero(ty: Key, ip: *const InternPool) bool {
if (ty.isPtrLikeOptional(ip)) {
return true;
}
return ty.pointer_type.is_allowzero;
if (ty.pointer_type.is_allowzero) return true;
return ty.isPtrLikeOptional(ip);
}
/// Returns true if the type is optional and would be lowered to a single pointer
@ -728,7 +684,21 @@ pub const Key = union(enum) {
try printType(function_info.return_type, ip, writer);
},
.union_type => @panic("TODO"),
.tuple_type => @panic("TODO"),
.tuple_type => |tuple_info| {
try writer.writeAll("tuple{");
for (tuple_info.types) |field_ty, i| {
if (i != 0) try writer.writeAll(", ");
const val = tuple_info.values[i];
if (val != Index.none) {
try writer.writeAll("comptime ");
}
try printType(field_ty, ip, writer);
if (val != Index.none) {
try writer.print(" = {}", .{val.fmtValue(field_ty, ip)});
}
}
try writer.writeByte('}');
},
.vector_type => |vector_info| {
try writer.print("@Vector({d},{})", .{
vector_info.len,
@ -746,9 +716,11 @@ pub const Key = union(enum) {
.float_128_value,
=> unreachable,
.type_value,
// .type_value,
.bytes,
.one_pointer,
// .one_pointer,
.aggregate,
.union_value,
=> unreachable,
}
}
@ -770,7 +742,6 @@ pub const Key = union(enum) {
ip: *const InternPool,
writer: anytype,
) @TypeOf(writer).Error!void {
_ = ty;
const value_key: Key = ip.indexToKey(value);
switch (value_key) {
.simple => |simple| switch (simple) {
@ -837,10 +808,32 @@ pub const Key = union(enum) {
.float_80_value => |float| try writer.print("{d}", .{@floatCast(f64, float)}),
.float_128_value => |float| try writer.print("{d}", .{@floatCast(f64, float)}),
.type_value,
.bytes,
.one_pointer,
=> unreachable,
// .type_value => |tty| tty.fmtType(ip),
.bytes => |data| try writer.print("\"{}\"", .{std.zig.fmtEscapes(data.data)}),
// .one_pointer => unreachable,
.aggregate => |aggregate| {
const struct_info = ip.indexToKey(ty).struct_type;
std.debug.assert(aggregate.data.len == struct_info.fields.len);
try writer.writeAll(".{");
var i: u32 = 0;
while (i < aggregate.data.len) : (i += 1) {
if (i != 0) try writer.writeAll(", ");
try writer.print(".{s} = ", .{struct_info.fields[i].name});
try printValue(aggregate.data[i], struct_info.fields[i].ty, ip, writer);
}
try writer.writeByte('}');
},
.union_value => |union_value| {
const union_info = ip.indexToKey(ty).union_type;
try writer.writeAll(".{ ");
try printValue(union_info.tag_type, union_value.tag, ip, writer);
try writer.writeAll(" = ");
try printValue(union_value.val, @panic("TODO"), ip, writer);
try writer.writeAll(" }");
},
}
}
};
@ -962,16 +955,22 @@ pub const Tag = enum(u8) {
/// A float value that can be represented by f128.
/// data is payload to f128.
float_f128,
/// A type value.
/// data is Index.
type,
// /// A type value.
// /// data is Index.
// type,
/// A byte sequence value.
/// data is payload to data begin and length.
bytes,
/// A single pointer value.
/// data is index to value.
one_pointer,
// /// A single pointer value.
// /// data is index to value.
// one_pointer,
/// A aggregate (struct) value.
/// data is index to Aggregate.
aggregate,
/// A union value.
/// data is index to UnionValue.
union_value,
};
pub const Simple = enum(u32) {
@ -1060,10 +1059,10 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
.float_f64 => .{ .float_64_value = ip.extraData(f64, data) },
.float_f80 => .{ .float_80_value = ip.extraData(f80, data) },
.float_f128 => .{ .float_128_value = ip.extraData(f128, data) },
.type => .{ .type_value = @intToEnum(Index, data) },
// .type => .{ .type_value = @intToEnum(Index, data) },
.bytes => unreachable, // TODO
.one_pointer => .{ .one_pointer = @intToEnum(Index, data) },
// .one_pointer => .{ .one_pointer = @intToEnum(Index, data) },
else => @panic("TODO"),
};
}
@ -1099,9 +1098,9 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
},
.float_16_value => |float_val| .{ .tag = .float_f16, .data = @bitCast(u16, float_val) },
.float_32_value => |float_val| .{ .tag = .float_f32, .data = @bitCast(u32, float_val) },
.type_value => |ty| .{ .tag = .type, .data = @enumToInt(ty) },
// .type_value => |ty| .{ .tag = .type, .data = @enumToInt(ty) },
.bytes => unreachable, // TODO
.one_pointer => |val| .{ .tag = .one_pointer, .data = @enumToInt(val) },
// .one_pointer => |val| .{ .tag = .one_pointer, .data = @enumToInt(val) },
inline else => |data| .{ .tag = key.tag(), .data = try ip.addExtra(gpa, data) }, // TODO sad stage1 noises :(
};
try ip.items.append(gpa, item);
@ -2454,6 +2453,42 @@ test "array type" {
try testExpectFmtType(&ip, u32_0_0_array_type, "[3:0]u32");
}
test "struct type" {
const gpa = std.testing.allocator;
var ip: InternPool = .{};
defer ip.deinit(gpa);
const i32_type = try ip.get(gpa, .{ .int_type = .{ .signedness = .signed, .bits = 32 } });
const u64_type = try ip.get(gpa, .{ .int_type = .{ .signedness = .unsigned, .bits = 64 } });
const bool_type = try ip.get(gpa, .{ .simple = .bool });
const field1 = Struct.Field{ .name = "foo", .ty = u64_type };
const field2 = Struct.Field{ .name = "bar", .ty = i32_type };
const field3 = Struct.Field{ .name = "baz", .ty = bool_type };
const struct_type_0 = try ip.get(gpa, Key{
.struct_type = Struct{
.fields = &.{ field1, field2, field3 },
.namespace = .none,
.layout = .Auto,
.backing_int_ty = .none,
},
});
_ = try ip.get(gpa, .{ .simple = .unreachable_value });
const struct_type_1 = try ip.get(gpa, Key{
.struct_type = Struct{
.fields = &.{ field1, field2, field3 },
.namespace = .none,
.layout = .Auto,
.backing_int_ty = .none,
},
});
std.debug.assert(struct_type_0 == struct_type_1);
}
test "resolvePeerTypes" {
const gpa = std.testing.allocator;

View File

@ -586,12 +586,11 @@ fn typeToCompletion(
switch (key) {
.struct_type => |struct_info| {
var field_it = struct_info.fields.iterator();
while (field_it.next()) |entry| {
for (struct_info.fields) |field| {
try list.append(allocator, .{
.label = entry.key_ptr.*,
.label = field.name,
.kind = .Field,
.insertText = entry.key_ptr.*,
.insertText = field.name,
.insertTextFormat = .PlainText,
});
}