do not intern Structs, Enums and Unions

This commit is contained in:
Techatrix 2023-01-28 18:02:29 +01:00
parent 9131285db1
commit 55364f2e2b
5 changed files with 240 additions and 284 deletions

View File

@ -23,7 +23,6 @@ allocator: std.mem.Allocator,
ip: InternPool = .{},
document_store: *DocumentStore,
uri: DocumentStore.Uri,
decls: std.ArrayListUnmanaged(Decl) = .{},
namespaces: std.MultiArrayList(Namespace) = .{},
/// Interpreter diagnostic errors
@ -69,7 +68,6 @@ pub fn deinit(interpreter: *ComptimeInterpreter) void {
interpreter.namespaces.items(.usingnamespaces)[i].deinit(interpreter.allocator);
}
interpreter.namespaces.deinit(interpreter.allocator);
interpreter.decls.deinit(interpreter.allocator);
}
pub const Type = struct {
@ -86,29 +84,18 @@ pub const Value = struct {
ty: Index,
val: Index,
};
pub const Decl = struct {
name: []const u8,
ty: Index,
val: Index,
alignment: u16,
address_space: std.builtin.AddressSpace,
is_pub: bool,
is_exported: bool,
};
// pub const Comptimeness = enum { @"comptime", runtime };
pub const NamespaceIndex = InternPool.NamespaceIndex;
pub const Namespace = struct {
/// always points to Namespace or Index.none
parent: NamespaceIndex,
parent: Namespace.Index,
node_idx: Ast.Node.Index,
/// Will be a struct, enum, union, opaque or .none
ty: Index,
decls: std.StringArrayHashMapUnmanaged(Decl) = .{},
usingnamespaces: std.ArrayListUnmanaged(NamespaceIndex) = .{},
ty: InternPool.Index,
decls: std.StringArrayHashMapUnmanaged(InternPool.DeclIndex) = .{},
usingnamespaces: std.ArrayListUnmanaged(InternPool.DeclIndex) = .{},
pub const Index = InternPool.NamespaceIndex;
// TODO: Actually use this value
// comptimeness: Comptimeness,
@ -161,15 +148,15 @@ pub const InterpretResult = union(enum) {
pub fn huntItDown(
interpreter: *ComptimeInterpreter,
namespace: NamespaceIndex,
namespace: Namespace.Index,
decl_name: []const u8,
options: InterpretOptions,
) ?Decl {
) ?InternPool.DeclIndex {
_ = options;
var current_namespace = namespace;
while (current_namespace != .none) {
const decls: std.StringArrayHashMapUnmanaged(Decl) = interpreter.namespaces.items(.decls)[@enumToInt(current_namespace)];
const decls = interpreter.namespaces.items(.decls)[@enumToInt(current_namespace)];
defer current_namespace = interpreter.namespaces.items(.parent)[@enumToInt(current_namespace)];
if (decls.get(decl_name)) |decl| {
@ -199,7 +186,7 @@ pub const InterpretError = std.mem.Allocator.Error || std.fmt.ParseIntError || s
pub fn interpret(
interpreter: *ComptimeInterpreter,
node_idx: Ast.Node.Index,
namespace: NamespaceIndex,
namespace: Namespace.Index,
options: InterpretOptions,
) InterpretError!InterpretResult {
const tree = interpreter.getHandle().tree;
@ -229,10 +216,16 @@ pub fn interpret(
.node_idx = node_idx,
.ty = undefined,
});
const container_namespace = @intToEnum(NamespaceIndex, interpreter.namespaces.len - 1);
const container_namespace = @intToEnum(Namespace.Index, interpreter.namespaces.len - 1);
var fields = std.ArrayListUnmanaged(InternPool.Struct.Field){};
defer fields.deinit(interpreter.allocator);
const struct_index = try interpreter.ip.createStruct(interpreter.allocator, .{
.fields = .{},
.namespace = container_namespace,
.layout = .Auto, // TODO
.backing_int_ty = .none, // TODO
.status = .none, // TODO
});
var struct_info = interpreter.ip.getStruct(struct_index);
var buffer: [2]Ast.Node.Index = undefined;
@ -259,28 +252,18 @@ pub fn interpret(
);
continue;
}
const field_name = try interpreter.ip.get(interpreter.allocator, .{
.bytes = tree.tokenSlice(container_field.ast.main_token),
});
const field: InternPool.Struct.Field = .{
.name = field_name,
const field_name = tree.tokenSlice(container_field.ast.main_token);
try struct_info.fields.put(interpreter.allocator, field_name, .{
.ty = init_type_value.val,
.default_value = default_value,
.alignment = 0, // TODO,
.is_comptime = false, // TODO
};
try fields.append(interpreter.allocator, field);
});
}
const struct_type = try interpreter.ip.get(interpreter.allocator, Key{
.struct_type = .{
.fields = fields.items,
.namespace = namespace,
.layout = .Auto, // TODO
.backing_int_ty = .none, // TODO
},
});
const struct_type = try interpreter.ip.get(interpreter.allocator, Key{ .struct_type = struct_index }); // TODO potential double free on struct_info.field
interpreter.namespaces.items(.ty)[@enumToInt(container_namespace)] = struct_type;
return InterpretResult{ .value = Value{
@ -317,7 +300,7 @@ pub fn interpret(
if (v.ty != type_type) return InterpretResult{ .nothing = {} };
}
try decls.putNoClobber(interpreter.allocator, name, .{
const decl_index = try interpreter.ip.createDecl(interpreter.allocator, .{
.name = name,
.ty = if (type_value) |v| v.val else init_value.?.ty,
.val = if (init_value) |init| init.val else .none,
@ -326,6 +309,7 @@ pub fn interpret(
.is_pub = true, // TODO
.is_exported = false, // TODO
});
try decls.putNoClobber(interpreter.allocator, name, decl_index);
// TODO: Am I a dumbo shrimp? (e.g. is this tree shaking correct? works on my machine so like...)
@ -345,7 +329,7 @@ pub fn interpret(
.node_idx = node_idx,
.ty = .none,
});
const block_namespace = @intToEnum(NamespaceIndex, interpreter.namespaces.len - 1);
const block_namespace = @intToEnum(Namespace.Index, interpreter.namespaces.len - 1);
var buffer: [2]Ast.Node.Index = undefined;
const statements = ast.blockStatements(tree, node_idx, &buffer).?;
@ -442,7 +426,8 @@ pub fn interpret(
}
// Logic to find identifiers in accessible scopes
if (interpreter.huntItDown(namespace, identifier, options)) |decl| {
if (interpreter.huntItDown(namespace, identifier, options)) |decl_index| {
const decl = interpreter.ip.getDecl(decl_index);
return InterpretResult{ .value = Value{
.interpreter = interpreter,
.node_idx = node_idx,
@ -478,7 +463,8 @@ pub fn interpret(
if (irv.val == .none) break :blk true;
const ty_key = interpreter.ip.indexToKey(irv.val);
if (interpreter.huntItDown(ty_key.getNamespace(), field_name, options)) |decl| {
if (interpreter.huntItDown(ty_key.getNamespace(interpreter.ip), field_name, options)) |decl_index| {
const decl = interpreter.ip.getDecl(decl_index);
return InterpretResult{ .value = Value{
.interpreter = interpreter,
.node_idx = node_idx,
@ -492,19 +478,18 @@ pub fn interpret(
_ = error_set_info;
},
.union_type => {}, // TODO
.enum_type => |enum_info| { // TODO
if (interpreter.ip.contains(Key{ .bytes = field_name })) |field_name_index| {
for (enum_info.fields) |field| {
if (field.name != field_name_index) continue;
return InterpretResult{
.value = Value{
.interpreter = interpreter,
.node_idx = data[node_idx].rhs,
.ty = irv.val,
.val = .none, // TODO resolve enum value
},
};
}
.enum_type => |enum_index| { // TODO
const enum_info = interpreter.ip.getEnum(enum_index);
if (enum_info.fields.get(field_name)) |field| {
_ = field;
return InterpretResult{
.value = Value{
.interpreter = interpreter,
.node_idx = data[node_idx].rhs,
.ty = irv.val,
.val = .none, // TODO resolve enum value
},
};
}
},
else => break :blk false,
@ -583,17 +568,15 @@ pub fn interpret(
} };
}
},
.struct_type => |struct_info| blk: {
// if the intern pool does not contain the field name, it is impossible that there is a field with the given name
const field_name_index = interpreter.ip.contains(Key{ .bytes = field_name }) orelse break :blk true;
for (struct_info.fields) |field, i| {
if (field.name != field_name_index) continue;
.struct_type => |struct_index| blk: {
const struct_info = interpreter.ip.getStruct(struct_index);
if (struct_info.fields.getIndex(field_name)) |field_index| {
const field = struct_info.fields.values()[field_index];
const val = found_val: {
if (irv.val == .none) break :found_val .none;
const val_key = interpreter.ip.indexToKey(irv.val);
if (val_key != .aggregate) break :found_val .none;
break :found_val val_key.aggregate[i];
break :found_val val_key.aggregate[field_index];
};
return InterpretResult{ .value = Value{
@ -813,15 +796,17 @@ pub fn interpret(
// TODO: Implement root support
if (std.mem.eql(u8, import_str[1 .. import_str.len - 1], "root")) {
const struct_index = try interpreter.ip.createStruct(interpreter.allocator, .{
.fields = .{},
.namespace = .none,
.layout = .Auto,
.backing_int_ty = .none,
.status = .none,
});
return InterpretResult{ .value = Value{
.interpreter = interpreter,
.node_idx = node_idx,
.ty = try interpreter.ip.get(interpreter.allocator, Key{ .struct_type = .{
.fields = &.{},
.namespace = .none,
.layout = .Auto,
.backing_int_ty = .none,
} }),
.ty = try interpreter.ip.get(interpreter.allocator, Key{ .struct_type = struct_index }),
.val = try interpreter.ip.get(interpreter.allocator, Key{ .simple = .undefined_value }),
} };
}
@ -865,7 +850,7 @@ pub fn interpret(
if (value.ty != type_type) return error.InvalidBuiltin;
if (interpreter.ip.indexToKey(field_name.ty) != .pointer_type) return error.InvalidBuiltin; // Check if it's a []const u8
const value_namespace = interpreter.ip.indexToKey(value.val).getNamespace();
const value_namespace = interpreter.ip.indexToKey(value.val).getNamespace(interpreter.ip);
if (value_namespace == .none) return error.InvalidBuiltin;
const name = interpreter.ip.indexToKey(field_name.val).bytes; // TODO add checks
@ -986,7 +971,8 @@ pub fn interpret(
if (namespace != .none) {
const decls = &interpreter.namespaces.items(.decls)[@enumToInt(namespace)];
try decls.put(interpreter.allocator, name, .{
const decl_index = try interpreter.ip.createDecl(interpreter.allocator, .{
.name = name,
.ty = type_type,
.val = function_type,
@ -995,6 +981,7 @@ pub fn interpret(
.is_pub = false, // TODO
.is_exported = false, // TODO
});
try decls.putNoClobber(interpreter.allocator, name, decl_index);
}
return InterpretResult{ .nothing = {} };
@ -1107,7 +1094,7 @@ pub fn interpret(
}
pub const CallResult = struct {
namespace: NamespaceIndex,
namespace: Namespace.Index,
result: union(enum) {
value: Value,
nothing,
@ -1116,7 +1103,7 @@ pub const CallResult = struct {
pub fn call(
interpreter: *ComptimeInterpreter,
namespace: NamespaceIndex,
namespace: Namespace.Index,
func_node_idx: Ast.Node.Index,
arguments: []const Value,
options: InterpretOptions,
@ -1136,7 +1123,7 @@ pub fn call(
.node_idx = func_node_idx,
.ty = .none,
});
const fn_namespace = @intToEnum(NamespaceIndex, interpreter.namespaces.len - 1);
const fn_namespace = @intToEnum(Namespace.Index, interpreter.namespaces.len - 1);
const type_type = try interpreter.ip.get(interpreter.allocator, Key{ .simple = .type });
@ -1157,7 +1144,8 @@ pub fn call(
if (param.name_token) |name_token| {
const name = offsets.tokenToSlice(tree, name_token);
try interpreter.namespaces.items(.decls)[@enumToInt(fn_namespace)].put(interpreter.allocator, name, .{
const decls = &interpreter.namespaces.items(.decls)[@enumToInt(fn_namespace)];
const decl_index = try interpreter.ip.createDecl(interpreter.allocator, .{
.name = name,
.ty = tex.val,
.val = arguments[arg_index].val,
@ -1166,6 +1154,7 @@ pub fn call(
.is_pub = true, // TODO
.is_exported = false, // TODO
});
try decls.putNoClobber(interpreter.allocator, name, decl_index);
arg_index += 1;
}
}

View File

@ -4,6 +4,11 @@ map: std.AutoArrayHashMapUnmanaged(void, void) = .{},
items: std.MultiArrayList(Item) = .{},
extra: std.ArrayListUnmanaged(u8) = .{},
decls: std.ArrayListUnmanaged(InternPool.Decl) = .{},
structs: std.ArrayListUnmanaged(InternPool.Struct) = .{},
enums: std.ArrayListUnmanaged(InternPool.Enum) = .{},
unions: std.ArrayListUnmanaged(InternPool.Union) = .{},
const InternPool = @This();
const std = @import("std");
const builtin = @import("builtin");
@ -36,15 +41,26 @@ pub const Array = packed struct {
sentinel: Index = .none,
};
pub const FieldStatus = enum {
none,
field_types_wip,
have_field_types,
layout_wip,
have_layout,
fully_resolved_wip,
fully_resolved,
};
pub const StructIndex = enum(u32) { _ };
pub const Struct = struct {
fields: []const Field,
fields: std.StringArrayHashMapUnmanaged(Field),
namespace: NamespaceIndex,
layout: std.builtin.Type.ContainerLayout = .Auto,
backing_int_ty: Index,
status: FieldStatus,
pub const Field = packed struct {
/// guaranteed to be .bytes
name: Index,
ty: Index,
default_value: Index = .none,
alignment: u16 = 0,
@ -66,17 +82,14 @@ pub const ErrorSet = struct {
names: []const Index,
};
pub const EnumIndex = enum(u32) { _ };
pub const Enum = struct {
tag_type: Index,
fields: []const Field,
fields: std.StringArrayHashMapUnmanaged(void),
values: std.AutoArrayHashMapUnmanaged(Index, void),
namespace: NamespaceIndex,
tag_type_infered: bool,
pub const Field = packed struct {
/// guaranteed to be .bytes
name: Index,
val: Index,
};
};
pub const Function = struct {
@ -94,15 +107,16 @@ pub const Function = struct {
is_var_args: bool = false,
};
pub const UnionIndex = enum(u32) { _ };
pub const Union = struct {
tag_type: Index,
fields: []const Field,
fields: std.StringArrayHashMapUnmanaged(Field),
namespace: NamespaceIndex,
layout: std.builtin.Type.ContainerLayout = .Auto,
status: FieldStatus,
pub const Field = packed struct {
/// guaranteed to be .bytes
name: Index,
ty: Index,
alignment: u16,
};
@ -134,19 +148,34 @@ pub const UnionValue = packed struct {
val: Index,
};
pub const DeclIndex = enum(u32) { _ };
pub const Decl = struct {
name: []const u8,
ty: Index,
val: Index,
alignment: u16,
address_space: std.builtin.AddressSpace,
is_pub: bool,
is_exported: bool,
};
pub const Key = union(enum) {
simple: Simple,
int_type: Int,
pointer_type: Pointer,
array_type: Array,
struct_type: Struct,
/// TODO consider *Struct instead of StructIndex
struct_type: StructIndex,
optional_type: Optional,
error_union_type: ErrorUnion,
error_set_type: ErrorSet,
enum_type: Enum,
/// TODO consider *Enum instead of EnumIndex
enum_type: EnumIndex,
function_type: Function,
union_type: Union,
/// TODO consider *Union instead of UnionIndex
union_type: UnionIndex,
tuple_type: Tuple,
vector_type: Vector,
anyframe_type: AnyFrame,
@ -396,7 +425,8 @@ pub const Key = union(enum) {
},
.int_type => |int_info| return int_info,
.enum_type => return panicOrElse("TODO", .{ .signedness = .unsigned, .bits = 0 }),
.struct_type => |struct_info| {
.struct_type => |struct_index| {
const struct_info = ip.getStruct(struct_index);
assert(struct_info.layout == .Packed);
key = ip.indexToKey(struct_info.backing_int_ty);
},
@ -485,11 +515,11 @@ pub const Key = union(enum) {
};
}
pub fn getNamespace(ty: Key) NamespaceIndex {
pub fn getNamespace(ty: Key, ip: InternPool) NamespaceIndex {
return switch (ty) {
.struct_type => |struct_info| struct_info.namespace,
.enum_type => |enum_info| enum_info.namespace,
.union_type => |union_info| union_info.namespace,
.struct_type => |struct_index| ip.getStruct(struct_index).namespace,
.enum_type => |enum_index| ip.getEnum(enum_index).namespace,
.union_type => |union_index| ip.getUnion(union_index).namespace,
else => .none,
};
}
@ -555,10 +585,12 @@ pub const Key = union(enum) {
}
return null;
},
.struct_type => |struct_info| {
for (struct_info.fields) |field| {
if (field.is_comptime) continue;
if (ip.indexToKey(field.ty).onePossibleValue(ip) != null) continue;
.struct_type => |struct_index| {
const struct_info = ip.getStruct(struct_index);
var field_it = struct_info.fields.iterator();
while (field_it.next()) |entry| {
if (entry.value_ptr.is_comptime) continue;
if (ip.indexToKey(entry.value_ptr.ty).onePossibleValue(ip) != null) continue;
return null;
}
return panicOrElse("TODO return empty struct value", null);
@ -572,10 +604,11 @@ pub const Key = union(enum) {
},
.error_union_type => return null,
.error_set_type => return null,
.enum_type => |enum_info| {
switch (enum_info.fields.len) {
.enum_type => |enum_index| {
const enum_info = ip.getEnum(enum_index);
switch (enum_info.fields.count()) {
0 => return Key{ .simple = .unreachable_value },
1 => return ip.indexToKey(enum_info.fields[0].val),
1 => return ip.indexToKey(enum_info.values.keys()[0]),
else => return null,
}
},
@ -623,11 +656,7 @@ pub const Key = union(enum) {
ip: InternPool,
};
// TODO implement options
pub const FormatOptions = struct {
include_fields: bool = true,
include_declarations: bool = true,
};
pub const FormatOptions = struct {};
fn formatType(
ctx: TypeFormatContext,
@ -925,27 +954,27 @@ pub const Key = union(enum) {
.bytes => |bytes| try writer.print("\"{}\"", .{std.zig.fmtEscapes(bytes)}),
.aggregate => |aggregate| {
const struct_info = ip.indexToKey(ty).struct_type;
assert(aggregate.len == struct_info.fields.len);
const struct_info = ip.getStruct(ip.indexToKey(ty).struct_type);
assert(aggregate.len == struct_info.fields.count());
try writer.writeAll(".{");
var i: u32 = 0;
while (i < aggregate.len) : (i += 1) {
if (i != 0) try writer.writeAll(", ");
const field_name = ip.indexToKey(struct_info.fields[i].name).bytes;
const field_name = struct_info.fields.keys()[i];
try writer.print(".{s} = ", .{field_name});
try printValue(ip.indexToKey(aggregate[i]), struct_info.fields[i].ty, ip, writer);
try printValue(ip.indexToKey(aggregate[i]), struct_info.fields.values()[i].ty, ip, writer);
}
try writer.writeByte('}');
},
.union_value => |union_value| {
const union_info = ip.indexToKey(ty).union_type;
const union_info = ip.getUnion(ip.indexToKey(ty).union_type);
const name = ip.indexToKey(union_info.fields[union_value.field_index].name).bytes;
const name = union_info.fields.keys()[union_value.field_index];
try writer.print(".{{ .{} = {} }}", .{
std.zig.fmtId(name),
union_value.val.fmtValue(union_info.fields[union_value.field_index].ty, ip),
union_value.val.fmtValue(union_info.fields.values()[union_value.field_index].ty, ip),
});
},
}
@ -978,6 +1007,7 @@ pub const Item = struct {
/// Two values which have the same type can be equality compared simply
/// by checking if their indexes are equal, provided they are both in
/// the same `InternPool`.
/// TODO split this into an Optional and non-Optional Index
pub const Index = enum(u32) {
none = std.math.maxInt(u32),
_,
@ -1181,6 +1211,21 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void {
ip.map.deinit(gpa);
ip.items.deinit(gpa);
ip.extra.deinit(gpa);
for (ip.structs.items) |*item| {
item.fields.deinit(gpa);
}
for (ip.enums.items) |*item| {
item.fields.deinit(gpa);
item.values.deinit(gpa);
}
for (ip.unions.items) |*item| {
item.fields.deinit(gpa);
}
ip.decls.deinit(gpa);
ip.structs.deinit(gpa);
ip.enums.deinit(gpa);
ip.unions.deinit(gpa);
}
pub fn indexToKey(ip: InternPool, index: Index) Key {
@ -1199,17 +1244,18 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
} },
.type_pointer => .{ .pointer_type = ip.extraData(Pointer, data) },
.type_array => .{ .array_type = ip.extraData(Array, data) },
.type_struct => .{ .struct_type = ip.extraData(Struct, data) },
.type_optional => .{ .optional_type = .{ .payload_type = @intToEnum(Index, data) } },
.type_anyframe => .{ .anyframe_type = .{ .child = @intToEnum(Index, data) } },
.type_error_union => .{ .error_union_type = ip.extraData(ErrorUnion, data) },
.type_error_set => .{ .error_set_type = ip.extraData(ErrorSet, data) },
.type_enum => .{ .enum_type = ip.extraData(Enum, data) },
.type_function => .{ .function_type = ip.extraData(Function, data) },
.type_union => .{ .union_type = ip.extraData(Union, data) },
.type_tuple => .{ .tuple_type = ip.extraData(Tuple, data) },
.type_vector => .{ .vector_type = ip.extraData(Vector, data) },
.type_struct => .{ .struct_type = @intToEnum(StructIndex, data) },
.type_enum => .{ .enum_type = @intToEnum(EnumIndex, data) },
.type_union => .{ .union_type = @intToEnum(UnionIndex, data) },
.int_u32 => .{ .int_u64_value = @intCast(u32, data) },
.int_i32 => .{ .int_i64_value = @bitCast(i32, data) },
.int_u64 => .{ .int_u64_value = ip.extraData(u64, data) },
@ -1248,6 +1294,10 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
.optional_type => |optional_ty| @enumToInt(optional_ty.payload_type),
.anyframe_type => |anyframe_ty| @enumToInt(anyframe_ty.child),
.struct_type => |struct_index| @enumToInt(struct_index),
.enum_type => |enum_index| @enumToInt(enum_index),
.union_type => |union_index| @enumToInt(union_index),
.int_u64_value => |int_val| if (tag == .int_u32) @intCast(u32, int_val) else try ip.addExtra(gpa, int_val),
.int_i64_value => |int_val| if (tag == .int_i32) @bitCast(u32, @intCast(u32, int_val)) else try ip.addExtra(gpa, int_val),
.int_big_value => |big_int_val| try ip.addExtra(gpa, big_int_val.limbs),
@ -1270,6 +1320,36 @@ pub fn contains(ip: InternPool, key: Key) ?Index {
return @intToEnum(Index, index);
}
pub fn getDecl(ip: *InternPool, index: InternPool.DeclIndex) *InternPool.Decl {
return &ip.decls.items[@enumToInt(index)];
}
pub fn getStruct(ip: InternPool, index: InternPool.StructIndex) *InternPool.Struct {
return &ip.structs.items[@enumToInt(index)];
}
pub fn getEnum(ip: InternPool, index: InternPool.EnumIndex) *InternPool.Enum {
return &ip.enums.items[@enumToInt(index)];
}
pub fn getUnion(ip: InternPool, index: InternPool.UnionIndex) *InternPool.Union {
return &ip.unions.items[@enumToInt(index)];
}
pub fn createDecl(ip: *InternPool, gpa: Allocator, decl: InternPool.Decl) error{OutOfMemory}!InternPool.DeclIndex {
try ip.decls.append(gpa, decl);
return @intToEnum(InternPool.DeclIndex, ip.decls.items.len - 1);
}
pub fn createStruct(ip: *InternPool, gpa: Allocator, struct_info: InternPool.Struct) error{OutOfMemory}!InternPool.StructIndex {
try ip.structs.append(gpa, struct_info);
return @intToEnum(InternPool.StructIndex, ip.structs.items.len - 1);
}
pub fn createEnum(ip: *InternPool, gpa: Allocator, enum_info: InternPool.Enum) error{OutOfMemory}!InternPool.EnumIndex {
try ip.enums.append(gpa, enum_info);
return @intToEnum(InternPool.EnumIndex, ip.enums.items.len - 1);
}
pub fn createUnion(ip: *InternPool, gpa: Allocator, union_info: InternPool.Union) error{OutOfMemory}!InternPool.UnionIndex {
try ip.unions.append(gpa, union_info);
return @intToEnum(InternPool.UnionIndex, ip.unions.items.len - 1);
}
fn addExtra(ip: *InternPool, gpa: Allocator, extra: anytype) Allocator.Error!u32 {
const T = @TypeOf(extra);
comptime if (@sizeOf(T) <= 4) {
@ -2997,41 +3077,6 @@ 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 foo_name = try ip.get(gpa, .{ .bytes = "foo" });
const bar_name = try ip.get(gpa, .{ .bytes = "bar" });
const baz_name = try ip.get(gpa, .{ .bytes = "baz" });
const field1 = Struct.Field{ .name = foo_name, .ty = u64_type };
const field2 = Struct.Field{ .name = bar_name, .ty = i32_type };
const field3 = Struct.Field{ .name = baz_name, .ty = bool_type };
const struct_type_0 = try ip.get(gpa, .{ .struct_type = .{
.fields = &.{ field1, field2, field3 },
.namespace = .none,
.layout = .Auto,
.backing_int_ty = .none,
} });
const struct_type_1 = try ip.get(gpa, .{ .struct_type = .{
.fields = &.{ field1, field2, field3 },
.namespace = .none,
.layout = .Auto,
.backing_int_ty = .none,
} });
try std.testing.expect(struct_type_0 == struct_type_1);
}
test "struct value" {
const gpa = std.testing.allocator;
@ -3041,18 +3086,17 @@ test "struct value" {
const i32_type = try ip.get(gpa, .{ .int_type = .{ .signedness = .signed, .bits = 32 } });
const bool_type = try ip.get(gpa, .{ .simple = .bool });
const foo_name = try ip.get(gpa, .{ .bytes = "foo" });
const bar_name = try ip.get(gpa, .{ .bytes = "bar" });
const field1 = Struct.Field{ .name = foo_name, .ty = i32_type };
const field2 = Struct.Field{ .name = bar_name, .ty = bool_type };
const struct_type = try ip.get(gpa, .{ .struct_type = .{
.fields = &.{ field1, field2 },
const struct_index = try ip.createStruct(gpa, .{
.fields = .{},
.namespace = .none,
.layout = .Auto,
.backing_int_ty = .none,
} });
.status = .none,
});
const struct_type = try ip.get(gpa, .{ .struct_type = struct_index });
const struct_info = ip.getStruct(struct_index);
try struct_info.fields.put(gpa, "foo", .{ .ty = i32_type });
try struct_info.fields.put(gpa, "bar", .{ .ty = bool_type });
const one_value = try ip.get(gpa, .{ .int_i64_value = 1 });
const true_value = try ip.get(gpa, .{ .simple = .bool_true });
@ -3062,50 +3106,6 @@ test "struct value" {
try ip.testExpectFmtValue(aggregate_value, struct_type, ".{.foo = 1, .bar = true}");
}
test "enum type" {
const gpa = std.testing.allocator;
var ip: InternPool = .{};
defer ip.deinit(gpa);
const zig_name = try ip.get(gpa, .{ .bytes = "zig" });
const cpp_name = try ip.get(gpa, .{ .bytes = "cpp" });
const empty_enum1 = try ip.get(gpa, .{ .enum_type = .{
.tag_type = .none,
.fields = &.{},
.namespace = .none,
.tag_type_infered = true,
} });
const empty_enum2 = try ip.get(gpa, .{ .enum_type = .{
.tag_type = .none,
.fields = &.{},
.namespace = .none,
.tag_type_infered = true,
} });
const field1 = Enum.Field{ .name = zig_name, .val = .none };
const field2 = Enum.Field{ .name = cpp_name, .val = .none };
const enum1 = try ip.get(gpa, .{ .enum_type = .{
.tag_type = .none,
.fields = &.{ field1, field2 },
.namespace = .none,
.tag_type_infered = true,
} });
const enum2 = try ip.get(gpa, .{ .enum_type = .{
.tag_type = .none,
.fields = &.{ field2, field1 },
.namespace = .none,
.tag_type_infered = true,
} });
try std.testing.expect(empty_enum1 == empty_enum2);
try std.testing.expect(empty_enum2 != enum1);
try std.testing.expect(enum1 != enum2);
}
test "function type" {
const gpa = std.testing.allocator;
@ -3152,40 +3152,6 @@ test "function type" {
try testExpectFmtType(ip, @"fn() align(4) callconv(.C) type", "fn() align(4) callconv(.C) type");
}
test "union type" {
const gpa = std.testing.allocator;
var ip: InternPool = .{};
defer ip.deinit(gpa);
const u32_type = try ip.get(gpa, .{ .int_type = .{ .signedness = .unsigned, .bits = 32 } });
const void_type = try ip.get(gpa, .{ .simple = .void });
const ok_name = try ip.get(gpa, .{ .bytes = "Ok" });
const err_name = try ip.get(gpa, .{ .bytes = "Err" });
var field1 = Union.Field{ .name = ok_name, .ty = u32_type, .alignment = 0 };
var field2 = Union.Field{ .name = err_name, .ty = void_type, .alignment = 0 };
const union_type1 = try ip.get(gpa, .{
.union_type = .{
.tag_type = .none,
.fields = &.{ field1, field2 },
.namespace = .none,
},
});
const union_type2 = try ip.get(gpa, .{
.union_type = .{
.tag_type = .none,
.fields = &.{ field2, field1 },
.namespace = .none,
},
});
try std.testing.expect(union_type1 != union_type2);
}
test "union value" {
const gpa = std.testing.allocator;
@ -3198,19 +3164,17 @@ test "union value" {
const int_value = try ip.get(gpa, .{ .int_u64_value = 1 });
const f16_value = try ip.get(gpa, .{ .float_16_value = 0.25 });
const int_name = try ip.get(gpa, .{ .bytes = "int" });
const float_name = try ip.get(gpa, .{ .bytes = "float" });
var field1 = Union.Field{ .name = int_name, .ty = u32_type, .alignment = 0 };
var field2 = Union.Field{ .name = float_name, .ty = f16_type, .alignment = 0 };
const union_type = try ip.get(gpa, .{
.union_type = .{
.tag_type = .none,
.fields = &.{ field1, field2 },
.namespace = .none,
},
const union_index = try ip.createUnion(gpa, .{
.tag_type = .none,
.fields = .{},
.namespace = .none,
.layout = .Auto,
.status = .none,
});
const union_type = try ip.get(gpa, .{ .union_type = union_index });
const union_info = ip.getUnion(union_index);
try union_info.fields.put(gpa, "int", .{ .ty = u32_type, .alignment = 0 });
try union_info.fields.put(gpa, "float", .{ .ty = f16_type, .alignment = 0 });
const union_value1 = try ip.get(gpa, .{ .union_value = .{
.field_index = 0,

View File

@ -24,7 +24,7 @@ pub fn dotCompletions(
.simple => |simple| switch (simple) {
.type => {
const ty_key = ip.indexToKey(val);
const namespace = ty_key.getNamespace();
const namespace = ty_key.getNamespace(ip.*);
if (namespace != .none) {
// TODO lookup in namespace
}
@ -40,11 +40,12 @@ pub fn dotCompletions(
}
},
.union_type => {}, // TODO
.enum_type => |enum_info| {
for (enum_info.fields) |field| {
const field_name = ip.indexToKey(field.name).bytes;
.enum_type => |enum_index| {
const enum_info = ip.getEnum(enum_index);
var field_it = enum_info.fields.iterator();
while (field_it.next()) |entry| {
try completions.append(arena, .{
.label = field_name,
.label = entry.key_ptr.*,
.kind = .Constant,
// include field.val?
});
@ -85,14 +86,15 @@ pub fn dotCompletions(
.detail = try std.fmt.allocPrint(arena, "usize ({d})", .{array_info.len}), // TODO how should this be displayed
});
},
.struct_type => |struct_info| {
for (struct_info.fields) |field| {
const field_name = ip.indexToKey(field.name).bytes;
.struct_type => |struct_index| {
const struct_info = ip.getStruct(struct_index);
var field_it = struct_info.fields.iterator();
while (field_it.next()) |entry| {
try completions.append(arena, types.CompletionItem{
.label = field_name,
.label = entry.key_ptr.*,
.kind = .Field,
// TODO include alignment and comptime
.detail = try std.fmt.allocPrint(arena, "{}", .{field.ty.fmtType(ip.*)}),
.detail = try std.fmt.allocPrint(arena, "{}", .{entry.value_ptr.ty.fmtType(ip.*)}),
});
}
},
@ -103,26 +105,28 @@ pub fn dotCompletions(
.detail = try std.fmt.allocPrint(arena, "{}", .{optional_info.payload_type.fmtType(ip.*)}),
});
},
.enum_type => |enum_info| {
for (enum_info.fields) |field| {
const field_name = ip.indexToKey(field.name).bytes;
.enum_type => |enum_index| {
const enum_info = ip.getEnum(enum_index);
for (enum_info.fields.keys()) |field_name, i| {
const field_val = enum_info.values.keys()[i];
try completions.append(arena, .{
.label = field_name,
.kind = .Field,
.detail = try std.fmt.allocPrint(arena, "{}", .{field.val.fmtValue(enum_info.tag_type, ip.*)}),
.detail = try std.fmt.allocPrint(arena, "{}", .{field_val.fmtValue(enum_info.tag_type, ip.*)}),
});
}
},
.union_type => |union_info| {
for (union_info.fields) |field| {
const field_name = ip.indexToKey(field.name).bytes;
.union_type => |union_index| {
const union_info = ip.getUnion(union_index);
var field_it = union_info.fields.iterator();
while (field_it.next()) |entry| {
try completions.append(arena, .{
.label = field_name,
.label = entry.key_ptr.*,
.kind = .Field,
.detail = if (field.alignment != 0)
try std.fmt.allocPrint(arena, "align({d}) {}", .{ field.alignment, field.ty.fmtType(ip.*) })
.detail = if (entry.value_ptr.alignment != 0)
try std.fmt.allocPrint(arena, "align({d}) {}", .{ entry.value_ptr.alignment, entry.value_ptr.ty.fmtType(ip.*) })
else
try std.fmt.allocPrint(arena, "{}", .{field.ty.fmtType(ip.*)}),
try std.fmt.allocPrint(arena, "{}", .{entry.value_ptr.ty.fmtType(ip.*)}),
});
}
},

View File

@ -772,7 +772,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, arena: *std.heap.ArenaAl
};
var interpreter: *ComptimeInterpreter = handle.interpreter.?;
const root_namespace = @intToEnum(ComptimeInterpreter.NamespaceIndex, 0);
const root_namespace = @intToEnum(ComptimeInterpreter.Namespace.Index, 0);
// TODO: Start from current/nearest-current scope
const result = interpreter.interpret(node, root_namespace, .{}) catch |err| {

View File

@ -169,16 +169,15 @@ test "ComptimeInterpreter - call return struct" {
try std.testing.expect(result.ty == .simple);
try std.testing.expect(result.ty.simple == .type);
const struct_info = result.val.?.struct_type;
const struct_info = context.interpreter.ip.getStruct(result.val.?.struct_type);
try std.testing.expectEqual(Index.none, struct_info.backing_int_ty);
try std.testing.expectEqual(std.builtin.Type.ContainerLayout.Auto, struct_info.layout);
const field_name = context.interpreter.ip.indexToKey(struct_info.fields[0].name).bytes;
const bool_type = try context.interpreter.ip.get(allocator, .{ .simple = .bool });
try std.testing.expectEqual(@as(usize, 1), struct_info.fields.len);
try std.testing.expectEqualStrings("slay", field_name);
try std.testing.expect(struct_info.fields[0].ty == bool_type);
try std.testing.expectEqual(@as(usize, 1), struct_info.fields.count());
try std.testing.expectEqualStrings("slay", struct_info.fields.keys()[0]);
try std.testing.expect(struct_info.fields.values()[0].ty == bool_type);
}
test "ComptimeInterpreter - call comptime argument" {
@ -284,7 +283,7 @@ const Context = struct {
};
}
const namespace = @intToEnum(ComptimeInterpreter.NamespaceIndex, 0); // root namespace
const namespace = @intToEnum(ComptimeInterpreter.Namespace.Index, 0); // root namespace
const result = (try self.interpreter.call(namespace, func_node, args, .{})).result;
try std.testing.expect(result == .value);
@ -297,7 +296,7 @@ const Context = struct {
}
pub fn interpret(self: *Context, node: Ast.Node.Index) !KV {
const namespace = @intToEnum(ComptimeInterpreter.NamespaceIndex, 0); // root namespace
const namespace = @intToEnum(ComptimeInterpreter.Namespace.Index, 0); // root namespace
const result = try (try self.interpreter.interpret(node, namespace, .{})).getValue();
try std.testing.expect(result.ty != .none);