diff --git a/src/ComptimeInterpreter.zig b/src/ComptimeInterpreter.zig index a9c9c2b..83f4264 100644 --- a/src/ComptimeInterpreter.zig +++ b/src/ComptimeInterpreter.zig @@ -9,6 +9,7 @@ const ast = @import("ast.zig"); const zig = std.zig; const Ast = zig.Ast; const analysis = @import("analysis.zig"); +const offsets = @import("offsets.zig"); const DocumentStore = @import("DocumentStore.zig"); pub const InternPool = @import("InternPool.zig"); @@ -26,6 +27,8 @@ ip: InternPool = .{}, document_store: *DocumentStore, uri: DocumentStore.Uri, scopes: std.MultiArrayList(Scope) = .{}, +decls: std.ArrayListUnmanaged(Decl) = .{}, +namespaces: std.MultiArrayList(Namespace) = .{}, /// Interpreter diagnostic errors errors: std.AutoArrayHashMapUnmanaged(Ast.Node.Index, InterpreterError) = .{}, @@ -56,10 +59,15 @@ pub fn deinit(interpreter: *ComptimeInterpreter) void { interpreter.ip.deinit(interpreter.allocator); var i: usize = 0; - while (i < interpreter.scopes.len) : (i += 1) { - interpreter.scopes.items(.child_scopes)[i].deinit(interpreter.allocator); + while (i < interpreter.namespaces.len) : (i += 1) { + interpreter.namespaces.items(.decls)[i].deinit(interpreter.allocator); + interpreter.namespaces.items(.usingnamespaces)[i].deinit(interpreter.allocator); } + interpreter.namespaces.deinit(interpreter.allocator); + interpreter.decls.deinit(interpreter.allocator); interpreter.scopes.deinit(interpreter.allocator); + + interpreter.arena.deinit(); } pub const Type = struct { @@ -77,6 +85,27 @@ pub const Value = struct { val: IPIndex, }; +pub const Decl = struct { + name: []const u8, + ty: IPIndex, + val: IPIndex, + alignment: u16, + address_space: std.builtin.AddressSpace, + is_pub: bool, + is_exported: bool, +}; + +pub const NamespaceIndex = InternPool.NamespaceIndex; + +pub const Namespace = struct { + /// always points to Namespace or Index.none + parent: NamespaceIndex, + /// Will be a struct, enum, union, or opaque. + // ty: Index, + decls: std.StringArrayHashMapUnmanaged(Decl) = .{}, + usingnamespaces: std.ArrayListUnmanaged(NamespaceIndex) = .{}, +}; + // pub const Comptimeness = enum { @"comptime", runtime }; pub const Scope = struct { @@ -87,8 +116,7 @@ pub const Scope = struct { parent: u32, // zero indicates root scope node_idx: Ast.Node.Index, - namespace: IPIndex, - child_scopes: std.ArrayListUnmanaged(u32) = .{}, + namespace: NamespaceIndex, pub const ScopeKind = enum { container, block, function }; pub fn scopeKind(scope: Scope) ScopeKind { @@ -177,22 +205,19 @@ fn getDeclCount(tree: Ast, node_idx: Ast.Node.Index) usize { pub fn huntItDown( interpreter: *ComptimeInterpreter, - namespace: IPIndex, + namespace: NamespaceIndex, decl_name: []const u8, options: InterpretOptions, -) InterpretError!InternPool.Decl { +) InterpretError!Decl { _ = options; var current_namespace = namespace; - while (current_namespace != IPIndex.none) { - const namespace_info = interpreter.ip.indexToKey(current_namespace).namespace; - defer current_namespace = namespace_info.parent; + while (current_namespace != .none) { + const decls: std.StringArrayHashMapUnmanaged(Decl) = interpreter.namespaces.items(.decls)[@enumToInt(current_namespace)]; + defer current_namespace = interpreter.namespaces.items(.parent)[@enumToInt(current_namespace)]; - for (namespace_info.decls) |decl_index| { - const decl_info = interpreter.ip.indexToKey(decl_index).declaration; - if (std.mem.eql(u8, decl_info.name, decl_name)) { - return decl_info; - } + if (decls.get(decl_name)) |decl| { + return decl; } } @@ -260,45 +285,37 @@ pub fn interpret( .interpreter = interpreter, .parent = scope, .node_idx = node_idx, - .namespace = IPIndex.none, // declarations have not been resolved yet + .namespace = .none, // declarations have not been resolved yet }); const container_scope = @intCast(u32, interpreter.scopes.len - 1); var fields = std.StringArrayHashMapUnmanaged(InternPool.Struct.Field){}; - defer fields.deinit(interpreter.allocator); var buffer: [2]Ast.Node.Index = undefined; const members = ast.declMembers(tree, node_idx, &buffer); for (members) |member| { - const maybe_container_field: ?zig.Ast.full.ContainerField = switch (tags[member]) { - .container_field => tree.containerField(member), - .container_field_align => tree.containerFieldAlign(member), - .container_field_init => tree.containerFieldInit(member), - else => null, - }; - - const field_info = maybe_container_field orelse { + const container_field = ast.containerField(tree, member) orelse { _ = try interpreter.interpret(member, container_scope, options); continue; }; - var init_type_value = try (try interpreter.interpret(field_info.ast.type_expr, container_scope, .{})).getValue(); + var init_type_value = try (try interpreter.interpret(container_field.ast.type_expr, container_scope, .{})).getValue(); - var default_value = if (field_info.ast.value_expr == 0) + var default_value = if (container_field.ast.value_expr == 0) IPIndex.none else - (try (try interpreter.interpret(field_info.ast.value_expr, container_scope, .{})).getValue()).val; // TODO check ty + (try (try interpreter.interpret(container_field.ast.value_expr, container_scope, .{})).getValue()).val; // TODO check ty if (init_type_value.ty != type_type) { try interpreter.recordError( - field_info.ast.type_expr, + container_field.ast.type_expr, "expected_type", try std.fmt.allocPrint(interpreter.allocator, "expected type 'type', found '{}'", .{init_type_value.ty.fmtType(&interpreter.ip)}), ); continue; } - const name = tree.tokenSlice(field_info.ast.main_token); + const name = tree.tokenSlice(container_field.ast.main_token); const field: InternPool.Struct.Field = .{ .ty = init_type_value.val, @@ -310,21 +327,12 @@ pub fn interpret( try fields.put(interpreter.arena.allocator(), name, field); } - const namespace = try interpreter.ip.get(interpreter.allocator, IPKey{ - .namespace = .{ - .parent = IPIndex.none, - // .ty = struct_type, - .decls = undefined, // TODO, - .usingnamespaces = &.{}, - }, - }); - const struct_type = try interpreter.ip.get(interpreter.allocator, IPKey{ .struct_type = .{ .fields = fields, - .namespace = namespace, // TODO - .layout = std.builtin.Type.ContainerLayout.Auto, // TODO - .backing_int_ty = IPIndex.none, // TODO + .namespace = .none, // TODO + .layout = .Auto, // TODO + .backing_int_ty = .none, // TODO }, }); @@ -372,7 +380,7 @@ pub fn interpret( .interpreter = interpreter, .parent = scope, .node_idx = node_idx, - .namespace = IPIndex.none, + .namespace = .none, }); const block_scope = @intCast(u32, interpreter.scopes.len - 1); @@ -493,7 +501,7 @@ pub fn interpret( var ir = try interpreter.interpret(data[node_idx].lhs, scope, options); var irv = try ir.getValue(); - const namespace = interpreter.ip.indexToKey(irv.val).getNamespace() orelse return error.IdentifierNotFound; + const namespace = interpreter.ip.indexToKey(irv.val).getNamespace(); var scope_sub_decl = irv.interpreter.huntItDown(namespace, rhs_str, options) catch |err| { if (err == error.IdentifierNotFound) try interpreter.recordError( @@ -688,7 +696,7 @@ pub fn interpret( .node_idx = node_idx, .ty = try interpreter.ip.get(interpreter.allocator, IPKey{ .struct_type = .{ .fields = .{}, - .namespace = IPIndex.none, + .namespace = .none, .layout = .Auto, .backing_int_ty = IPIndex.none, } }), @@ -735,15 +743,13 @@ 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 namespace_index = interpreter.ip.indexToKey(value.val).getNamespace() orelse return error.InvalidBuiltin; - const namespace = interpreter.ip.indexToKey(namespace_index).namespace; + const namespace = interpreter.ip.indexToKey(value.val).getNamespace(); + if (namespace == .none) return error.InvalidBuiltin; const name = interpreter.ip.indexToKey(field_name.val).bytes.data; // TODO add checks - const has_decl = for (namespace.decls) |decl| { - const decl_name = interpreter.ip.indexToKey(decl).declaration.name; - if (std.mem.eql(u8, decl_name, name)) break true; - } else false; + const decls = interpreter.namespaces.items(.decls)[@enumToInt(namespace)]; + const has_decl = decls.contains(name); return InterpretResult{ .value = Value{ .interpreter = interpreter, @@ -812,24 +818,22 @@ pub fn interpret( .@"comptime" => { return try interpreter.interpret(data[node_idx].lhs, scope, .{}); }, - // .fn_proto, - // .fn_proto_multi, - // .fn_proto_one, - // .fn_proto_simple, - .fn_decl => { - // var buf: [1]Ast.Node.Index = undefined; - // const func = ast.fnProto(tree, node_idx, &buf).?; + .fn_proto, .fn_proto_multi, .fn_proto_one, .fn_proto_simple, .fn_decl => { + var buf: [1]Ast.Node.Index = undefined; + const func = ast.fnProto(tree, node_idx, &buf).?; // TODO: Resolve function type - // const function_type = try interpreter.ip.get(interpreter.allocator, IPKey{ .function_type = .{ - // .calling_convention = .Unspecified, - // .alignment = 0, - // .is_generic = false, - // .is_var_args = false, - // .return_type = IPIndex.none, - // .args = &.{}, - // } }); + const type_type = try interpreter.ip.get(interpreter.allocator, IPKey{ .simple = .type }); + + const function_type = try interpreter.ip.get(interpreter.allocator, IPKey{ .function_type = .{ + .calling_convention = .Unspecified, + .alignment = 0, + .is_generic = false, + .is_var_args = false, + .return_type = IPIndex.none, + .args = &.{}, + } }); // var it = func.iterate(&tree); // while (ast.nextFnParam(&it)) |param| { @@ -855,21 +859,21 @@ pub fn interpret( // if ((try interpreter.interpret(func.ast.return_type, func_scope_idx, .{ .observe_values = true, .is_comptime = true })).maybeGetValue()) |value| // fnd.return_type = value.value_data.@"type"; - // var value = Value{ - // .interpreter = interpreter, - // .node_idx = node_idx, - // .ty = function_type, - // .val = IPIndex.none, // TODO - // }; + const name = offsets.tokenToSlice(tree, func.name_token.?); - // const name = analysis.getDeclName(tree, node_idx).?; - // var namespace = interpreter.ip.indexToKey(scope.?.namespace).namespace; - // try namespace.decls.put(interpreter.allocator, name, .{ - // .scope = scope.?, - // .node_idx = node_idx, - // .name = name, - // .value = value, - // }); + const namespace = interpreter.scopes.items(.namespace)[scope]; + if (namespace != .none) { + const decls = &interpreter.namespaces.items(.decls)[@enumToInt(namespace)]; + try decls.put(interpreter.allocator, name, .{ + .name = name, + .ty = type_type, + .val = function_type, + .alignment = 0, // TODO + .address_space = .generic, // TODO + .is_pub = false, // TODO + .is_exported = false, // TODO + }); + } return InterpretResult{ .nothing = {} }; }, @@ -889,7 +893,7 @@ pub fn interpret( defer args.deinit(interpreter.allocator); for (call_full.ast.params) |param| { - try args.append(interpreter.allocator, try (try interpreter.interpret(param, scope, .{})).getValue()); + args.appendAssumeCapacity(try (try interpreter.interpret(param, scope, .{})).getValue()); } const func_id_result = try interpreter.interpret(call_full.ast.fn_expr, scope, .{}); @@ -1008,7 +1012,7 @@ pub fn call( .interpreter = interpreter, .parent = scope, .node_idx = func_node_idx, - .namespace = IPIndex.none, + .namespace = .none, }); const fn_scope = @intCast(u32, interpreter.scopes.len - 1); diff --git a/src/InternPool.zig b/src/InternPool.zig index c872517..ad16f92 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -519,8 +519,8 @@ pub const Key = union(enum) { .optional_type => |optional_info| { const child_ty = optional_info.payload_type; const child_key = ip.indexToKey(child_ty); - if(child_key != .pointer_type) return false; - const info = child_key.pointer_type; + if (child_key != .pointer_type) return false; + const info = child_key.pointer_type; switch (info.size) { .Slice, .C => return false, .Many, .One => return !info.is_allowzero, @@ -533,7 +533,7 @@ pub const Key = union(enum) { pub fn elemType2(ty: Key) Index { return switch (ty) { - .simple => |simple| switch(simple) { + .simple => |simple| switch (simple) { .@"anyframe" => @panic("TODO: return void type"), else => unreachable, }, @@ -1544,7 +1544,7 @@ pub fn resolvePeerTypes(ip: *InternPool, gpa: Allocator, types: []const Index, t return Index.none; } - if(chosen == .none) return chosen; + if (chosen == .none) return chosen; const chosen_key = ip.indexToKey(chosen); if (convert_to_slice) { @@ -2163,7 +2163,7 @@ fn coerceInMemoryAllowedPtrs( const ok_cv_qualifiers = (!src_info.is_const or dest_info.is_const) and (!src_info.is_volatile or dest_info.is_volatile); - + if (!ok_cv_qualifiers) { return InMemoryCoercionResult{ .ptr_qualifiers = .{ .actual_const = src_info.is_const, @@ -2188,7 +2188,7 @@ fn coerceInMemoryAllowedPtrs( .wanted = dest_info.elem_type, } }; } - + const dest_allow_zero = dest_ptr_info.ptrAllowsZero(ip); const src_allow_zero = src_ptr_info.ptrAllowsZero(ip); @@ -2199,7 +2199,7 @@ fn coerceInMemoryAllowedPtrs( .wanted = dest_ty, } }; } - + // if (src_info.host_size != dest_info.host_size or // src_info.bit_offset != dest_info.bit_offset) // { @@ -2214,8 +2214,8 @@ fn coerceInMemoryAllowedPtrs( const ok_sent = dest_info.sentinel == .none or src_info.size == .C or dest_info.sentinel == src_info.sentinel; // is this enough for a value equality check? if (!ok_sent) { return InMemoryCoercionResult{ .ptr_sentinel = .{ - .actual = if(src_info.sentinel != .none) src_info.sentinel else try ip.get(gpa, .{.simple = .unreachable_value}), - .wanted = if(dest_info.sentinel != .none) dest_info.sentinel else try ip.get(gpa, .{.simple = .unreachable_value}), + .actual = if (src_info.sentinel != .none) src_info.sentinel else try ip.get(gpa, .{ .simple = .unreachable_value }), + .wanted = if (dest_info.sentinel != .none) dest_info.sentinel else try ip.get(gpa, .{ .simple = .unreachable_value }), .ty = dest_info.elem_type, } }; } @@ -2227,11 +2227,10 @@ fn coerceInMemoryAllowedPtrs( alignment: { if (src_info.alignment == 0 and dest_info.alignment == 0 and dest_info.elem_type == src_info.elem_type // is this enough for a value equality check? - ) - { + ) { break :alignment; } - + // const src_align = if (src_info.alignment != 0) // src_info.alignment // else @@ -2394,7 +2393,7 @@ test "pointer type" { .size = .One, .is_const = true, } }); - + try std.testing.expect(const_u32_pointer_type != u32_pointer_type); try testExpectFmtType(&ip, i32_pointer_type_0, "*i32");