diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig index ab81c3415e..40541ea7c1 100644 --- a/lib/std/zig/ast.zig +++ b/lib/std/zig/ast.zig @@ -2834,10 +2834,12 @@ pub const Node = struct { /// `(lhs)`. main_token is the `(`; rhs is the token index of the `)`. grouped_expression, /// `@a(lhs, rhs)`. lhs and rhs may be omitted. + /// main_token is the builtin token. builtin_call_two, /// Same as builtin_call_two but there is known to be a trailing comma before the rparen. builtin_call_two_comma, /// `@a(b, c)`. `sub_list[lhs..rhs]`. + /// main_token is the builtin token. builtin_call, /// Same as builtin_call but there is known to be a trailing comma before the rparen. builtin_call_comma, diff --git a/src/Module.zig b/src/Module.zig index a1c2822732..2071ff671c 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -428,14 +428,14 @@ pub const Scope = struct { } /// Asserts the scope is a child of a File and has an AST tree and returns the tree. - pub fn tree(self: *Scope) *ast.Tree { + pub fn tree(self: *Scope) *const ast.Tree { switch (self.tag) { - .file => return self.cast(File).?.contents.tree, - .block => return self.cast(Block).?.src_decl.container.file_scope.contents.tree, - .gen_zir => return self.cast(GenZIR).?.decl.container.file_scope.contents.tree, - .local_val => return self.cast(LocalVal).?.gen_zir.decl.container.file_scope.contents.tree, - .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.container.file_scope.contents.tree, - .container => return self.cast(Container).?.file_scope.contents.tree, + .file => return self.cast(File).?.tree, + .block => return self.cast(Block).?.src_decl.container.file_scope.tree, + .gen_zir => return self.cast(GenZIR).?.decl.container.file_scope.tree, + .local_val => return self.cast(LocalVal).?.gen_zir.decl.container.file_scope.tree, + .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.container.file_scope.tree, + .container => return self.cast(Container).?.file_scope.tree, } } @@ -1008,38 +1008,38 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool { switch (node_tags[fn_proto]) { .fn_proto_simple => { var params: [1]ast.Node.Index = undefined; - return mod.astgenAndSemaFn(decl, tree, body, tree.fnProtoSimple(¶ms, fn_proto)); + return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoSimple(¶ms, fn_proto)); }, - .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree, body, tree.fnProtoMulti(fn_proto)), + .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoMulti(fn_proto)), .fn_proto_one => { var params: [1]ast.Node.Index = undefined; - return mod.astgenAndSemaFn(decl, tree, body, tree.fnProtoOne(¶ms, fn_proto)); + return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProtoOne(¶ms, fn_proto)); }, - .fn_proto => return mod.astgenAndSemaFn(decl, tree, body, tree.fnProto(fn_proto)), + .fn_proto => return mod.astgenAndSemaFn(decl, tree.*, body, tree.fnProto(fn_proto)), else => unreachable, } }, .fn_proto_simple => { var params: [1]ast.Node.Index = undefined; - return mod.astgenAndSemaFn(decl, tree, null, tree.fnProtoSimple(¶ms, decl_node)); + return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoSimple(¶ms, decl_node)); }, - .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree, null, tree.fnProtoMulti(decl_node)), + .fn_proto_multi => return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoMulti(decl_node)), .fn_proto_one => { var params: [1]ast.Node.Index = undefined; - return mod.astgenAndSemaFn(decl, tree, null, tree.fnProtoOne(¶ms, decl_node)); + return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProtoOne(¶ms, decl_node)); }, - .fn_proto => return mod.astgenAndSemaFn(decl, tree, null, tree.fnProto(decl_node)), + .fn_proto => return mod.astgenAndSemaFn(decl, tree.*, 0, tree.fnProto(decl_node)), - .global_var_decl => return mod.astgenAndSemaVarDecl(decl, tree, tree.globalVarDecl(decl_node)), - .local_var_decl => return mod.astgenAndSemaVarDecl(decl, tree, tree.localVarDecl(decl_node)), - .simple_var_decl => return mod.astgenAndSemaVarDecl(decl, tree, tree.simpleVarDecl(decl_node)), - .aligned_var_decl => return mod.astgenAndSemaVarDecl(decl, tree, tree.alignedVarDecl(decl_node)), + .global_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.globalVarDecl(decl_node)), + .local_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.localVarDecl(decl_node)), + .simple_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.simpleVarDecl(decl_node)), + .aligned_var_decl => return mod.astgenAndSemaVarDecl(decl, tree.*, tree.alignedVarDecl(decl_node)), .@"comptime" => { decl.analysis = .in_progress; // A comptime decl does not store any value so we can just deinit this arena after analysis is done. - var analysis_arena = std.heap.ArenaAllocator.init(self.gpa); + var analysis_arena = std.heap.ArenaAllocator.init(mod.gpa); defer analysis_arena.deinit(); var gen_scope: Scope.GenZIR = .{ .decl = decl, @@ -1047,14 +1047,15 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool { .parent = &decl.container.base, .force_comptime = true, }; - defer gen_scope.instructions.deinit(self.gpa); + defer gen_scope.instructions.deinit(mod.gpa); - _ = try astgen.comptimeExpr(self, &gen_scope.base, .none, comptime_decl.expr); - if (std.builtin.mode == .Debug and self.comp.verbose_ir) { - zir.dumpZir(self.gpa, "comptime_block", decl.name, gen_scope.instructions.items) catch {}; + const block_expr = node_datas[decl_node].lhs; + _ = try astgen.comptimeExpr(mod, &gen_scope.base, .none, block_expr); + if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { + zir.dumpZir(mod.gpa, "comptime_block", decl.name, gen_scope.instructions.items) catch {}; } - var inst_table = Scope.Block.InstTable.init(self.gpa); + var inst_table = Scope.Block.InstTable.init(mod.gpa); defer inst_table.deinit(); var branch_quota: u32 = default_eval_branch_quota; @@ -1071,17 +1072,17 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool { .is_comptime = true, .branch_quota = &branch_quota, }; - defer block_scope.instructions.deinit(self.gpa); + defer block_scope.instructions.deinit(mod.gpa); - _ = try zir_sema.analyzeBody(self, &block_scope, .{ + _ = try zir_sema.analyzeBody(mod, &block_scope, .{ .instructions = gen_scope.instructions.items, }); decl.analysis = .complete; - decl.generation = self.generation; + decl.generation = mod.generation; return true; }, - .UsingNamespace => @panic("TODO usingnamespace decl"), + .@"usingnamespace" => @panic("TODO usingnamespace decl"), else => unreachable, } } @@ -1099,18 +1100,20 @@ fn astgenAndSemaFn( decl.analysis = .in_progress; const token_starts = tree.tokens.items(.start); + const token_tags = tree.tokens.items(.tag); // This arena allocator's memory is discarded at the end of this function. It is used // to determine the type of the function, and hence the type of the decl, which is needed // to complete the Decl analysis. - var fn_type_scope_arena = std.heap.ArenaAllocator.init(self.gpa); + var fn_type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa); defer fn_type_scope_arena.deinit(); var fn_type_scope: Scope.GenZIR = .{ .decl = decl, .arena = &fn_type_scope_arena.allocator, .parent = &decl.container.base, + .force_comptime = true, }; - defer fn_type_scope.instructions.deinit(self.gpa); + defer fn_type_scope.instructions.deinit(mod.gpa); decl.is_pub = fn_proto.visib_token != null; @@ -1126,7 +1129,7 @@ fn astgenAndSemaFn( }; const param_types = try fn_type_scope.arena.alloc(*zir.Inst, param_count); const fn_src = token_starts[fn_proto.ast.fn_token]; - const type_type = try astgen.addZIRInstConst(self, &fn_type_scope.base, fn_src, .{ + const type_type = try astgen.addZIRInstConst(mod, &fn_type_scope.base, fn_src, .{ .ty = Type.initTag(.type), .val = Value.initTag(.type_type), }); @@ -1138,13 +1141,13 @@ fn astgenAndSemaFn( while (it.next()) |param| : (param_type_i += 1) { if (param.anytype_ellipsis3) |token| { switch (token_tags[token]) { - .keyword_anytype => return self.failTok( + .keyword_anytype => return mod.failTok( &fn_type_scope.base, - tok_i, + token, "TODO implement anytype parameter", .{}, ), - .ellipsis3 => return self.failTok( + .ellipsis3 => return mod.failTok( &fn_type_scope.base, token, "TODO implement var args", @@ -1156,7 +1159,7 @@ fn astgenAndSemaFn( const param_type_node = param.type_expr; assert(param_type_node != 0); param_types[param_type_i] = - try astgen.expr(self, &fn_type_scope.base, type_type_rl, param_type_node); + try astgen.expr(mod, &fn_type_scope.base, type_type_rl, param_type_node); } assert(param_type_i == param_count); } @@ -1164,10 +1167,10 @@ fn astgenAndSemaFn( // TODO call std.zig.parseStringLiteral const lib_name_str = mem.trim(u8, tree.tokenSlice(lib_name), "\""); log.debug("extern fn symbol expected in lib '{s}'", .{lib_name_str}); - const target = self.comp.getTarget(); + const target = mod.comp.getTarget(); if (target_util.is_libc_lib_name(target, lib_name_str)) { - if (!self.comp.bin_file.options.link_libc) { - return self.failTok( + if (!mod.comp.bin_file.options.link_libc) { + return mod.failTok( &fn_type_scope.base, lib_name, "dependency on libc must be explicitly specified in the build command", @@ -1177,8 +1180,8 @@ fn astgenAndSemaFn( break :blk; } if (target_util.is_libcpp_lib_name(target, lib_name_str)) { - if (!self.comp.bin_file.options.link_libcpp) { - return self.failTok( + if (!mod.comp.bin_file.options.link_libcpp) { + return mod.failTok( &fn_type_scope.base, lib_name, "dependency on libc++ must be explicitly specified in the build command", @@ -1187,16 +1190,16 @@ fn astgenAndSemaFn( } break :blk; } - if (!target.isWasm() and !self.comp.bin_file.options.pic) { - return self.failTok( + if (!target.isWasm() and !mod.comp.bin_file.options.pic) { + return mod.failTok( &fn_type_scope.base, lib_name, "dependency on dynamic library '{s}' requires enabling Position Independent Code. Fixed by `-l{s}` or `-fPIC`.", .{ lib_name, lib_name }, ); } - self.comp.stage1AddLinkLib(lib_name_str) catch |err| { - return self.failTok( + mod.comp.stage1AddLinkLib(lib_name_str) catch |err| { + return mod.failTok( &fn_type_scope.base, lib_name, "unable to add link lib '{s}': {s}", @@ -1204,45 +1207,55 @@ fn astgenAndSemaFn( ); }; } - if (fn_proto.ast.align_expr) |align_expr| { - return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{}); - } - if (fn_proto.ast.section_expr) |sect_expr| { - return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{}); - } - if (fn_proto.ast.callconv_expr) |callconv_expr| { - return self.failNode( + if (fn_proto.ast.align_expr != 0) { + return mod.failNode( &fn_type_scope.base, - callconv_expr, + fn_proto.ast.align_expr, + "TODO implement function align expression", + .{}, + ); + } + if (fn_proto.ast.section_expr != 0) { + return mod.failNode( + &fn_type_scope.base, + fn_proto.ast.section_expr, + "TODO implement function section expression", + .{}, + ); + } + if (fn_proto.ast.callconv_expr != 0) { + return mod.failNode( + &fn_type_scope.base, + fn_proto.ast.callconv_expr, "TODO implement function calling convention expression", .{}, ); } const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1; if (token_tags[maybe_bang] == .bang) { - return self.failTok(&fn_type_scope.base, maybe_bang, "TODO implement inferred error sets", .{}); + return mod.failTok(&fn_type_scope.base, maybe_bang, "TODO implement inferred error sets", .{}); } const return_type_inst = try astgen.expr( - self, + mod, &fn_type_scope.base, type_type_rl, fn_proto.ast.return_type, ); - const fn_type_inst = try astgen.addZIRInst(self, &fn_type_scope.base, fn_src, zir.Inst.FnType, .{ + const fn_type_inst = try astgen.addZIRInst(mod, &fn_type_scope.base, fn_src, zir.Inst.FnType, .{ .return_type = return_type_inst, .param_types = param_types, }, .{}); - if (std.builtin.mode == .Debug and self.comp.verbose_ir) { - zir.dumpZir(self.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {}; + if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { + zir.dumpZir(mod.gpa, "fn_type", decl.name, fn_type_scope.instructions.items) catch {}; } // We need the memory for the Type to go into the arena for the Decl - var decl_arena = std.heap.ArenaAllocator.init(self.gpa); + var decl_arena = std.heap.ArenaAllocator.init(mod.gpa); errdefer decl_arena.deinit(); const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); - var inst_table = Scope.Block.InstTable.init(self.gpa); + var inst_table = Scope.Block.InstTable.init(mod.gpa); defer inst_table.deinit(); var branch_quota: u32 = default_eval_branch_quota; @@ -1259,9 +1272,9 @@ fn astgenAndSemaFn( .is_comptime = false, .branch_quota = &branch_quota, }; - defer block_scope.instructions.deinit(self.gpa); + defer block_scope.instructions.deinit(mod.gpa); - const fn_type = try zir_sema.analyzeBodyValueAsType(self, &block_scope, fn_type_inst, .{ + const fn_type = try zir_sema.analyzeBodyValueAsType(mod, &block_scope, fn_type_inst, .{ .instructions = fn_type_scope.instructions.items, }); if (body_node == 0) { @@ -1270,7 +1283,7 @@ fn astgenAndSemaFn( if (decl.typedValueManaged()) |tvm| { type_changed = !tvm.typed_value.ty.eql(fn_type); - tvm.deinit(self.gpa); + tvm.deinit(mod.gpa); } const fn_val = try Value.Tag.extern_fn.create(&decl_arena.allocator, decl); @@ -1282,13 +1295,13 @@ fn astgenAndSemaFn( }, }; decl.analysis = .complete; - decl.generation = self.generation; + decl.generation = mod.generation; - try self.comp.bin_file.allocateDeclIndexes(decl); - try self.comp.work_queue.writeItem(.{ .codegen_decl = decl }); + try mod.comp.bin_file.allocateDeclIndexes(decl); + try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl }); - if (type_changed and self.emit_h != null) { - try self.comp.work_queue.writeItem(.{ .emit_h_decl = decl }); + if (type_changed and mod.emit_h != null) { + try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl }); } return type_changed; @@ -1304,17 +1317,17 @@ fn astgenAndSemaFn( .arena = &decl_arena.allocator, .parent = &decl.container.base, }; - defer gen_scope.instructions.deinit(self.gpa); + defer gen_scope.instructions.deinit(mod.gpa); // We need an instruction for each parameter, and they must be first in the body. - try gen_scope.instructions.resize(self.gpa, param_count); + try gen_scope.instructions.resize(mod.gpa, param_count); var params_scope = &gen_scope.base; var i: usize = 0; var it = fn_proto.iterate(tree); while (it.next()) |param| : (i += 1) { const name_token = param.name_token.?; const src = token_starts[name_token]; - const param_name = try self.identifierTokenString(&gen_scope.base, name_token); + const param_name = try mod.identifierTokenString(&gen_scope.base, name_token); const arg = try decl_arena.allocator.create(zir.Inst.NoOp); arg.* = .{ .base = .{ @@ -1335,17 +1348,17 @@ fn astgenAndSemaFn( params_scope = &sub_scope.base; } - try astgen.blockExpr(self, params_scope, body_node); + try astgen.blockExpr(mod, params_scope, body_node); if (gen_scope.instructions.items.len == 0 or !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn()) { const src = token_starts[tree.lastToken(body_node)]; - _ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .returnvoid); + _ = try astgen.addZIRNoOp(mod, &gen_scope.base, src, .returnvoid); } - if (std.builtin.mode == .Debug and self.comp.verbose_ir) { - zir.dumpZir(self.gpa, "fn_body", decl.name, gen_scope.instructions.items) catch {}; + if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { + zir.dumpZir(mod.gpa, "fn_body", decl.name, gen_scope.instructions.items) catch {}; } break :blk .{ @@ -1379,7 +1392,7 @@ fn astgenAndSemaFn( prev_is_inline = prev_func.state == .inline_only; } - tvm.deinit(self.gpa); + tvm.deinit(mod.gpa); } decl_arena_state.* = decl_arena.state; @@ -1393,25 +1406,25 @@ fn astgenAndSemaFn( }, }; decl.analysis = .complete; - decl.generation = self.generation; + decl.generation = mod.generation; if (!is_inline and fn_type.hasCodeGenBits()) { // We don't fully codegen the decl until later, but we do need to reserve a global // offset table index for it. This allows us to codegen decls out of dependency order, // increasing how many computations can be done in parallel. - try self.comp.bin_file.allocateDeclIndexes(decl); - try self.comp.work_queue.writeItem(.{ .codegen_decl = decl }); - if (type_changed and self.emit_h != null) { - try self.comp.work_queue.writeItem(.{ .emit_h_decl = decl }); + try mod.comp.bin_file.allocateDeclIndexes(decl); + try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl }); + if (type_changed and mod.emit_h != null) { + try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl }); } } else if (!prev_is_inline and prev_type_has_bits) { - self.comp.bin_file.freeDecl(decl); + mod.comp.bin_file.freeDecl(decl); } if (fn_proto.extern_export_token) |maybe_export_token| { - if (token_tags[maybe_export_token] == .Keyword_export) { + if (token_tags[maybe_export_token] == .keyword_export) { if (is_inline) { - return self.failTok( + return mod.failTok( &block_scope.base, maybe_export_token, "export of inline function", @@ -1421,7 +1434,7 @@ fn astgenAndSemaFn( const export_src = token_starts[maybe_export_token]; const name = tree.tokenSlice(fn_proto.name_token.?); // TODO identifierTokenString // The scope needs to have the decl in it. - try self.analyzeExport(&block_scope.base, export_src, name, decl); + try mod.analyzeExport(&block_scope.base, export_src, name, decl); } } return type_changed or is_inline != prev_is_inline; @@ -1439,13 +1452,14 @@ fn astgenAndSemaVarDecl( decl.analysis = .in_progress; const token_starts = tree.tokens.items(.start); + const token_tags = tree.tokens.items(.tag); // We need the memory for the Type to go into the arena for the Decl - var decl_arena = std.heap.ArenaAllocator.init(self.gpa); + var decl_arena = std.heap.ArenaAllocator.init(mod.gpa); errdefer decl_arena.deinit(); const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); - var decl_inst_table = Scope.Block.InstTable.init(self.gpa); + var decl_inst_table = Scope.Block.InstTable.init(mod.gpa); defer decl_inst_table.deinit(); var branch_quota: u32 = default_eval_branch_quota; @@ -1462,63 +1476,83 @@ fn astgenAndSemaVarDecl( .is_comptime = true, .branch_quota = &branch_quota, }; - defer block_scope.instructions.deinit(self.gpa); + defer block_scope.instructions.deinit(mod.gpa); - decl.is_pub = var_decl.getVisibToken() != null; + decl.is_pub = var_decl.visib_token != null; const is_extern = blk: { - const maybe_extern_token = var_decl.getExternExportToken() orelse - break :blk false; - if (tree.token_ids[maybe_extern_token] != .Keyword_extern) break :blk false; - if (var_decl.getInitNode()) |some| { - return self.failNode(&block_scope.base, some, "extern variables have no initializers", .{}); + const maybe_extern_token = var_decl.extern_export_token orelse break :blk false; + if (token_tags[maybe_extern_token] != .keyword_extern) break :blk false; + if (var_decl.ast.init_node != 0) { + return mod.failNode( + &block_scope.base, + var_decl.ast.init_node, + "extern variables have no initializers", + .{}, + ); } break :blk true; }; - if (var_decl.getLibName()) |lib_name| { + if (var_decl.lib_name) |lib_name| { assert(is_extern); - return self.failNode(&block_scope.base, lib_name, "TODO implement function library name", .{}); + return mod.failTok(&block_scope.base, lib_name, "TODO implement function library name", .{}); } - const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var; - const is_threadlocal = if (var_decl.getThreadLocalToken()) |some| blk: { + const is_mutable = token_tags[var_decl.mut_token] == .keyword_var; + const is_threadlocal = if (var_decl.threadlocal_token) |some| blk: { if (!is_mutable) { - return self.failTok(&block_scope.base, some, "threadlocal variable cannot be constant", .{}); + return mod.failTok(&block_scope.base, some, "threadlocal variable cannot be constant", .{}); } break :blk true; } else false; - assert(var_decl.getComptimeToken() == null); - if (var_decl.getAlignNode()) |align_expr| { - return self.failNode(&block_scope.base, align_expr, "TODO implement function align expression", .{}); + assert(var_decl.comptime_token == null); + if (var_decl.ast.align_node != 0) { + return mod.failNode( + &block_scope.base, + var_decl.ast.align_node, + "TODO implement function align expression", + .{}, + ); } - if (var_decl.getSectionNode()) |sect_expr| { - return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{}); + if (var_decl.ast.section_node != 0) { + return mod.failNode( + &block_scope.base, + var_decl.ast.section_node, + "TODO implement function section expression", + .{}, + ); } - const var_info: struct { ty: Type, val: ?Value } = if (var_decl.getInitNode()) |init_node| vi: { - var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa); + const var_info: struct { ty: Type, val: ?Value } = if (var_decl.ast.init_node != 0) vi: { + var gen_scope_arena = std.heap.ArenaAllocator.init(mod.gpa); defer gen_scope_arena.deinit(); var gen_scope: Scope.GenZIR = .{ .decl = decl, .arena = &gen_scope_arena.allocator, .parent = &decl.container.base, }; - defer gen_scope.instructions.deinit(self.gpa); + defer gen_scope.instructions.deinit(mod.gpa); - const init_result_loc: astgen.ResultLoc = if (var_decl.getTypeNode()) |type_node| rl: { - const src = token_starts[type_node.firstToken()]; - const type_type = try astgen.addZIRInstConst(self, &gen_scope.base, src, .{ + const init_result_loc: astgen.ResultLoc = if (var_decl.ast.type_node != 0) rl: { + const type_node = var_decl.ast.type_node; + const src = token_starts[tree.firstToken(type_node)]; + const type_type = try astgen.addZIRInstConst(mod, &gen_scope.base, src, .{ .ty = Type.initTag(.type), .val = Value.initTag(.type_type), }); - const var_type = try astgen.expr(self, &gen_scope.base, .{ .ty = type_type }, type_node); + const var_type = try astgen.expr(mod, &gen_scope.base, .{ .ty = type_type }, type_node); break :rl .{ .ty = var_type }; } else .none; - const init_inst = try astgen.comptimeExpr(self, &gen_scope.base, init_result_loc, init_node); - if (std.builtin.mode == .Debug and self.comp.verbose_ir) { - zir.dumpZir(self.gpa, "var_init", decl.name, gen_scope.instructions.items) catch {}; + const init_inst = try astgen.comptimeExpr( + mod, + &gen_scope.base, + init_result_loc, + var_decl.ast.init_node, + ); + if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { + zir.dumpZir(mod.gpa, "var_init", decl.name, gen_scope.instructions.items) catch {}; } - var var_inst_table = Scope.Block.InstTable.init(self.gpa); + var var_inst_table = Scope.Block.InstTable.init(mod.gpa); defer var_inst_table.deinit(); var branch_quota_vi: u32 = default_eval_branch_quota; @@ -1534,8 +1568,8 @@ fn astgenAndSemaVarDecl( .is_comptime = true, .branch_quota = &branch_quota_vi, }; - defer inner_block.instructions.deinit(self.gpa); - try zir_sema.analyzeBody(self, &inner_block, .{ + defer inner_block.instructions.deinit(mod.gpa); + try zir_sema.analyzeBody(mod, &inner_block, .{ .instructions = gen_scope.instructions.items, }); @@ -1550,24 +1584,30 @@ fn astgenAndSemaVarDecl( .val = try val.copy(block_scope.arena), }; } else if (!is_extern) { - return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{}); - } else if (var_decl.getTypeNode()) |type_node| vi: { + return mod.failTok( + &block_scope.base, + tree.firstToken(var_decl), + "variables must be initialized", + .{}, + ); + } else if (var_decl.ast.type_node != 0) vi: { + const type_node = var_decl.ast.type_node; // Temporary arena for the zir instructions. - var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa); + var type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa); defer type_scope_arena.deinit(); var type_scope: Scope.GenZIR = .{ .decl = decl, .arena = &type_scope_arena.allocator, .parent = &decl.container.base, }; - defer type_scope.instructions.deinit(self.gpa); + defer type_scope.instructions.deinit(mod.gpa); - const var_type = try astgen.typeExpr(self, &type_scope.base, type_node); - if (std.builtin.mode == .Debug and self.comp.verbose_ir) { - zir.dumpZir(self.gpa, "var_type", decl.name, type_scope.instructions.items) catch {}; + const var_type = try astgen.typeExpr(mod, &type_scope.base, type_node); + if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { + zir.dumpZir(mod.gpa, "var_type", decl.name, type_scope.instructions.items) catch {}; } - const ty = try zir_sema.analyzeBodyValueAsType(self, &block_scope, var_type, .{ + const ty = try zir_sema.analyzeBodyValueAsType(mod, &block_scope, var_type, .{ .instructions = type_scope.instructions.items, }); break :vi .{ @@ -1575,18 +1615,28 @@ fn astgenAndSemaVarDecl( .val = null, }; } else { - return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{}); + return mod.failTok( + &block_scope.base, + tree.firstToken(var_decl), + "unable to infer variable type", + .{}, + ); }; if (is_mutable and !var_info.ty.isValidVarType(is_extern)) { - return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_info.ty}); + return mod.failTok( + &block_scope.base, + tree.firstToken(var_decl), + "variable of type '{}' must be const", + .{var_info.ty}, + ); } var type_changed = true; if (decl.typedValueManaged()) |tvm| { type_changed = !tvm.typed_value.ty.eql(var_info.ty); - tvm.deinit(self.gpa); + tvm.deinit(mod.gpa); } const new_variable = try decl_arena.allocator.create(Var); @@ -1610,14 +1660,15 @@ fn astgenAndSemaVarDecl( }, }; decl.analysis = .complete; - decl.generation = self.generation; + decl.generation = mod.generation; - if (var_decl.getExternExportToken()) |maybe_export_token| { - if (tree.token_ids[maybe_export_token] == .Keyword_export) { + if (var_decl.extern_export_token) |maybe_export_token| { + if (token_tags[maybe_export_token] == .keyword_export) { const export_src = token_starts[maybe_export_token]; - const name = tree.tokenSlice(var_decl.name_token); // TODO identifierTokenString + const name_token = var_decl.ast.mut_token + 1; + const name = tree.tokenSlice(name_token); // TODO identifierTokenString // The scope needs to have the decl in it. - try self.analyzeExport(&block_scope.base, export_src, name, decl); + try mod.analyzeExport(&block_scope.base, export_src, name, decl); } } return type_changed; @@ -1761,7 +1812,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { decl_node, decl_i, tree.*, - null, + 0, tree.fnProtoSimple(¶ms, decl_node), ); }, @@ -1771,7 +1822,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { decl_node, decl_i, tree.*, - null, + 0, tree.fnProtoMulti(decl_node), ), .fn_proto_one => { @@ -1782,7 +1833,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { decl_node, decl_i, tree.*, - null, + 0, tree.fnProtoOne(¶ms, decl_node), ); }, @@ -1792,7 +1843,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { decl_node, decl_i, tree.*, - null, + 0, tree.fnProto(decl_node), ), @@ -1848,7 +1899,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { decl_node, decl_i, tree.*, - tree.containerFieldInit(decl), + tree.containerFieldInit(decl_node), ), .container_field_align => try mod.semaContainerField( container_scope, @@ -1856,7 +1907,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { decl_node, decl_i, tree.*, - tree.containerFieldAlign(decl), + tree.containerFieldAlign(decl_node), ), .container_field => try mod.semaContainerField( container_scope, @@ -1864,7 +1915,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { decl_node, decl_i, tree.*, - tree.containerField(decl), + tree.containerField(decl_node), ), .test_decl => { @@ -1936,14 +1987,14 @@ fn semaContainerFn( // in `Decl` to notice that the line number did not change. mod.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl }); }, - .c, .wasm => {}, + .c, .wasm, .spirv => {}, } } } else { const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash); container_scope.decls.putAssumeCapacity(new_decl, {}); - if (fn_proto.getExternExportInlineToken()) |maybe_export_token| { - if (tree.token_ids[maybe_export_token] == .Keyword_export) { + if (fn_proto.extern_export_token) |maybe_export_token| { + if (token_tags[maybe_export_token] == .keyword_export) { mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); } } @@ -1963,9 +2014,11 @@ fn semaContainerVar( defer tracy.end(); const token_starts = tree.tokens.items(.start); + const token_tags = tree.tokens.items(.tag); - const name_src = token_starts[var_decl.name_token]; - const name = tree.tokenSlice(var_decl.name_token); // TODO identifierTokenString + const name_token = var_decl.ast.mut_token + 1; + const name_src = token_starts[name_token]; + const name = tree.tokenSlice(name_token); // TODO identifierTokenString const name_hash = container_scope.fullyQualifiedNameHash(name); const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); if (mod.decl_table.get(name_hash)) |decl| { @@ -1987,15 +2040,23 @@ fn semaContainerVar( } else { const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash); container_scope.decls.putAssumeCapacity(new_decl, {}); - if (var_decl.getExternExportToken()) |maybe_export_token| { - if (tree.token_ids[maybe_export_token] == .Keyword_export) { + if (var_decl.extern_export_token) |maybe_export_token| { + if (token_tags[maybe_export_token] == .keyword_export) { mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); } } } } -fn semaContainerField() void { +fn semaContainerField( + mod: *Module, + container_scope: *Scope.Container, + deleted_decls: *std.AutoArrayHashMap(*Decl, void), + decl_node: ast.Node.Index, + decl_i: usize, + tree: ast.Tree, + field: ast.full.ContainerField, +) !void { const tracy = trace(@src()); defer tracy.end(); @@ -2898,7 +2959,7 @@ pub fn analyzeImport(self: *Module, scope: *Scope, src: usize, target_string: [] file_scope.* = .{ .sub_file_path = resolved_path, .source = .{ .unloaded = {} }, - .contents = .{ .not_available = {} }, + .tree = undefined, .status = .never_loaded, .pkg = found_pkg orelse cur_pkg, .root_container = .{ @@ -3415,11 +3476,12 @@ pub fn failTok( pub fn failNode( self: *Module, scope: *Scope, - ast_node: *ast.Node, + ast_node: ast.Node.Index, comptime format: []const u8, args: anytype, ) InnerError { - const src = scope.tree().tokens.items(.start)[ast_node.firstToken()]; + const tree = scope.tree(); + const src = tree.tokens.items(.start)[tree.firstToken(ast_node)]; return self.fail(scope, src, format, args); } diff --git a/src/astgen.zig b/src/astgen.zig index ece16d70da..dcc2ea9ad2 100644 --- a/src/astgen.zig +++ b/src/astgen.zig @@ -55,7 +55,7 @@ pub const ResultLoc = union(enum) { }; }; -pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*zir.Inst { +pub fn typeExpr(mod: *Module, scope: *Scope, type_node: ast.Node.Index) InnerError!*zir.Inst { const type_src = scope.tree().token_locs[type_node.firstToken()].start; const type_type = try addZIRInstConst(mod, scope, type_src, .{ .ty = Type.initTag(.type), @@ -65,134 +65,133 @@ pub fn typeExpr(mod: *Module, scope: *Scope, type_node: *ast.Node) InnerError!*z return expr(mod, scope, type_rl, type_node); } -fn lvalExpr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { - switch (node.tag) { - .Root => unreachable, - .Use => unreachable, - .TestDecl => unreachable, - .DocComment => unreachable, - .VarDecl => unreachable, - .SwitchCase => unreachable, - .SwitchElse => unreachable, - .Else => unreachable, - .Payload => unreachable, - .PointerPayload => unreachable, - .PointerIndexPayload => unreachable, - .ErrorTag => unreachable, - .FieldInitializer => unreachable, - .ContainerField => unreachable, +fn lvalExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst { + const tree = scope.tree(); + const node_tags = tree.nodes.items(.tag); + const main_tokens = tree.nodes.items(.main_token); + switch (node_tags[node]) { + .root => unreachable, + .@"usingnamespace" => unreachable, + .test_decl => unreachable, + .doc_comment => unreachable, + .var_decl => unreachable, + .switch_case => unreachable, + .switch_else => unreachable, + .container_field_init => unreachable, + .container_field_align => unreachable, + .container_field => unreachable, - .Assign, - .AssignBitAnd, - .AssignBitOr, - .AssignBitShiftLeft, - .AssignBitShiftRight, - .AssignBitXor, - .AssignDiv, - .AssignSub, - .AssignSubWrap, - .AssignMod, - .AssignAdd, - .AssignAddWrap, - .AssignMul, - .AssignMulWrap, - .Add, - .AddWrap, - .Sub, - .SubWrap, - .Mul, - .MulWrap, - .Div, - .Mod, - .BitAnd, - .BitOr, - .BitShiftLeft, - .BitShiftRight, - .BitXor, - .BangEqual, - .EqualEqual, - .GreaterThan, - .GreaterOrEqual, - .LessThan, - .LessOrEqual, - .ArrayCat, - .ArrayMult, - .BoolAnd, - .BoolOr, - .Asm, - .StringLiteral, - .IntegerLiteral, - .Call, - .Unreachable, - .Return, - .If, - .While, - .BoolNot, - .AddressOf, - .FloatLiteral, - .UndefinedLiteral, - .BoolLiteral, - .NullLiteral, - .OptionalType, - .Block, - .LabeledBlock, - .Break, + .assign, + .assign_bit_and, + .assign_bit_or, + .assign_bit_shift_left, + .assign_bit_shift_right, + .assign_bit_xor, + .assign_div, + .assign_sub, + .assign_sub_wrap, + .assign_mod, + .assign_add, + .assign_add_wrap, + .assign_mul, + .assign_mul_wrap, + .add, + .add_wrap, + .sub, + .sub_wrap, + .mul, + .mul_wrap, + .div, + .mod, + .bit_and, + .bit_or, + .bit_shift_left, + .bit_shift_right, + .bit_xor, + .bang_equal, + .equal_equal, + .greater_than, + .greater_or_equal, + .less_than, + .less_or_equal, + .array_cat, + .array_mult, + .bool_and, + .bool_or, + .@"asm", + .string_literal, + .integer_literal, + .call, + .@"unreachable", + .@"return", + .@"if", + .@"while", + .bool_not, + .address_of, + .float_literal, + .undefined_literal, + .bool_literal, + .null_literal, + .optional_type, + .block, + .labeled_block, + .@"break", .PtrType, - .ArrayType, - .ArrayTypeSentinel, - .EnumLiteral, + .array_type, + .array_type_sentinel, + .enum_literal, .MultilineStringLiteral, - .CharLiteral, - .Defer, - .Catch, - .ErrorUnion, - .MergeErrorSets, - .Range, - .Await, - .BitNot, - .Negation, - .NegationWrap, - .Resume, - .Try, - .SliceType, - .Slice, + .char_literal, + .@"defer", + .@"catch", + .error_union, + .merge_error_sets, + .range, + .@"await", + .bit_not, + .negation, + .negation_wrap, + .@"resume", + .@"try", + .slice_type, + .slice, .ArrayInitializer, .ArrayInitializerDot, .StructInitializer, .StructInitializerDot, - .Switch, - .For, - .Suspend, - .Continue, - .AnyType, - .ErrorType, + .@"switch", + .@"for", + .@"suspend", + .@"continue", + .@"anytype", + .error_type, .FnProto, - .AnyFrameType, - .ErrorSetDecl, + .anyframe_type, + .error_set_decl, .ContainerDecl, - .Comptime, - .Nosuspend, + .@"comptime", + .@"nosuspend", + .builtin_call, + .builtin_call_comma, => return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}), - // @field can be assigned to - .BuiltinCall => { - const call = node.castTag(.BuiltinCall).?; - const tree = scope.tree(); - const builtin_name = tree.tokenSlice(call.builtin_token); - + // `@field` can be assigned to. + .builtin_call_two, .builtin_call_two_comma => { + const builtin_token = main_tokens[node]; + const builtin_name = tree.tokenSlice(builtin_token); if (!mem.eql(u8, builtin_name, "@field")) { return mod.failNode(scope, node, "invalid left-hand side to assignment", .{}); } }, // can be assigned to - .UnwrapOptional, - .Deref, - .Period, - .ArrayAccess, - .Identifier, - .GroupedExpression, - .OrElse, + .unwrap_optional, + .deref, + .period, + .array_access, + .identifier, + .grouped_expression, + .@"orelse", => {}, } return expr(mod, scope, .ref, node); @@ -202,16 +201,16 @@ fn lvalExpr(mod: *Module, scope: *Scope, node: *ast.Node) InnerError!*zir.Inst { /// When `rl` is discard, ptr, inferred_ptr, bitcasted_ptr, or inferred_ptr, the /// result instruction can be used to inspect whether it is isNoReturn() but that is it, /// it must otherwise not be used. -pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerError!*zir.Inst { +pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!*zir.Inst { switch (node.tag) { - .Root => unreachable, // Top-level declaration. - .Use => unreachable, // Top-level declaration. - .TestDecl => unreachable, // Top-level declaration. - .DocComment => unreachable, // Top-level declaration. - .VarDecl => unreachable, // Handled in `blockExpr`. - .SwitchCase => unreachable, // Handled in `switchExpr`. - .SwitchElse => unreachable, // Handled in `switchExpr`. - .Range => unreachable, // Handled in `switchExpr`. + .root => unreachable, // Top-level declaration. + .@"usingnamespace" => unreachable, // Top-level declaration. + .test_decl => unreachable, // Top-level declaration. + .doc_comment => unreachable, // Top-level declaration. + .var_decl => unreachable, // Handled in `blockExpr`. + .switch_case => unreachable, // Handled in `switchExpr`. + .switch_else => unreachable, // Handled in `switchExpr`. + .range => unreachable, // Handled in `switchExpr`. .Else => unreachable, // Handled explicitly the control flow expression functions. .Payload => unreachable, // Handled explicitly. .PointerPayload => unreachable, // Handled explicitly. @@ -220,114 +219,113 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr .FieldInitializer => unreachable, // Handled explicitly. .ContainerField => unreachable, // Handled explicitly. - .Assign => return rvalueVoid(mod, scope, rl, node, try assign(mod, scope, node.castTag(.Assign).?)), - .AssignBitAnd => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitAnd).?, .bit_and)), - .AssignBitOr => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitOr).?, .bit_or)), - .AssignBitShiftLeft => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitShiftLeft).?, .shl)), - .AssignBitShiftRight => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitShiftRight).?, .shr)), - .AssignBitXor => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignBitXor).?, .xor)), - .AssignDiv => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignDiv).?, .div)), - .AssignSub => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignSub).?, .sub)), - .AssignSubWrap => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignSubWrap).?, .subwrap)), - .AssignMod => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMod).?, .mod_rem)), - .AssignAdd => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignAdd).?, .add)), - .AssignAddWrap => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignAddWrap).?, .addwrap)), - .AssignMul => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMul).?, .mul)), - .AssignMulWrap => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node.castTag(.AssignMulWrap).?, .mulwrap)), + .assign => return rvalueVoid(mod, scope, rl, node, try assign(mod, scope, node)), + .assign_bit_and => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .bit_and)), + .assign_bit_or => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .bit_or)), + .assign_bit_shift_left => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .shl)), + .assign_bit_shift_right => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .shr)), + .assign_bit_xor => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .xor)), + .assign_div => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .div)), + .assign_sub => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .sub)), + .assign_sub_wrap => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .subwrap)), + .assign_mod => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .mod_rem)), + .assign_add => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .add)), + .assign_add_wrap => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .addwrap)), + .assign_mul => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .mul)), + .assign_mul_wrap => return rvalueVoid(mod, scope, rl, node, try assignOp(mod, scope, node, .mulwrap)), - .Add => return simpleBinOp(mod, scope, rl, node.castTag(.Add).?, .add), - .AddWrap => return simpleBinOp(mod, scope, rl, node.castTag(.AddWrap).?, .addwrap), - .Sub => return simpleBinOp(mod, scope, rl, node.castTag(.Sub).?, .sub), - .SubWrap => return simpleBinOp(mod, scope, rl, node.castTag(.SubWrap).?, .subwrap), - .Mul => return simpleBinOp(mod, scope, rl, node.castTag(.Mul).?, .mul), - .MulWrap => return simpleBinOp(mod, scope, rl, node.castTag(.MulWrap).?, .mulwrap), - .Div => return simpleBinOp(mod, scope, rl, node.castTag(.Div).?, .div), - .Mod => return simpleBinOp(mod, scope, rl, node.castTag(.Mod).?, .mod_rem), - .BitAnd => return simpleBinOp(mod, scope, rl, node.castTag(.BitAnd).?, .bit_and), - .BitOr => return simpleBinOp(mod, scope, rl, node.castTag(.BitOr).?, .bit_or), - .BitShiftLeft => return simpleBinOp(mod, scope, rl, node.castTag(.BitShiftLeft).?, .shl), - .BitShiftRight => return simpleBinOp(mod, scope, rl, node.castTag(.BitShiftRight).?, .shr), - .BitXor => return simpleBinOp(mod, scope, rl, node.castTag(.BitXor).?, .xor), + .add => return simpleBinOp(mod, scope, rl, node, .add), + .add_wrap => return simpleBinOp(mod, scope, rl, node, .addwrap), + .sub => return simpleBinOp(mod, scope, rl, node, .sub), + .sub_wrap => return simpleBinOp(mod, scope, rl, node, .subwrap), + .mul => return simpleBinOp(mod, scope, rl, node, .mul), + .mul_wrap => return simpleBinOp(mod, scope, rl, node, .mulwrap), + .div => return simpleBinOp(mod, scope, rl, node, .div), + .mod => return simpleBinOp(mod, scope, rl, node, .mod_rem), + .bit_and => return simpleBinOp(mod, scope, rl, node, .bit_and), + .bit_or => return simpleBinOp(mod, scope, rl, node, .bit_or), + .bit_shift_left => return simpleBinOp(mod, scope, rl, node, .shl), + .bit_shift_right => return simpleBinOp(mod, scope, rl, node, .shr), + .bit_xor => return simpleBinOp(mod, scope, rl, node, .xor), - .BangEqual => return simpleBinOp(mod, scope, rl, node.castTag(.BangEqual).?, .cmp_neq), - .EqualEqual => return simpleBinOp(mod, scope, rl, node.castTag(.EqualEqual).?, .cmp_eq), - .GreaterThan => return simpleBinOp(mod, scope, rl, node.castTag(.GreaterThan).?, .cmp_gt), - .GreaterOrEqual => return simpleBinOp(mod, scope, rl, node.castTag(.GreaterOrEqual).?, .cmp_gte), - .LessThan => return simpleBinOp(mod, scope, rl, node.castTag(.LessThan).?, .cmp_lt), - .LessOrEqual => return simpleBinOp(mod, scope, rl, node.castTag(.LessOrEqual).?, .cmp_lte), + .bang_equal => return simpleBinOp(mod, scope, rl, node, .cmp_neq), + .equal_equal => return simpleBinOp(mod, scope, rl, node, .cmp_eq), + .greater_than => return simpleBinOp(mod, scope, rl, node, .cmp_gt), + .greater_or_equal => return simpleBinOp(mod, scope, rl, node, .cmp_gte), + .less_than => return simpleBinOp(mod, scope, rl, node, .cmp_lt), + .less_or_equal => return simpleBinOp(mod, scope, rl, node, .cmp_lte), - .ArrayCat => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayCat).?, .array_cat), - .ArrayMult => return simpleBinOp(mod, scope, rl, node.castTag(.ArrayMult).?, .array_mul), + .array_cat => return simpleBinOp(mod, scope, rl, node, .array_cat), + .array_mult => return simpleBinOp(mod, scope, rl, node, .array_mul), - .BoolAnd => return boolBinOp(mod, scope, rl, node.castTag(.BoolAnd).?), - .BoolOr => return boolBinOp(mod, scope, rl, node.castTag(.BoolOr).?), + .bool_and => return boolBinOp(mod, scope, rl, node), + .bool_or => return boolBinOp(mod, scope, rl, node), - .BoolNot => return rvalue(mod, scope, rl, try boolNot(mod, scope, node.castTag(.BoolNot).?)), - .BitNot => return rvalue(mod, scope, rl, try bitNot(mod, scope, node.castTag(.BitNot).?)), - .Negation => return rvalue(mod, scope, rl, try negation(mod, scope, node.castTag(.Negation).?, .sub)), - .NegationWrap => return rvalue(mod, scope, rl, try negation(mod, scope, node.castTag(.NegationWrap).?, .subwrap)), + .bool_not => return rvalue(mod, scope, rl, try boolNot(mod, scope, node)), + .bit_not => return rvalue(mod, scope, rl, try bitNot(mod, scope, node)), + .negation => return rvalue(mod, scope, rl, try negation(mod, scope, node, .sub)), + .negation_wrap => return rvalue(mod, scope, rl, try negation(mod, scope, node, .subwrap)), - .Identifier => return try identifier(mod, scope, rl, node.castTag(.Identifier).?), - .Asm => return rvalue(mod, scope, rl, try assembly(mod, scope, node.castTag(.Asm).?)), - .StringLiteral => return rvalue(mod, scope, rl, try stringLiteral(mod, scope, node.castTag(.StringLiteral).?)), - .IntegerLiteral => return rvalue(mod, scope, rl, try integerLiteral(mod, scope, node.castTag(.IntegerLiteral).?)), - .BuiltinCall => return builtinCall(mod, scope, rl, node.castTag(.BuiltinCall).?), - .Call => return callExpr(mod, scope, rl, node.castTag(.Call).?), - .Unreachable => return unreach(mod, scope, node.castTag(.Unreachable).?), - .Return => return ret(mod, scope, node.castTag(.Return).?), - .If => return ifExpr(mod, scope, rl, node.castTag(.If).?), - .While => return whileExpr(mod, scope, rl, node.castTag(.While).?), - .Period => return field(mod, scope, rl, node.castTag(.Period).?), - .Deref => return rvalue(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)), - .AddressOf => return rvalue(mod, scope, rl, try addressOf(mod, scope, node.castTag(.AddressOf).?)), - .FloatLiteral => return rvalue(mod, scope, rl, try floatLiteral(mod, scope, node.castTag(.FloatLiteral).?)), - .UndefinedLiteral => return rvalue(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)), - .BoolLiteral => return rvalue(mod, scope, rl, try boolLiteral(mod, scope, node.castTag(.BoolLiteral).?)), - .NullLiteral => return rvalue(mod, scope, rl, try nullLiteral(mod, scope, node.castTag(.NullLiteral).?)), - .OptionalType => return rvalue(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)), - .UnwrapOptional => return unwrapOptional(mod, scope, rl, node.castTag(.UnwrapOptional).?), - .Block => return rvalueVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)), - .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?, .block), - .Break => return rvalue(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)), - .Continue => return rvalue(mod, scope, rl, try continueExpr(mod, scope, node.castTag(.Continue).?)), - .PtrType => return rvalue(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)), - .GroupedExpression => return expr(mod, scope, rl, node.castTag(.GroupedExpression).?.expr), - .ArrayType => return rvalue(mod, scope, rl, try arrayType(mod, scope, node.castTag(.ArrayType).?)), - .ArrayTypeSentinel => return rvalue(mod, scope, rl, try arrayTypeSentinel(mod, scope, node.castTag(.ArrayTypeSentinel).?)), - .EnumLiteral => return rvalue(mod, scope, rl, try enumLiteral(mod, scope, node.castTag(.EnumLiteral).?)), - .MultilineStringLiteral => return rvalue(mod, scope, rl, try multilineStrLiteral(mod, scope, node.castTag(.MultilineStringLiteral).?)), - .CharLiteral => return rvalue(mod, scope, rl, try charLiteral(mod, scope, node.castTag(.CharLiteral).?)), - .SliceType => return rvalue(mod, scope, rl, try sliceType(mod, scope, node.castTag(.SliceType).?)), - .ErrorUnion => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.ErrorUnion).?, .error_union_type)), - .MergeErrorSets => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node.castTag(.MergeErrorSets).?, .merge_error_sets)), - .AnyFrameType => return rvalue(mod, scope, rl, try anyFrameType(mod, scope, node.castTag(.AnyFrameType).?)), - .ErrorSetDecl => return rvalue(mod, scope, rl, try errorSetDecl(mod, scope, node.castTag(.ErrorSetDecl).?)), - .ErrorType => return rvalue(mod, scope, rl, try errorType(mod, scope, node.castTag(.ErrorType).?)), - .For => return forExpr(mod, scope, rl, node.castTag(.For).?), - .ArrayAccess => return arrayAccess(mod, scope, rl, node.castTag(.ArrayAccess).?), - .Slice => return rvalue(mod, scope, rl, try sliceExpr(mod, scope, node.castTag(.Slice).?)), - .Catch => return catchExpr(mod, scope, rl, node.castTag(.Catch).?), - .Comptime => return comptimeKeyword(mod, scope, rl, node.castTag(.Comptime).?), - .OrElse => return orelseExpr(mod, scope, rl, node.castTag(.OrElse).?), - .Switch => return switchExpr(mod, scope, rl, node.castTag(.Switch).?), - .ContainerDecl => return containerDecl(mod, scope, rl, node.castTag(.ContainerDecl).?), + .identifier => return try identifier(mod, scope, rl, node), + .@"asm" => return rvalue(mod, scope, rl, try assembly(mod, scope, node)), + .string_literal => return rvalue(mod, scope, rl, try stringLiteral(mod, scope, node)), + .integer_literal => return rvalue(mod, scope, rl, try integerLiteral(mod, scope, node)), + .builtin_call => return builtinCall(mod, scope, rl, node), + .call => return callExpr(mod, scope, rl, node), + .@"unreachable" => return unreach(mod, scope, node), + .@"return" => return ret(mod, scope, node), + .@"if" => return ifExpr(mod, scope, rl, node), + .@"while" => return whileExpr(mod, scope, rl, node), + .period => return field(mod, scope, rl, node), + .deref => return rvalue(mod, scope, rl, try deref(mod, scope, node)), + .address_of => return rvalue(mod, scope, rl, try addressOf(mod, scope, node)), + .float_literal => return rvalue(mod, scope, rl, try floatLiteral(mod, scope, node)), + .undefined_literal => return rvalue(mod, scope, rl, try undefLiteral(mod, scope, node)), + .bool_literal => return rvalue(mod, scope, rl, try boolLiteral(mod, scope, node)), + .null_literal => return rvalue(mod, scope, rl, try nullLiteral(mod, scope, node)), + .optional_type => return rvalue(mod, scope, rl, try optionalType(mod, scope, node)), + .unwrap_optional => return unwrapOptional(mod, scope, rl, node), + .block => return rvalueVoid(mod, scope, rl, node, try blockExpr(mod, scope, node)), + .labeled_block => return labeledBlockExpr(mod, scope, rl, node, .block), + .@"break" => return rvalue(mod, scope, rl, try breakExpr(mod, scope, node)), + .@"continue" => return rvalue(mod, scope, rl, try continueExpr(mod, scope, node)), + .grouped_expression => return expr(mod, scope, rl, node.expr), + .array_type => return rvalue(mod, scope, rl, try arrayType(mod, scope, node)), + .array_type_sentinel => return rvalue(mod, scope, rl, try arrayTypeSentinel(mod, scope, node)), + .enum_literal => return rvalue(mod, scope, rl, try enumLiteral(mod, scope, node)), + .MultilineStringLiteral => return rvalue(mod, scope, rl, try multilineStrLiteral(mod, scope, node)), + .char_literal => return rvalue(mod, scope, rl, try charLiteral(mod, scope, node)), + .slice_type => return rvalue(mod, scope, rl, try sliceType(mod, scope, node)), + .error_union => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node, .error_union_type)), + .merge_error_sets => return rvalue(mod, scope, rl, try typeInixOp(mod, scope, node, .merge_error_sets)), + .anyframe_type => return rvalue(mod, scope, rl, try anyFrameType(mod, scope, node)), + .error_set_decl => return rvalue(mod, scope, rl, try errorSetDecl(mod, scope, node)), + .error_type => return rvalue(mod, scope, rl, try errorType(mod, scope, node)), + .@"for" => return forExpr(mod, scope, rl, node), + .array_access => return arrayAccess(mod, scope, rl, node), + .slice => return rvalue(mod, scope, rl, try sliceExpr(mod, scope, node)), + .@"catch" => return catchExpr(mod, scope, rl, node), + .@"comptime" => return comptimeKeyword(mod, scope, rl, node), + .@"orelse" => return orelseExpr(mod, scope, rl, node), + .@"switch" => return switchExpr(mod, scope, rl, node), + .ContainerDecl => return containerDecl(mod, scope, rl, node), - .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}), - .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}), - .Resume => return mod.failNode(scope, node, "TODO implement astgen.expr for .Resume", .{}), - .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), + .@"defer" => return mod.failNode(scope, node, "TODO implement astgen.expr for .defer", .{}), + .@"await" => return mod.failNode(scope, node, "TODO implement astgen.expr for .await", .{}), + .@"resume" => return mod.failNode(scope, node, "TODO implement astgen.expr for .resume", .{}), + .@"try" => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}), .ArrayInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializer", .{}), .ArrayInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayInitializerDot", .{}), .StructInitializer => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializer", .{}), .StructInitializerDot => return mod.failNode(scope, node, "TODO implement astgen.expr for .StructInitializerDot", .{}), - .Suspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Suspend", .{}), - .AnyType => return mod.failNode(scope, node, "TODO implement astgen.expr for .AnyType", .{}), + .@"suspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .suspend", .{}), + .@"anytype" => return mod.failNode(scope, node, "TODO implement astgen.expr for .anytype", .{}), .FnProto => return mod.failNode(scope, node, "TODO implement astgen.expr for .FnProto", .{}), - .Nosuspend => return mod.failNode(scope, node, "TODO implement astgen.expr for .Nosuspend", .{}), + .@"nosuspend" => return mod.failNode(scope, node, "TODO implement astgen.expr for .nosuspend", .{}), } } -fn comptimeKeyword(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Comptime) InnerError!*zir.Inst { +fn comptimeKeyword(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.@"comptime") InnerError!*zir.Inst { const tracy = trace(@src()); defer tracy.end(); @@ -338,7 +336,7 @@ pub fn comptimeExpr( mod: *Module, parent_scope: *Scope, rl: ResultLoc, - node: *ast.Node, + node: ast.Node.Index, ) InnerError!*zir.Inst { // If we are already in a comptime scope, no need to make another one. if (parent_scope.isComptime()) { @@ -347,7 +345,7 @@ pub fn comptimeExpr( // Optimization for labeled blocks: don't need to have 2 layers of blocks, // we can reuse the existing one. - if (node.castTag(.LabeledBlock)) |block_node| { + if (node.castTag(.labeled_block)) |block_node| { return labeledBlockExpr(mod, parent_scope, rl, block_node, .block_comptime); } @@ -366,6 +364,8 @@ pub fn comptimeExpr( _ = try expr(mod, &block_scope.base, rl, node); const tree = parent_scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[node.firstToken()].start; const block = try addZIRInstBlock(mod, parent_scope, src, .block_comptime_flat, .{ @@ -381,6 +381,8 @@ fn breakExpr( node: *ast.Node.ControlFlowExpression, ) InnerError!*zir.Inst { const tree = parent_scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[node.ltoken].start; // Look for the label in the scope. @@ -445,6 +447,8 @@ fn breakExpr( fn continueExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { const tree = parent_scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[node.ltoken].start; // Look for the label in the scope. @@ -485,7 +489,7 @@ fn continueExpr(mod: *Module, parent_scope: *Scope, node: *ast.Node.ControlFlowE } } -pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.Block) InnerError!void { +pub fn blockExpr(mod: *Module, parent_scope: *Scope, block_node: *ast.Node.block) InnerError!void { const tracy = trace(@src()); defer tracy.end(); @@ -502,6 +506,8 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn if (gen_zir.label) |prev_label| { if (try tokenIdentEql(mod, parent_scope, label, prev_label.token)) { const tree = parent_scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const label_src = tree.token_locs[label].start; const prev_label_src = tree.token_locs[prev_label.token].start; @@ -539,7 +545,7 @@ fn labeledBlockExpr( mod: *Module, parent_scope: *Scope, rl: ResultLoc, - block_node: *ast.Node.LabeledBlock, + block_node: *ast.Node.labeled_block, zir_tag: zir.Inst.Tag, ) InnerError!*zir.Inst { const tracy = trace(@src()); @@ -548,6 +554,8 @@ fn labeledBlockExpr( assert(zir_tag == .block or zir_tag == .block_comptime); const tree = parent_scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[block_node.lbrace].start; try checkLabelRedefinition(mod, parent_scope, block_node.label); @@ -627,10 +635,12 @@ fn labeledBlockExpr( fn blockExprStmts( mod: *Module, parent_scope: *Scope, - node: *ast.Node, - statements: []*ast.Node, + node: ast.Node.Index, + statements: []const ast.Node.Index, ) !void { const tree = parent_scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); var block_arena = std.heap.ArenaAllocator.init(mod.gpa); defer block_arena.deinit(); @@ -640,24 +650,24 @@ fn blockExprStmts( const src = tree.token_locs[statement.firstToken()].start; _ = try addZIRNoOp(mod, scope, src, .dbg_stmt); switch (statement.tag) { - .VarDecl => { - const var_decl_node = statement.castTag(.VarDecl).?; + .var_decl => { + const var_decl_node = statement.castTag(.var_decl).?; scope = try varDecl(mod, scope, var_decl_node, &block_arena.allocator); }, - .Assign => try assign(mod, scope, statement.castTag(.Assign).?), - .AssignBitAnd => try assignOp(mod, scope, statement.castTag(.AssignBitAnd).?, .bit_and), - .AssignBitOr => try assignOp(mod, scope, statement.castTag(.AssignBitOr).?, .bit_or), - .AssignBitShiftLeft => try assignOp(mod, scope, statement.castTag(.AssignBitShiftLeft).?, .shl), - .AssignBitShiftRight => try assignOp(mod, scope, statement.castTag(.AssignBitShiftRight).?, .shr), - .AssignBitXor => try assignOp(mod, scope, statement.castTag(.AssignBitXor).?, .xor), - .AssignDiv => try assignOp(mod, scope, statement.castTag(.AssignDiv).?, .div), - .AssignSub => try assignOp(mod, scope, statement.castTag(.AssignSub).?, .sub), - .AssignSubWrap => try assignOp(mod, scope, statement.castTag(.AssignSubWrap).?, .subwrap), - .AssignMod => try assignOp(mod, scope, statement.castTag(.AssignMod).?, .mod_rem), - .AssignAdd => try assignOp(mod, scope, statement.castTag(.AssignAdd).?, .add), - .AssignAddWrap => try assignOp(mod, scope, statement.castTag(.AssignAddWrap).?, .addwrap), - .AssignMul => try assignOp(mod, scope, statement.castTag(.AssignMul).?, .mul), - .AssignMulWrap => try assignOp(mod, scope, statement.castTag(.AssignMulWrap).?, .mulwrap), + .assign => try assign(mod, scope, statement), + .assign_bit_and => try assignOp(mod, scope, statement, .bit_and), + .assign_bit_or => try assignOp(mod, scope, statement, .bit_or), + .assign_bit_shift_left => try assignOp(mod, scope, statement, .shl), + .assign_bit_shift_right => try assignOp(mod, scope, statement, .shr), + .assign_bit_xor => try assignOp(mod, scope, statement, .xor), + .assign_div => try assignOp(mod, scope, statement, .div), + .assign_sub => try assignOp(mod, scope, statement, .sub), + .assign_sub_wrap => try assignOp(mod, scope, statement, .subwrap), + .assign_mod => try assignOp(mod, scope, statement, .mod_rem), + .assign_add => try assignOp(mod, scope, statement, .add), + .assign_add_wrap => try assignOp(mod, scope, statement, .addwrap), + .assign_mul => try assignOp(mod, scope, statement, .mul), + .assign_mul_wrap => try assignOp(mod, scope, statement, .mulwrap), else => { const possibly_unused_result = try expr(mod, scope, .none, statement); @@ -672,7 +682,7 @@ fn blockExprStmts( fn varDecl( mod: *Module, scope: *Scope, - node: *ast.Node.VarDecl, + node: *ast.Node.var_decl, block_arena: *Allocator, ) InnerError!*Scope { if (node.getComptimeToken()) |comptime_token| { @@ -682,6 +692,8 @@ fn varDecl( return mod.failNode(scope, align_node, "TODO implement alignment on locals", .{}); } const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const name_src = tree.token_locs[node.name_token].start; const ident_name = try mod.identifierTokenString(scope, node.name_token); @@ -733,7 +745,7 @@ fn varDecl( return mod.fail(scope, name_src, "variables must be initialized", .{}); switch (tree.token_ids[node.mut_token]) { - .Keyword_const => { + .keyword_const => { // Depending on the type of AST the initialization expression is, we may need an lvalue // or an rvalue as a result location. If it is an rvalue, we can use the instruction as // the variable, no memory location needed. @@ -834,7 +846,7 @@ fn varDecl( }; return &sub_scope.base; }, - .Keyword_var => { + .keyword_var => { var resolve_inferred_alloc: ?*zir.Inst = null; const var_data: struct { result_loc: ResultLoc, alloc: *zir.Inst } = if (node.getTypeNode()) |type_node| a: { const type_inst = try typeExpr(mod, scope, type_node); @@ -862,33 +874,39 @@ fn varDecl( } } -fn assign(mod: *Module, scope: *Scope, infix_node: *ast.Node.SimpleInfixOp) InnerError!void { - if (infix_node.lhs.castTag(.Identifier)) |ident| { - // This intentionally does not support @"_" syntax. - const ident_name = scope.tree().tokenSlice(ident.token); +fn assign(mod: *Module, scope: *Scope, infix_node: ast.Node.Index) InnerError!void { + const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); + const lhs = node_datas[infix_node].lhs; + const rhs = node_datas[infix_node].rhs; + if (node_tags[lhs] == .identifier) { + // This intentionally does not support `@"_"` syntax. + const ident_name = tree.tokenSlice(main_tokens[lhs]); if (mem.eql(u8, ident_name, "_")) { _ = try expr(mod, scope, .discard, infix_node.rhs); return; } } - const lvalue = try lvalExpr(mod, scope, infix_node.lhs); - _ = try expr(mod, scope, .{ .ptr = lvalue }, infix_node.rhs); + const lvalue = try lvalExpr(mod, scope, lhs); + _ = try expr(mod, scope, .{ .ptr = lvalue }, rhs); } fn assignOp( mod: *Module, scope: *Scope, - infix_node: *ast.Node.SimpleInfixOp, + infix_node: ast.Node.Index, op_inst_tag: zir.Inst.Tag, ) InnerError!void { - const lhs_ptr = try lvalExpr(mod, scope, infix_node.lhs); + const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); + + const lhs_ptr = try lvalExpr(mod, scope, node_datas[infix_node].lhs); const lhs = try addZIRUnOp(mod, scope, lhs_ptr.src, .deref, lhs_ptr); const lhs_type = try addZIRUnOp(mod, scope, lhs_ptr.src, .typeof, lhs); - const rhs = try expr(mod, scope, .{ .ty = lhs_type }, infix_node.rhs); - - const tree = scope.tree(); - const src = tree.token_locs[infix_node.op_token].start; - + const rhs = try expr(mod, scope, .{ .ty = lhs_type }, node_datas[infix_node].rhs); + const src = token_starts[main_tokens[infix_node]]; const result = try addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs); _ = try addZIRBinOp(mod, scope, src, .store, lhs_ptr, result); } @@ -935,7 +953,7 @@ fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) Inn return addZIRUnOp(mod, scope, src, .optional_type, operand); } -fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.SliceType) InnerError!*zir.Inst { +fn sliceType(mod: *Module, scope: *Scope, node: *ast.Node.slice_type) InnerError!*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.op_token].start; return ptrSliceType(mod, scope, src, &node.ptr_info, node.rhs, .Slice); @@ -948,7 +966,7 @@ fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir .Asterisk, .AsteriskAsterisk => .One, // TODO stage1 type inference bug .LBracket => @as(std.builtin.TypeInfo.Pointer.Size, switch (tree.token_ids[node.op_token + 2]) { - .Identifier => .C, + .identifier => .C, else => .Many, }), else => unreachable, @@ -998,7 +1016,7 @@ fn ptrSliceType(mod: *Module, scope: *Scope, src: usize, ptr_info: *ast.PtrInfo, return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args); } -fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst { +fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.array_type) !*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.op_token].start; const usize_type = try addZIRInstConst(mod, scope, src, .{ @@ -1013,7 +1031,7 @@ fn arrayType(mod: *Module, scope: *Scope, node: *ast.Node.ArrayType) !*zir.Inst return addZIRBinOp(mod, scope, src, .array_type, len, elem_type); } -fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSentinel) !*zir.Inst { +fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.array_type_sentinel) !*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.op_token].start; const usize_type = try addZIRInstConst(mod, scope, src, .{ @@ -1034,7 +1052,7 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, node: *ast.Node.ArrayTypeSenti }, .{}); } -fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.AnyFrameType) InnerError!*zir.Inst { +fn anyFrameType(mod: *Module, scope: *Scope, node: *ast.Node.anyframe_type) InnerError!*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.anyframe_token].start; if (node.result) |some| { @@ -1056,7 +1074,7 @@ fn typeInixOp(mod: *Module, scope: *Scope, node: *ast.Node.SimpleInfixOp, op_ins return addZIRBinOp(mod, scope, src, op_inst_tag, error_set, payload); } -fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.EnumLiteral) !*zir.Inst { +fn enumLiteral(mod: *Module, scope: *Scope, node: *ast.Node.enum_literal) !*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.name].start; const name = try mod.identifierTokenString(scope, node.name); @@ -1141,13 +1159,13 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con var layout: std.builtin.TypeInfo.ContainerLayout = .Auto; if (node.layout_token) |some| switch (tree.token_ids[some]) { - .Keyword_extern => layout = .Extern, - .Keyword_packed => layout = .Packed, + .keyword_extern => layout = .Extern, + .keyword_packed => layout = .Packed, else => unreachable, }; const container_type = switch (tree.token_ids[node.kind_token]) { - .Keyword_enum => blk: { + .keyword_enum => blk: { const tag_type: ?*zir.Inst = switch (node.init_arg_expr) { .Type => |t| try typeExpr(mod, &gen_scope.base, t), .None => null, @@ -1174,7 +1192,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con }; break :blk Type.initPayload(&enum_type.base); }, - .Keyword_struct => blk: { + .keyword_struct => blk: { assert(node.init_arg_expr == .None); const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.StructType, .{ .fields = try arena.dupe(*zir.Inst, fields.items), @@ -1196,7 +1214,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con }; break :blk Type.initPayload(&struct_type.base); }, - .Keyword_union => blk: { + .keyword_union => blk: { const init_inst = switch (node.init_arg_expr) { .Enum => |e| if (e) |t| try typeExpr(mod, &gen_scope.base, t) else null, .None => null, @@ -1229,7 +1247,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con }; break :blk Type.initPayload(&union_type.base); }, - .Keyword_opaque => blk: { + .keyword_opaque => blk: { if (fields.items.len > 0) { return mod.fail(scope, fields.items[0].src, "opaque types cannot have fields", .{}); } @@ -1258,7 +1276,7 @@ fn containerDecl(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Con } } -fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.ErrorSetDecl) InnerError!*zir.Inst { +fn errorSetDecl(mod: *Module, scope: *Scope, node: *ast.Node.error_set_decl) InnerError!*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.error_token].start; const decls = node.decls(); @@ -1281,7 +1299,7 @@ fn errorType(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!* }); } -fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Catch) InnerError!*zir.Inst { +fn catchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.@"catch") InnerError!*zir.Inst { switch (rl) { .ref => return orelseCatchExpr( mod, @@ -1528,7 +1546,7 @@ pub fn field(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleI const tree = scope.tree(); const src = tree.token_locs[node.op_token].start; // TODO custom AST node for field access so that we don't have to go through a node cast here - const field_name = try mod.identifierTokenString(scope, node.rhs.castTag(.Identifier).?.token); + const field_name = try mod.identifierTokenString(scope, node.rhs.castTag(.identifier).?.token); if (rl == .ref) { return addZirInstTag(mod, scope, src, .field_ptr, .{ .object = try expr(mod, scope, .ref, node.lhs), @@ -1545,7 +1563,7 @@ fn namedField( mod: *Module, scope: *Scope, rl: ResultLoc, - call: *ast.Node.BuiltinCall, + call: *ast.Node.builtin_call, ) InnerError!*zir.Inst { try ensureBuiltinParamCount(mod, scope, call, 2); @@ -1571,7 +1589,7 @@ fn namedField( })); } -fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.ArrayAccess) InnerError!*zir.Inst { +fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.array_access) InnerError!*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.rtoken].start; const usize_type = try addZIRInstConst(mod, scope, src, .{ @@ -1592,7 +1610,7 @@ fn arrayAccess(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Array })); } -fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.Slice) InnerError!*zir.Inst { +fn sliceExpr(mod: *Module, scope: *Scope, node: *ast.Node.slice) InnerError!*zir.Inst { const tree = scope.tree(); const src = tree.token_locs[node.rtoken].start; @@ -1633,15 +1651,16 @@ fn simpleBinOp( mod: *Module, scope: *Scope, rl: ResultLoc, - infix_node: *ast.Node.SimpleInfixOp, + infix_node: ast.Node.Index, op_inst_tag: zir.Inst.Tag, ) InnerError!*zir.Inst { const tree = scope.tree(); - const src = tree.token_locs[infix_node.op_token].start; - - const lhs = try expr(mod, scope, .none, infix_node.lhs); - const rhs = try expr(mod, scope, .none, infix_node.rhs); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); + const lhs = try expr(mod, scope, .none, node_datas[infix_node].lhs); + const rhs = try expr(mod, scope, .none, node_datas[infix_node].rhs); + const src = token_starts[main_tokens[infix_node]]; const result = try addZIRBinOp(mod, scope, src, op_inst_tag, lhs, rhs); return rvalue(mod, scope, rl, result); } @@ -1653,6 +1672,9 @@ fn boolBinOp( infix_node: *ast.Node.SimpleInfixOp, ) InnerError!*zir.Inst { const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); + const src = tree.token_locs[infix_node.op_token].start; const bool_type = try addZIRInstConst(mod, scope, src, .{ .ty = Type.initTag(.type), @@ -1703,7 +1725,7 @@ fn boolBinOp( }; defer const_scope.instructions.deinit(mod.gpa); - const is_bool_and = infix_node.base.tag == .BoolAnd; + const is_bool_and = infix_node.base.tag == .bool_and; _ = try addZIRInst(mod, &const_scope.base, src, zir.Inst.Break, .{ .block = block, .operand = try addZIRInstConst(mod, &const_scope.base, src, .{ @@ -1769,7 +1791,7 @@ const CondKind = union(enum) { return &then_scope.base; }; const is_ptr = payload.ptr_token != null; - const ident_node = payload.value_symbol.castTag(.Identifier).?; + const ident_node = payload.value_symbol.castTag(.identifier).?; // This intentionally does not support @"_" syntax. const ident_name = then_scope.base.tree().tokenSlice(ident_node.token); @@ -1788,7 +1810,7 @@ const CondKind = union(enum) { const payload_ptr = try addZIRUnOp(mod, &else_scope.base, src, .err_union_payload_unsafe_ptr, self.err_union.?); const payload = payload_node.?.castTag(.Payload).?; - const ident_node = payload.error_symbol.castTag(.Identifier).?; + const ident_node = payload.error_symbol.castTag(.identifier).?; // This intentionally does not support @"_" syntax. const ident_name = else_scope.base.tree().tokenSlice(ident_node.token); @@ -1800,7 +1822,7 @@ const CondKind = union(enum) { } }; -fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst { +fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.@"if") InnerError!*zir.Inst { var cond_kind: CondKind = .bool; if (if_node.payload) |_| cond_kind = .{ .optional = null }; if (if_node.@"else") |else_node| { @@ -1819,6 +1841,8 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn defer block_scope.instructions.deinit(mod.gpa); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const if_src = tree.token_locs[if_node.if_token].start; const cond = try cond_kind.cond(mod, &block_scope, if_src, if_node.condition); @@ -1918,7 +1942,7 @@ fn whileExpr( mod: *Module, scope: *Scope, rl: ResultLoc, - while_node: *ast.Node.While, + while_node: *ast.Node.@"while", ) InnerError!*zir.Inst { var cond_kind: CondKind = .bool; if (while_node.payload) |_| cond_kind = .{ .optional = null }; @@ -1955,6 +1979,8 @@ fn whileExpr( defer continue_scope.instructions.deinit(mod.gpa); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const while_src = tree.token_locs[while_node.while_token].start; const void_type = try addZIRInstConst(mod, scope, while_src, .{ .ty = Type.initTag(.type), @@ -2066,7 +2092,7 @@ fn forExpr( mod: *Module, scope: *Scope, rl: ResultLoc, - for_node: *ast.Node.For, + for_node: *ast.Node.@"for", ) InnerError!*zir.Inst { if (for_node.label) |label| { try checkLabelRedefinition(mod, scope, label); @@ -2077,6 +2103,8 @@ fn forExpr( // setup variables and constants const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const for_src = tree.token_locs[for_node.for_token].start; const index_ptr = blk: { const usize_type = try addZIRInstConst(mod, scope, for_src, .{ @@ -2246,9 +2274,9 @@ fn forExpr( ); } -fn switchCaseUsesRef(node: *ast.Node.Switch) bool { +fn switchCaseUsesRef(node: *ast.Node.@"switch") bool { for (node.cases()) |uncasted_case| { - const case = uncasted_case.castTag(.SwitchCase).?; + const case = uncasted_case.castTag(.switch_case).?; const uncasted_payload = case.payload orelse continue; const payload = uncasted_payload.castTag(.PointerPayload).?; if (payload.ptr_token) |_| return true; @@ -2260,15 +2288,17 @@ fn getRangeNode(node: *ast.Node) ?*ast.Node.SimpleInfixOp { var cur = node; while (true) { switch (cur.tag) { - .Range => return @fieldParentPtr(ast.Node.SimpleInfixOp, "base", cur), - .GroupedExpression => cur = @fieldParentPtr(ast.Node.GroupedExpression, "base", cur).expr, + .range => return @fieldParentPtr(ast.Node.SimpleInfixOp, "base", cur), + .grouped_expression => cur = @fieldParentPtr(ast.Node.grouped_expression, "base", cur).expr, else => return null, } } } -fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node.Switch) InnerError!*zir.Inst { +fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node.@"switch") InnerError!*zir.Inst { const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const switch_src = tree.token_locs[switch_node.switch_token].start; const use_ref = switchCaseUsesRef(switch_node); @@ -2291,12 +2321,12 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node var first_range: ?*zir.Inst = null; var simple_case_count: usize = 0; for (switch_node.cases()) |uncasted_case| { - const case = uncasted_case.castTag(.SwitchCase).?; + const case = uncasted_case.castTag(.switch_case).?; const case_src = tree.token_locs[case.firstToken()].start; assert(case.items_len != 0); // Check for else/_ prong, those are handled last. - if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) { + if (case.items_len == 1 and case.items()[0].tag == .switch_else) { if (else_src) |src| { const msg = msg: { const msg = try mod.errMsg( @@ -2313,7 +2343,7 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node } else_src = case_src; continue; - } else if (case.items_len == 1 and case.items()[0].tag == .Identifier and + } else if (case.items_len == 1 and case.items()[0].tag == .identifier and mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_")) { if (underscore_src) |src| { @@ -2412,20 +2442,20 @@ fn switchExpr(mod: *Module, scope: *Scope, rl: ResultLoc, switch_node: *ast.Node defer else_scope.instructions.deinit(mod.gpa); // Now generate all but the special cases - var special_case: ?*ast.Node.SwitchCase = null; + var special_case: ?*ast.Node.switch_case = null; var items_index: usize = 0; var case_index: usize = 0; for (switch_node.cases()) |uncasted_case| { - const case = uncasted_case.castTag(.SwitchCase).?; + const case = uncasted_case.castTag(.switch_case).?; const case_src = tree.token_locs[case.firstToken()].start; // reset without freeing to reduce allocations. case_scope.instructions.items.len = 0; // Check for else/_ prong, those are handled last. - if (case.items_len == 1 and case.items()[0].tag == .SwitchElse) { + if (case.items_len == 1 and case.items()[0].tag == .switch_else) { special_case = case; continue; - } else if (case.items_len == 1 and case.items()[0].tag == .Identifier and + } else if (case.items_len == 1 and case.items()[0].tag == .identifier and mem.eql(u8, tree.tokenSlice(case.items()[0].firstToken()), "_")) { special_case = case; @@ -2528,11 +2558,13 @@ fn switchCaseExpr( scope: *Scope, rl: ResultLoc, block: *zir.Inst.Block, - case: *ast.Node.SwitchCase, + case: *ast.Node.switch_case, target: *zir.Inst, target_ptr: ?*zir.Inst, ) !void { const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const case_src = tree.token_locs[case.firstToken()].start; const sub_scope = blk: { const uncasted_payload = case.payload orelse break :blk scope; @@ -2559,6 +2591,8 @@ fn switchCaseExpr( fn ret(mod: *Module, scope: *Scope, cfe: *ast.Node.ControlFlowExpression) InnerError!*zir.Inst { const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[cfe.ltoken].start; if (cfe.getRHS()) |rhs_node| { if (nodeMayNeedMemoryLocation(rhs_node, scope)) { @@ -2580,6 +2614,8 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo defer tracy.end(); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const ident_name = try mod.identifierTokenString(scope, ident.token); const src = tree.token_locs[ident.token].start; if (mem.eql(u8, ident_name, "_")) { @@ -2667,6 +2703,8 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.OneToken) InnerError!*zir.Inst { const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const unparsed_bytes = tree.tokenSlice(str_lit.token); const arena = scope.arena(); @@ -2686,6 +2724,8 @@ fn stringLiteral(mod: *Module, scope: *Scope, str_lit: *ast.Node.OneToken) Inner fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStringLiteral) !*zir.Inst { const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const lines = node.linesConst(); const src = tree.token_locs[lines[0]].start; @@ -2713,6 +2753,8 @@ fn multilineStrLiteral(mod: *Module, scope: *Scope, node: *ast.Node.MultilineStr fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst { const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[node.token].start; const slice = tree.tokenSlice(node.token); @@ -2733,6 +2775,8 @@ fn charLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) !*zir.Inst fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) InnerError!*zir.Inst { const arena = scope.arena(); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const prefixed_bytes = tree.tokenSlice(int_lit.token); const base = if (mem.startsWith(u8, prefixed_bytes, "0x")) 16 @@ -2762,6 +2806,8 @@ fn integerLiteral(mod: *Module, scope: *Scope, int_lit: *ast.Node.OneToken) Inne fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.OneToken) InnerError!*zir.Inst { const arena = scope.arena(); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const bytes = tree.tokenSlice(float_lit.token); if (bytes.len > 2 and bytes[1] == 'x') { return mod.failTok(scope, float_lit.token, "TODO hex floats", .{}); @@ -2780,6 +2826,8 @@ fn floatLiteral(mod: *Module, scope: *Scope, float_lit: *ast.Node.OneToken) Inne fn undefLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst { const arena = scope.arena(); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[node.token].start; return addZIRInstConst(mod, scope, src, .{ .ty = Type.initTag(.@"undefined"), @@ -2790,12 +2838,14 @@ fn undefLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerErro fn boolLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst { const arena = scope.arena(); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[node.token].start; return addZIRInstConst(mod, scope, src, .{ .ty = Type.initTag(.bool), .val = switch (tree.token_ids[node.token]) { - .Keyword_true => Value.initTag(.bool_true), - .Keyword_false => Value.initTag(.bool_false), + .keyword_true => Value.initTag(.bool_true), + .keyword_false => Value.initTag(.bool_false), else => unreachable, }, }); @@ -2804,6 +2854,8 @@ fn boolLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError fn nullLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError!*zir.Inst { const arena = scope.arena(); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[node.token].start; return addZIRInstConst(mod, scope, src, .{ .ty = Type.initTag(.@"null"), @@ -2811,12 +2863,14 @@ fn nullLiteral(mod: *Module, scope: *Scope, node: *ast.Node.OneToken) InnerError }); } -fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst { +fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.@"asm") InnerError!*zir.Inst { if (asm_node.outputs.len != 0) { return mod.failNode(scope, &asm_node.base, "TODO implement asm with an output", .{}); } const arena = scope.arena(); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const inputs = try arena.alloc(*zir.Inst, asm_node.inputs.len); const args = try arena.alloc(*zir.Inst, asm_node.inputs.len); @@ -2839,7 +2893,7 @@ fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zi .ty = Type.initTag(.type), .val = Value.initTag(.void_type), }); - const asm_inst = try addZIRInst(mod, scope, src, zir.Inst.Asm, .{ + const asm_inst = try addZIRInst(mod, scope, src, zir.Inst.@"asm", .{ .asm_source = try expr(mod, scope, str_type_rl, asm_node.template), .return_type = return_type, }, .{ @@ -2851,7 +2905,7 @@ fn assembly(mod: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zi return asm_inst; } -fn ensureBuiltinParamCount(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall, count: u32) !void { +fn ensureBuiltinParamCount(mod: *Module, scope: *Scope, call: *ast.Node.builtin_call, count: u32) !void { if (call.params_len == count) return; @@ -2863,11 +2917,13 @@ fn simpleCast( mod: *Module, scope: *Scope, rl: ResultLoc, - call: *ast.Node.BuiltinCall, + call: *ast.Node.builtin_call, inst_tag: zir.Inst.Tag, ) InnerError!*zir.Inst { try ensureBuiltinParamCount(mod, scope, call, 2); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[call.builtin_token].start; const params = call.params(); const dest_type = try typeExpr(mod, scope, params[0]); @@ -2876,10 +2932,12 @@ fn simpleCast( return rvalue(mod, scope, rl, result); } -fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { +fn ptrToInt(mod: *Module, scope: *Scope, call: *ast.Node.builtin_call) InnerError!*zir.Inst { try ensureBuiltinParamCount(mod, scope, call, 1); const operand = try expr(mod, scope, .none, call.params()[0]); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[call.builtin_token].start; return addZIRUnOp(mod, scope, src, .ptrtoint, operand); } @@ -2888,10 +2946,12 @@ fn as( mod: *Module, scope: *Scope, rl: ResultLoc, - call: *ast.Node.BuiltinCall, + call: *ast.Node.builtin_call, ) InnerError!*zir.Inst { try ensureBuiltinParamCount(mod, scope, call, 2); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[call.builtin_token].start; const params = call.params(); const dest_type = try typeExpr(mod, scope, params[0]); @@ -2963,9 +3023,11 @@ fn asRlPtr( } } -fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { +fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.builtin_call) InnerError!*zir.Inst { try ensureBuiltinParamCount(mod, scope, call, 2); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[call.builtin_token].start; const params = call.params(); const dest_type = try typeExpr(mod, scope, params[0]); @@ -3007,27 +3069,33 @@ fn bitCast(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCa } } -fn import(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { +fn import(mod: *Module, scope: *Scope, call: *ast.Node.builtin_call) InnerError!*zir.Inst { try ensureBuiltinParamCount(mod, scope, call, 1); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[call.builtin_token].start; const params = call.params(); const target = try expr(mod, scope, .none, params[0]); return addZIRUnOp(mod, scope, src, .import, target); } -fn compileError(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { +fn compileError(mod: *Module, scope: *Scope, call: *ast.Node.builtin_call) InnerError!*zir.Inst { try ensureBuiltinParamCount(mod, scope, call, 1); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[call.builtin_token].start; const params = call.params(); const target = try expr(mod, scope, .none, params[0]); return addZIRUnOp(mod, scope, src, .compile_error, target); } -fn setEvalBranchQuota(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { +fn setEvalBranchQuota(mod: *Module, scope: *Scope, call: *ast.Node.builtin_call) InnerError!*zir.Inst { try ensureBuiltinParamCount(mod, scope, call, 1); const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[call.builtin_token].start; const params = call.params(); const u32_type = try addZIRInstConst(mod, scope, src, .{ @@ -3038,8 +3106,10 @@ fn setEvalBranchQuota(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) return addZIRUnOp(mod, scope, src, .set_eval_branch_quota, quota); } -fn typeOf(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { +fn typeOf(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.builtin_call) InnerError!*zir.Inst { const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const arena = scope.arena(); const src = tree.token_locs[call.builtin_token].start; const params = call.params(); @@ -3054,8 +3124,10 @@ fn typeOf(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCal items[param_i] = try expr(mod, scope, .none, param); return rvalue(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.TypeOfPeer, .{ .items = items }, .{})); } -fn compileLog(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { +fn compileLog(mod: *Module, scope: *Scope, call: *ast.Node.builtin_call) InnerError!*zir.Inst { const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const arena = scope.arena(); const src = tree.token_locs[call.builtin_token].start; const params = call.params(); @@ -3065,8 +3137,10 @@ fn compileLog(mod: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerErr return addZIRInst(mod, scope, src, zir.Inst.CompileLog, .{ .to_log = targets }, .{}); } -fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { +fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.builtin_call) InnerError!*zir.Inst { const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const builtin_name = tree.tokenSlice(call.builtin_token); // We handle the different builtins manually because they have different semantics depending @@ -3104,8 +3178,10 @@ fn builtinCall(mod: *Module, scope: *Scope, rl: ResultLoc, call: *ast.Node.Built } } -fn callExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Call) InnerError!*zir.Inst { +fn callExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.call) InnerError!*zir.Inst { const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const lhs = try expr(mod, scope, .none, node.lhs); const param_nodes = node.params(); @@ -3130,6 +3206,8 @@ fn callExpr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.Call) In fn unreach(mod: *Module, scope: *Scope, unreach_node: *ast.Node.OneToken) InnerError!*zir.Inst { const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); const src = tree.token_locs[unreach_node.token].start; return addZIRNoOp(mod, scope, src, .unreachable_safe); } @@ -3176,11 +3254,11 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { while (true) { switch (node.tag) { .Root, - .Use, - .TestDecl, - .DocComment, - .SwitchCase, - .SwitchElse, + .@"usingnamespace", + .test_decl, + .doc_comment, + .switch_case, + .switch_else, .Else, .Payload, .PointerPayload, @@ -3190,97 +3268,97 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { .FieldInitializer, => unreachable, - .Return, - .Break, - .Continue, - .BitNot, - .BoolNot, - .VarDecl, - .Defer, - .AddressOf, - .OptionalType, - .Negation, - .NegationWrap, - .Resume, - .ArrayType, - .ArrayTypeSentinel, + .@"return", + .@"break", + .@"continue", + .bit_not, + .bool_not, + .var_decl, + .@"defer", + .address_of, + .optional_type, + .negation, + .negation_wrap, + .@"resume", + .array_type, + .array_type_sentinel, .PtrType, - .SliceType, - .Suspend, - .AnyType, - .ErrorType, + .slice_type, + .@"suspend", + .@"anytype", + .error_type, .FnProto, - .AnyFrameType, - .IntegerLiteral, - .FloatLiteral, - .EnumLiteral, - .StringLiteral, + .anyframe_type, + .integer_literal, + .float_literal, + .enum_literal, + .string_literal, .MultilineStringLiteral, - .CharLiteral, - .BoolLiteral, - .NullLiteral, - .UndefinedLiteral, - .Unreachable, - .Identifier, - .ErrorSetDecl, + .char_literal, + .bool_literal, + .null_literal, + .undefined_literal, + .@"unreachable", + .identifier, + .error_set_decl, .ContainerDecl, - .Asm, - .Add, - .AddWrap, - .ArrayCat, - .ArrayMult, - .Assign, - .AssignBitAnd, - .AssignBitOr, - .AssignBitShiftLeft, - .AssignBitShiftRight, - .AssignBitXor, - .AssignDiv, - .AssignSub, - .AssignSubWrap, - .AssignMod, - .AssignAdd, - .AssignAddWrap, - .AssignMul, - .AssignMulWrap, - .BangEqual, - .BitAnd, - .BitOr, - .BitShiftLeft, - .BitShiftRight, - .BitXor, - .BoolAnd, - .BoolOr, - .Div, - .EqualEqual, - .ErrorUnion, - .GreaterOrEqual, - .GreaterThan, - .LessOrEqual, - .LessThan, - .MergeErrorSets, - .Mod, - .Mul, - .MulWrap, - .Range, - .Period, - .Sub, - .SubWrap, - .Slice, - .Deref, - .ArrayAccess, - .Block, + .@"asm", + .add, + .add_wrap, + .array_cat, + .array_mult, + .assign, + .assign_bit_and, + .assign_bit_or, + .assign_bit_shift_left, + .assign_bit_shift_right, + .assign_bit_xor, + .assign_div, + .assign_sub, + .assign_sub_wrap, + .assign_mod, + .assign_add, + .assign_add_wrap, + .assign_mul, + .assign_mul_wrap, + .bang_equal, + .bit_and, + .bit_or, + .bit_shift_left, + .bit_shift_right, + .bit_xor, + .bool_and, + .bool_or, + .div, + .equal_equal, + .error_union, + .greater_or_equal, + .greater_than, + .less_or_equal, + .less_than, + .merge_error_sets, + .mod, + .mul, + .mul_wrap, + .range, + .period, + .sub, + .sub_wrap, + .slice, + .deref, + .array_access, + .block, => return false, // Forward the question to a sub-expression. - .GroupedExpression => node = node.castTag(.GroupedExpression).?.expr, - .Try => node = node.castTag(.Try).?.rhs, - .Await => node = node.castTag(.Await).?.rhs, - .Catch => node = node.castTag(.Catch).?.rhs, - .OrElse => node = node.castTag(.OrElse).?.rhs, - .Comptime => node = node.castTag(.Comptime).?.expr, - .Nosuspend => node = node.castTag(.Nosuspend).?.expr, - .UnwrapOptional => node = node.castTag(.UnwrapOptional).?.lhs, + .grouped_expression => node = node.castTag(.grouped_expression).?.expr, + .@"try" => node = node.castTag(.@"try").?.rhs, + .@"await" => node = node.castTag(.@"await").?.rhs, + .@"catch" => node = node.castTag(.@"catch").?.rhs, + .@"orelse" => node = node.castTag(.@"orelse").?.rhs, + .@"comptime" => node = node.castTag(.@"comptime").?.expr, + .@"nosuspend" => node = node.castTag(.@"nosuspend").?.expr, + .unwrap_optional => node = node.castTag(.unwrap_optional).?.lhs, // True because these are exactly the expressions we need memory locations for. .ArrayInitializer, @@ -3291,14 +3369,14 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { // True because depending on comptime conditions, sub-expressions // may be the kind that need memory locations. - .While, - .For, - .Switch, - .Call, - .LabeledBlock, + .@"while", + .@"for", + .@"switch", + .call, + .labeled_block, => return true, - .BuiltinCall => { + .builtin_call => { @setEvalBranchQuota(5000); const builtin_needs_mem_loc = std.ComptimeStringMap(bool, .{ .{ "@addWithOverflow", false }, @@ -3404,12 +3482,12 @@ fn nodeMayNeedMemoryLocation(start_node: *ast.Node, scope: *Scope) bool { .{ "@TypeOf", false }, .{ "@unionInit", true }, }); - const name = scope.tree().tokenSlice(node.castTag(.BuiltinCall).?.builtin_token); + const name = scope.tree().tokenSlice(node.castTag(.builtin_call).?.builtin_token); return builtin_needs_mem_loc.get(name).?; }, // Depending on AST properties, they may need memory locations. - .If => return node.castTag(.If).?.@"else" != null, + .@"if" => return node.castTag(.@"if").?.@"else" != null, } } } @@ -3450,8 +3528,17 @@ fn rvalue(mod: *Module, scope: *Scope, rl: ResultLoc, result: *zir.Inst) InnerEr } } -fn rvalueVoid(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node, result: void) InnerError!*zir.Inst { - const src = scope.tree().token_locs[node.firstToken()].start; +fn rvalueVoid( + mod: *Module, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + result: void, +) InnerError!*zir.Inst { + const tree = scope.tree(); + const node_datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); + const src = tree.tokens.items(.start)[tree.firstToken(node)]; const void_inst = try addZIRInstConst(mod, scope, src, .{ .ty = Type.initTag(.void), .val = Value.initTag(.void_value), diff --git a/src/codegen.zig b/src/codegen.zig index 9771386403..095bb123ba 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -451,11 +451,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { const src_data: struct { lbrace_src: usize, rbrace_src: usize, source: []const u8 } = blk: { const container_scope = module_fn.owner_decl.container; - const tree = container_scope.file_scope.contents.tree; - const fn_proto = tree.root_node.decls()[module_fn.owner_decl.src_index].castTag(.FnProto).?; - const block = fn_proto.getBodyNode().?.castTag(.Block).?; - const lbrace_src = tree.token_locs[block.lbrace].start; - const rbrace_src = tree.token_locs[block.rbrace].start; + const tree = container_scope.file_scope.tree; + const node_tags = tree.nodes.items(.tag); + const node_datas = tree.nodes.items(.data); + const token_starts = tree.tokens.items(.start); + + const fn_decl = tree.rootDecls()[module_fn.owner_decl.src_index]; + assert(node_tags[fn_decl] == .fn_decl); + const block = node_datas[fn_decl].rhs; + const lbrace_src = token_starts[tree.firstToken(block)]; + const rbrace_src = token_starts[tree.lastToken(block)]; break :blk .{ .lbrace_src = lbrace_src, .rbrace_src = rbrace_src, diff --git a/src/ir.zig b/src/ir.zig index 0e83dbfd56..a0b33fba73 100644 --- a/src/ir.zig +++ b/src/ir.zig @@ -317,6 +317,7 @@ pub const Inst = struct { pub const base_tag = Tag.arg; base: Inst, + /// This exists to be emitted into debug info. name: [*:0]const u8, pub fn operandCount(self: *const Arg) usize { diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 18f3f57712..f92c585cd5 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -2223,13 +2223,19 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void { try dbg_line_buffer.ensureCapacity(26); const line_off: u28 = blk: { - const tree = decl.container.file_scope.contents.tree; - const file_ast_decls = tree.root_node.decls(); + const tree = decl.container.file_scope.tree; + const node_tags = tree.nodes.items(.tag); + const node_datas = tree.nodes.items(.data); + const token_starts = tree.tokens.items(.start); + + const file_ast_decls = tree.rootDecls(); // TODO Look into improving the performance here by adding a token-index-to-line // lookup table. Currently this involves scanning over the source code for newlines. - const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; - const block = fn_proto.getBodyNode().?.castTag(.Block).?; - const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); + const fn_decl = file_ast_decls[decl.src_index]; + assert(node_tags[fn_decl] == .fn_decl); + const block = node_datas[fn_decl].rhs; + const lbrace = tree.firstToken(block); + const line_delta = std.zig.lineDelta(tree.source, 0, token_starts[lbrace]); break :blk @intCast(u28, line_delta); }; @@ -2744,13 +2750,19 @@ pub fn updateDeclLineNumber(self: *Elf, module: *Module, decl: *const Module.Dec if (self.llvm_ir_module) |_| return; - const tree = decl.container.file_scope.contents.tree; - const file_ast_decls = tree.root_node.decls(); + const tree = decl.container.file_scope.tree; + const node_tags = tree.nodes.items(.tag); + const node_datas = tree.nodes.items(.data); + const token_starts = tree.tokens.items(.start); + + const file_ast_decls = tree.rootDecls(); // TODO Look into improving the performance here by adding a token-index-to-line // lookup table. Currently this involves scanning over the source code for newlines. - const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; - const block = fn_proto.getBodyNode().?.castTag(.Block).?; - const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); + const fn_decl = file_ast_decls[decl.src_index]; + assert(node_tags[fn_decl] == .fn_decl); + const block = node_datas[fn_decl].rhs; + const lbrace = tree.firstToken(block); + const line_delta = std.zig.lineDelta(tree.source, 0, token_starts[lbrace]); const casted_line_off = @intCast(u28, line_delta); const shdr = &self.sections.items[self.debug_line_section_index.?]; diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 15aa86be51..645e17068b 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -904,13 +904,19 @@ pub fn updateDeclLineNumber(self: *DebugSymbols, module: *Module, decl: *const M const tracy = trace(@src()); defer tracy.end(); - const tree = decl.container.file_scope.contents.tree; - const file_ast_decls = tree.root_node.decls(); + const tree = decl.container.file_scope.tree; + const node_tags = tree.nodes.items(.tag); + const node_datas = tree.nodes.items(.data); + const token_starts = tree.tokens.items(.start); + + const file_ast_decls = tree.rootDecls(); // TODO Look into improving the performance here by adding a token-index-to-line // lookup table. Currently this involves scanning over the source code for newlines. - const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; - const block = fn_proto.getBodyNode().?.castTag(.Block).?; - const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); + const fn_decl = file_ast_decls[decl.src_index]; + assert(node_tags[fn_decl] == .fn_decl); + const block = node_datas[fn_decl].rhs; + const lbrace = tree.firstToken(block); + const line_delta = std.zig.lineDelta(tree.source, 0, token_starts[lbrace]); const casted_line_off = @intCast(u28, line_delta); const dwarf_segment = &self.load_commands.items[self.dwarf_segment_cmd_index.?].Segment; @@ -948,13 +954,19 @@ pub fn initDeclDebugBuffers( try dbg_line_buffer.ensureCapacity(26); const line_off: u28 = blk: { - const tree = decl.container.file_scope.contents.tree; - const file_ast_decls = tree.root_node.decls(); + const tree = decl.container.file_scope.tree; + const node_tags = tree.nodes.items(.tag); + const node_datas = tree.nodes.items(.data); + const token_starts = tree.tokens.items(.start); + + const file_ast_decls = tree.rootDecls(); // TODO Look into improving the performance here by adding a token-index-to-line // lookup table. Currently this involves scanning over the source code for newlines. - const fn_proto = file_ast_decls[decl.src_index].castTag(.FnProto).?; - const block = fn_proto.getBodyNode().?.castTag(.Block).?; - const line_delta = std.zig.lineDelta(tree.source, 0, tree.token_locs[block.lbrace].start); + const fn_decl = file_ast_decls[decl.src_index]; + assert(node_tags[fn_decl] == .fn_decl); + const block = node_datas[fn_decl].rhs; + const lbrace = tree.firstToken(block); + const line_delta = std.zig.lineDelta(tree.source, 0, token_starts[lbrace]); break :blk @intCast(u28, line_delta); }; diff --git a/src/zir.zig b/src/zir.zig index d8ac023562..fc68aee216 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -53,6 +53,9 @@ pub const Inst = struct { indexable_ptr_len, /// Function parameter value. These must be first in a function's main block, /// in respective order with the parameters. + /// TODO make this instruction implicit; after we transition to having ZIR + /// instructions be same sized and referenced by index, the first N indexes + /// will implicitly be references to the parameters of the function. arg, /// Type coercion. as, @@ -354,9 +357,8 @@ pub const Inst = struct { .return_void, .ret_ptr, .ret_type, - .unreach_nocheck, - .@"unreachable", - .arg, + .unreachable_unsafe, + .unreachable_safe, .void_value, => NoOp, @@ -451,6 +453,7 @@ pub const Inst = struct { .block_comptime_flat, => Block, + .arg => Arg, .array_type_sentinel => ArrayTypeSentinel, .@"break" => Break, .break_void => BreakVoid, @@ -684,6 +687,18 @@ pub const Inst = struct { kw_args: struct {}, }; + pub const Arg = struct { + pub const base_tag = Tag.arg; + base: Inst, + + positionals: struct { + /// This exists to be passed to the arg TZIR instruction, which + /// needs it for debug info. + name: []const u8, + }, + kw_args: struct {}, + }; + pub const Block = struct { pub const base_tag = Tag.block; base: Inst,