From 4bb5d17edc85eac74626224810d6a44a3c73cca3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 28 Aug 2021 15:15:46 -0700 Subject: AstGen: pre-scan all decls in a namespace Also: * improve the "ambiguous reference" error by swapping the order of "declared here" and "also declared here" notes. * improve the "not accessible from inner function" error: - point out that it has to do with the thing being mutable - eliminate the incorrect association with it being a function - note where it crosses a namespace boundary * struct field types are evaluated in a context that has the struct namespace visible. Likewise with align expressions, linksection expressions, enum tag values, and union/enum tag argument expressions. Closes #9194 Closes #9622 --- src/Module.zig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/Module.zig') diff --git a/src/Module.zig b/src/Module.zig index 4ed39c9954..77f880b492 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -2648,7 +2648,10 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void { undefined; defer if (data_has_safety_tag) gpa.free(safety_buffer); const data_ptr = if (data_has_safety_tag) - @ptrCast([*]const u8, safety_buffer.ptr) + if (file.zir.instructions.len == 0) + @as([*]const u8, undefined) + else + @ptrCast([*]const u8, safety_buffer.ptr) else @ptrCast([*]const u8, file.zir.instructions.items(.data).ptr); if (data_has_safety_tag) { -- cgit v1.2.3 From 332eafeb7f3d866556ab767b960a04661bc43bc7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 28 Aug 2021 15:35:59 -0700 Subject: stage2: first pass at implementing usingnamespace Ran into a design flaw here which will need to get solved by having AstGen annotate ZIR with which instructions are closed over. --- src/AstGen.zig | 5 +- src/Module.zig | 62 ++++++++++--- src/Sema.zig | 115 ++++++++++++++++++++---- src/codegen.zig | 26 +++--- src/codegen/aarch64.zig | 2 +- src/codegen/arm.zig | 2 +- src/codegen/riscv64.zig | 4 +- src/codegen/x86.zig | 16 ++-- src/codegen/x86_64.zig | 34 +++---- src/link.zig | 2 +- src/link/Elf.zig | 152 ++++++++++++++++---------------- src/link/MachO/DebugSymbols.zig | 140 ++++++++++++++--------------- src/link/MachO/Object.zig | 4 +- test/behavior.zig | 3 +- test/behavior/eval.zig | 6 -- test/behavior/usingnamespace.zig | 23 ++--- test/behavior/usingnamespace_stage1.zig | 22 +++++ test/compile_errors.zig | 10 +++ 18 files changed, 385 insertions(+), 243 deletions(-) create mode 100644 test/behavior/usingnamespace_stage1.zig (limited to 'src/Module.zig') diff --git a/src/AstGen.zig b/src/AstGen.zig index 245e40c3a1..c96a97ddeb 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -6416,6 +6416,9 @@ fn identifier( }, .top => break, }; + if (found_already == null) { + return astgen.failNode(ident, "use of undeclared identifier '{s}'", .{ident_name}); + } // Decl references happen by name rather than ZIR index so that when unrelated // decls are modified, ZIR code containing references to them can be unmodified. @@ -10052,7 +10055,7 @@ fn isPrimitive(name: []const u8) bool { } } -/// Local variables shadowing detection, including function parameters and primitives. +/// Local variables shadowing detection, including function parameters. fn detectLocalShadowing( astgen: *AstGen, scope: *Scope, diff --git a/src/Module.zig b/src/Module.zig index 77f880b492..c17780cdc3 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -365,6 +365,8 @@ pub const Decl = struct { /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it /// deletes the Decl on the spot. alive: bool, + /// Whether the Decl is a `usingnamespace` declaration. + is_usingnamespace: bool, /// Represents the position of the code in the output file. /// This is populated regardless of semantic analysis and code generation. @@ -1008,6 +1010,11 @@ pub const Scope = struct { anon_decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{}, + /// Key is usingnamespace Decl itself. To find the namespace being included, + /// the Decl Value has to be resolved as a Type which has a Namespace. + /// Value is whether the usingnamespace decl is marked `pub`. + usingnamespace_set: std.AutoHashMapUnmanaged(*Decl, bool) = .{}, + pub fn deinit(ns: *Namespace, mod: *Module) void { ns.destroyDecls(mod); ns.* = undefined; @@ -3174,6 +3181,31 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { errdefer decl_arena.deinit(); const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); + if (decl.is_usingnamespace) { + const ty_ty = Type.initTag(.type); + if (!decl_tv.ty.eql(ty_ty)) { + return mod.fail(&block_scope.base, src, "expected type, found {}", .{decl_tv.ty}); + } + var buffer: Value.ToTypeBuffer = undefined; + const ty = decl_tv.val.toType(&buffer); + if (ty.getNamespace() == null) { + return mod.fail(&block_scope.base, src, "type {} has no namespace", .{ty}); + } + + decl.ty = ty_ty; + decl.val = try Value.Tag.ty.create(&decl_arena.allocator, ty); + decl.align_val = Value.initTag(.null_value); + decl.linksection_val = Value.initTag(.null_value); + decl.has_tv = true; + decl.owns_tv = false; + decl_arena_state.* = decl_arena.state; + decl.value_arena = decl_arena_state; + decl.analysis = .complete; + decl.generation = mod.generation; + + return true; + } + if (decl_tv.val.castTag(.function)) |fn_payload| { const func = fn_payload.data; const owns_tv = func.owner_decl == decl; @@ -3269,16 +3301,13 @@ fn semaDecl(mod: *Module, decl: *Decl) !bool { if (type_changed and mod.emit_h != null) { try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl }); } - } else if (decl_tv.ty.zigTypeTag() == .Type) { - // In case this Decl is a struct or union, we need to resolve the fields - // while we still have the `Sema` in scope, so that the field type expressions - // can use the resolved AIR instructions that they possibly reference. - // We do this after the decl is populated and set to `complete` so that a `Decl` - // may reference itself. - var buffer: Value.ToTypeBuffer = undefined; - const ty = decl.val.toType(&buffer); - try sema.resolveDeclFields(&block_scope, src, ty); } + // In case this Decl is a struct or union, we need to resolve the fields + // while we still have the `Sema` in scope, so that the field type expressions + // can use the resolved AIR instructions that they possibly reference. + // We do this after the decl is populated and set to `complete` so that a `Decl` + // may reference itself. + try sema.resolvePendingTypes(&block_scope); if (decl.is_exported) { const export_src = src; // TODO point to the export token @@ -3494,7 +3523,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi // zig fmt: off const is_pub = (flags & 0b0001) != 0; - const is_exported = (flags & 0b0010) != 0; + const export_bit = (flags & 0b0010) != 0; const has_align = (flags & 0b0100) != 0; const has_linksection = (flags & 0b1000) != 0; // zig fmt: on @@ -3509,7 +3538,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi var is_named_test = false; const decl_name: [:0]const u8 = switch (decl_name_index) { 0 => name: { - if (is_exported) { + if (export_bit) { const i = iter.usingnamespace_index; iter.usingnamespace_index += 1; break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i}); @@ -3535,11 +3564,17 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi } }, }; + const is_exported = export_bit and decl_name_index != 0; + const is_usingnamespace = export_bit and decl_name_index == 0; + if (is_usingnamespace) try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1); // We create a Decl for it regardless of analysis status. const gop = try namespace.decls.getOrPut(gpa, decl_name); if (!gop.found_existing) { const new_decl = try mod.allocateNewDecl(namespace, decl_node); + if (is_usingnamespace) { + namespace.usingnamespace_set.putAssumeCapacity(new_decl, is_pub); + } log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace }); new_decl.src_line = line; new_decl.name = decl_name; @@ -3548,7 +3583,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi // test decls if in test mode, get analyzed. const decl_pkg = namespace.file_scope.pkg; const want_analysis = is_exported or switch (decl_name_index) { - 0 => true, // comptime decl + 0 => true, // comptime or usingnamespace decl 1 => blk: { // test decl with no name. Skip the part where we check against // the test name filter. @@ -3571,6 +3606,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi } new_decl.is_pub = is_pub; new_decl.is_exported = is_exported; + new_decl.is_usingnamespace = is_usingnamespace; new_decl.has_align = has_align; new_decl.has_linksection = has_linksection; new_decl.zir_decl_index = @intCast(u32, decl_sub_index); @@ -3587,6 +3623,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) SemaError!voi decl.is_pub = is_pub; decl.is_exported = is_exported; + decl.is_usingnamespace = is_usingnamespace; decl.has_align = has_align; decl.has_linksection = has_linksection; decl.zir_decl_index = @intCast(u32, decl_sub_index); @@ -3979,6 +4016,7 @@ pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast. .has_linksection = false, .has_align = false, .alive = false, + .is_usingnamespace = false, }; return new_decl; } diff --git a/src/Sema.zig b/src/Sema.zig index 108470ec79..b3eb3b1b85 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -58,6 +58,9 @@ comptime_args_fn_inst: Zir.Inst.Index = 0, /// extra hash table lookup in the `monomorphed_funcs` set. /// Sema will set this to null when it takes ownership. preallocated_new_func: ?*Module.Fn = null, +/// Collects struct, union, enum, and opaque decls which need to have their +/// fields resolved before this Sema is deinitialized. +types_pending_resolution: std.ArrayListUnmanaged(Type) = .{}, const std = @import("std"); const mem = std.mem; @@ -90,6 +93,7 @@ pub fn deinit(sema: *Sema) void { sema.air_values.deinit(gpa); sema.inst_map.deinit(gpa); sema.decl_val_table.deinit(gpa); + sema.types_pending_resolution.deinit(gpa); sema.* = undefined; } @@ -908,7 +912,9 @@ fn zirStructDecl( &struct_obj.namespace, new_decl, new_decl.name, }); try sema.analyzeStructDecl(new_decl, inst, struct_obj); + try sema.types_pending_resolution.ensureUnusedCapacity(sema.gpa, 1); try new_decl.finalizeNewArena(&new_decl_arena); + sema.types_pending_resolution.appendAssumeCapacity(struct_ty); return sema.analyzeDeclVal(block, src, new_decl); } @@ -1198,7 +1204,9 @@ fn zirUnionDecl( _ = try sema.mod.scanNamespace(&union_obj.namespace, extra_index, decls_len, new_decl); + try sema.types_pending_resolution.ensureUnusedCapacity(sema.gpa, 1); try new_decl.finalizeNewArena(&new_decl_arena); + sema.types_pending_resolution.appendAssumeCapacity(union_ty); return sema.analyzeDeclVal(block, src, new_decl); } @@ -2324,42 +2332,105 @@ fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr } fn lookupIdentifier(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, name: []const u8) !*Decl { - // TODO emit a compile error if more than one decl would be matched. var namespace = sema.namespace; while (true) { - if (try sema.lookupInNamespace(namespace, name)) |decl| { + if (try sema.lookupInNamespace(block, src, namespace, name, false)) |decl| { return decl; } namespace = namespace.parent orelse break; } - return sema.mod.fail(&block.base, src, "use of undeclared identifier '{s}'", .{name}); + unreachable; // AstGen detects use of undeclared identifier errors. } /// This looks up a member of a specific namespace. It is affected by `usingnamespace` but /// only for ones in the specified namespace. fn lookupInNamespace( sema: *Sema, + block: *Scope.Block, + src: LazySrcLoc, namespace: *Scope.Namespace, ident_name: []const u8, + observe_usingnamespace: bool, ) CompileError!?*Decl { + const mod = sema.mod; + const namespace_decl = namespace.getDecl(); if (namespace_decl.analysis == .file_failure) { - try sema.mod.declareDeclDependency(sema.owner_decl, namespace_decl); + try mod.declareDeclDependency(sema.owner_decl, namespace_decl); return error.AnalysisFail; } - // TODO implement usingnamespace - if (namespace.decls.get(ident_name)) |decl| { - try sema.mod.declareDeclDependency(sema.owner_decl, decl); + if (observe_usingnamespace and namespace.usingnamespace_set.count() != 0) { + const src_file = block.src_decl.namespace.file_scope; + + const gpa = sema.gpa; + var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Scope.Namespace, void) = .{}; + defer checked_namespaces.deinit(gpa); + + // Keep track of name conflicts for error notes. + var candidates: std.ArrayListUnmanaged(*Decl) = .{}; + defer candidates.deinit(gpa); + + try checked_namespaces.put(gpa, namespace, {}); + var check_i: usize = 0; + + while (check_i < checked_namespaces.count()) : (check_i += 1) { + const check_ns = checked_namespaces.keys()[check_i]; + if (check_ns.decls.get(ident_name)) |decl| { + // Skip decls which are not marked pub, which are in a different + // file than the `a.b`/`@hasDecl` syntax. + if (decl.is_pub or src_file == decl.namespace.file_scope) { + try candidates.append(gpa, decl); + } + } + var it = check_ns.usingnamespace_set.iterator(); + while (it.next()) |entry| { + const sub_usingnamespace_decl = entry.key_ptr.*; + const sub_is_pub = entry.value_ptr.*; + if (!sub_is_pub and src_file != sub_usingnamespace_decl.namespace.file_scope) { + // Skip usingnamespace decls which are not marked pub, which are in + // a different file than the `a.b`/`@hasDecl` syntax. + continue; + } + try sema.ensureDeclAnalyzed(sub_usingnamespace_decl); + const ns_ty = sub_usingnamespace_decl.val.castTag(.ty).?.data; + const sub_ns = ns_ty.getNamespace().?; + try checked_namespaces.put(gpa, sub_ns, {}); + } + } + + switch (candidates.items.len) { + 0 => {}, + 1 => { + const decl = candidates.items[0]; + try mod.declareDeclDependency(sema.owner_decl, decl); + return decl; + }, + else => { + const msg = msg: { + const msg = try mod.errMsg(&block.base, src, "ambiguous reference", .{}); + errdefer msg.destroy(gpa); + for (candidates.items) |candidate| { + const src_loc = candidate.srcLoc(); + try mod.errNoteNonLazy(src_loc, msg, "declared here", .{}); + } + break :msg msg; + }; + return mod.failWithOwnedErrorMsg(&block.base, msg); + }, + } + } else if (namespace.decls.get(ident_name)) |decl| { + try mod.declareDeclDependency(sema.owner_decl, decl); return decl; } + log.debug("{*} ({s}) depends on non-existence of '{s}' in {*} ({s})", .{ sema.owner_decl, sema.owner_decl.name, ident_name, namespace_decl, namespace_decl.name, }); // TODO This dependency is too strong. Really, it should only be a dependency // on the non-existence of `ident_name` in the namespace. We can lessen the number of // outdated declarations by making this dependency more sophisticated. - try sema.mod.declareDeclDependency(sema.owner_decl, namespace_decl); + try mod.declareDeclDependency(sema.owner_decl, namespace_decl); return null; } @@ -2727,10 +2798,7 @@ fn analyzeCall( // we need to resolve the field type expressions right here, right now, while // the child `Sema` is still available, with the AIR instruction map intact, // because the field type expressions may reference into it. - if (sema.typeOf(result).zigTypeTag() == .Type) { - const ty = try sema.analyzeAsType(&child_block, call_src, result); - try sema.resolveDeclFields(&child_block, call_src, ty); - } + try sema.resolvePendingTypes(&child_block); } break :res2 result; @@ -5332,6 +5400,7 @@ fn zirHasField(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; + const src = inst_data.src(); const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; const container_type = try sema.resolveType(block, lhs_src, extra.lhs); @@ -5344,7 +5413,7 @@ fn zirHasDecl(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileErr "expected struct, enum, union, or opaque, found '{}'", .{container_type}, ); - if (try sema.lookupInNamespace(namespace, decl_name)) |decl| { + if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl| { if (decl.is_pub or decl.namespace.file_scope == block.base.namespace().file_scope) { return Air.Inst.Ref.bool_true; } @@ -8203,7 +8272,7 @@ fn namespaceLookup( ) CompileError!?*Decl { const mod = sema.mod; const gpa = sema.gpa; - if (try sema.lookupInNamespace(namespace, decl_name)) |decl| { + if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl| { if (!decl.is_pub and decl.namespace.file_scope != block.getFileScope()) { const msg = msg: { const msg = try mod.errMsg(&block.base, src, "'{s}' is not marked 'pub'", .{ @@ -8919,8 +8988,7 @@ fn analyzeDeclVal( return result; } -fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref { - try sema.mod.declareDeclDependency(sema.owner_decl, decl); +fn ensureDeclAnalyzed(sema: *Sema, decl: *Decl) CompileError!void { sema.mod.ensureDeclAnalyzed(decl) catch |err| { if (sema.owner_func) |owner_func| { owner_func.state = .dependency_failure; @@ -8929,6 +8997,11 @@ fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref { } return err; }; +} + +fn analyzeDeclRef(sema: *Sema, decl: *Decl) CompileError!Air.Inst.Ref { + try sema.mod.declareDeclDependency(sema.owner_decl, decl); + try sema.ensureDeclAnalyzed(decl); const decl_tv = try decl.typedValue(); if (decl_tv.val.castTag(.variable)) |payload| { @@ -9560,6 +9633,16 @@ pub fn resolveTypeLayout( } } +pub fn resolvePendingTypes(sema: *Sema, block: *Scope.Block) !void { + for (sema.types_pending_resolution.items) |ty| { + // If an error happens resolving the fields of a struct, it will be marked + // invalid and a proper compile error set up. But we should still look at the + // other types pending resolution. + const src: LazySrcLoc = .{ .node_offset = 0 }; + sema.resolveDeclFields(block, src, ty) catch continue; + } +} + /// `sema` and `block` are expected to be the same ones used for the `Decl`. pub fn resolveDeclFields(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ty: Type) !void { switch (ty.tag()) { diff --git a/src/codegen.zig b/src/codegen.zig index cf51f30fe3..0a8797d887 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -899,7 +899,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { fn dbgSetPrologueEnd(self: *Self) InnerError!void { switch (self.debug_output) { .dwarf => |dbg_out| { - try dbg_out.dbg_line.append(DW.LNS_set_prologue_end); + try dbg_out.dbg_line.append(DW.LNS.set_prologue_end); try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); }, .none => {}, @@ -909,7 +909,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { fn dbgSetEpilogueBegin(self: *Self) InnerError!void { switch (self.debug_output) { .dwarf => |dbg_out| { - try dbg_out.dbg_line.append(DW.LNS_set_epilogue_begin); + try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin); try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column); }, .none => {}, @@ -925,13 +925,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { // It lets you emit single-byte opcodes that add different numbers to // both the PC and the line number at the same time. try dbg_out.dbg_line.ensureUnusedCapacity(11); - dbg_out.dbg_line.appendAssumeCapacity(DW.LNS_advance_pc); + dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_pc); leb128.writeULEB128(dbg_out.dbg_line.writer(), delta_pc) catch unreachable; if (delta_line != 0) { - dbg_out.dbg_line.appendAssumeCapacity(DW.LNS_advance_line); + dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.advance_line); leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable; } - dbg_out.dbg_line.appendAssumeCapacity(DW.LNS_copy); + dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy); }, .none => {}, } @@ -1010,7 +1010,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .dwarf => |dbg_out| { assert(ty.hasCodeGenBits()); const index = dbg_out.dbg_info.items.len; - try dbg_out.dbg_info.resize(index + 4); // DW.AT_type, DW.FORM_ref4 + try dbg_out.dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4 const gop = try dbg_out.dbg_info_type_relocs.getOrPut(self.gpa, ty); if (!gop.found_existing) { @@ -2438,13 +2438,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { .dwarf => |dbg_out| { try dbg_out.dbg_info.ensureCapacity(dbg_out.dbg_info.items.len + 3); dbg_out.dbg_info.appendAssumeCapacity(link.File.Elf.abbrev_parameter); - dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT_location, DW.FORM_exprloc + dbg_out.dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc 1, // ULEB128 dwarf expression length reg.dwarfLocOp(), }); try dbg_out.dbg_info.ensureCapacity(dbg_out.dbg_info.items.len + 5 + name_with_null.len); - try self.addDbgInfoTypeReloc(ty); // DW.AT_type, DW.FORM_ref4 - dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT_name, DW.FORM_string + try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 + dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string }, .none => {}, } @@ -2467,15 +2467,15 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { var counting_writer = std.io.countingWriter(std.io.null_writer); leb128.writeILEB128(counting_writer.writer(), adjusted_stack_offset) catch unreachable; - // DW.AT_location, DW.FORM_exprloc + // DW.AT.location, DW.FORM.exprloc // ULEB128 dwarf expression length try leb128.writeULEB128(dbg_out.dbg_info.writer(), counting_writer.bytes_written + 1); - try dbg_out.dbg_info.append(DW.OP_breg11); + try dbg_out.dbg_info.append(DW.OP.breg11); try leb128.writeILEB128(dbg_out.dbg_info.writer(), adjusted_stack_offset); try dbg_out.dbg_info.ensureCapacity(dbg_out.dbg_info.items.len + 5 + name_with_null.len); - try self.addDbgInfoTypeReloc(ty); // DW.AT_type, DW.FORM_ref4 - dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT_name, DW.FORM_string + try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4 + dbg_out.dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string }, else => {}, } diff --git a/src/codegen/aarch64.zig b/src/codegen/aarch64.zig index 1c176df017..dfda04da85 100644 --- a/src/codegen/aarch64.zig +++ b/src/codegen/aarch64.zig @@ -52,7 +52,7 @@ pub const Register = enum(u6) { } pub fn dwarfLocOp(self: Register) u8 { - return @as(u8, self.id()) + DW.OP_reg0; + return @as(u8, self.id()) + DW.OP.reg0; } }; diff --git a/src/codegen/arm.zig b/src/codegen/arm.zig index 42e3e52fac..ec9152f96b 100644 --- a/src/codegen/arm.zig +++ b/src/codegen/arm.zig @@ -170,7 +170,7 @@ pub const Register = enum(u5) { } pub fn dwarfLocOp(self: Register) u8 { - return @as(u8, self.id()) + DW.OP_reg0; + return @as(u8, self.id()) + DW.OP.reg0; } }; diff --git a/src/codegen/riscv64.zig b/src/codegen/riscv64.zig index 831f74b1b7..b297737816 100644 --- a/src/codegen/riscv64.zig +++ b/src/codegen/riscv64.zig @@ -390,7 +390,7 @@ pub const RawRegister = enum(u5) { x24, x25, x26, x27, x28, x29, x30, x31, pub fn dwarfLocOp(reg: RawRegister) u8 { - return @enumToInt(reg) + DW.OP_reg0; + return @enumToInt(reg) + DW.OP.reg0; } }; @@ -424,7 +424,7 @@ pub const Register = enum(u5) { } pub fn dwarfLocOp(reg: Register) u8 { - return @as(u8, @enumToInt(reg)) + DW.OP_reg0; + return @as(u8, @enumToInt(reg)) + DW.OP.reg0; } }; diff --git a/src/codegen/x86.zig b/src/codegen/x86.zig index fdad4e56db..5b981b9ef4 100644 --- a/src/codegen/x86.zig +++ b/src/codegen/x86.zig @@ -59,14 +59,14 @@ pub const Register = enum(u8) { pub fn dwarfLocOp(reg: Register) u8 { return switch (reg.to32()) { - .eax => DW.OP_reg0, - .ecx => DW.OP_reg1, - .edx => DW.OP_reg2, - .ebx => DW.OP_reg3, - .esp => DW.OP_reg4, - .ebp => DW.OP_reg5, - .esi => DW.OP_reg6, - .edi => DW.OP_reg7, + .eax => DW.OP.reg0, + .ecx => DW.OP.reg1, + .edx => DW.OP.reg2, + .ebx => DW.OP.reg3, + .esp => DW.OP.reg4, + .ebp => DW.OP.reg5, + .esi => DW.OP.reg6, + .edi => DW.OP.reg7, else => unreachable, }; } diff --git a/src/codegen/x86_64.zig b/src/codegen/x86_64.zig index 2964d7245e..72a7468041 100644 --- a/src/codegen/x86_64.zig +++ b/src/codegen/x86_64.zig @@ -115,23 +115,23 @@ pub const Register = enum(u8) { pub fn dwarfLocOp(self: Register) u8 { return switch (self.to64()) { - .rax => DW.OP_reg0, - .rdx => DW.OP_reg1, - .rcx => DW.OP_reg2, - .rbx => DW.OP_reg3, - .rsi => DW.OP_reg4, - .rdi => DW.OP_reg5, - .rbp => DW.OP_reg6, - .rsp => DW.OP_reg7, - - .r8 => DW.OP_reg8, - .r9 => DW.OP_reg9, - .r10 => DW.OP_reg10, - .r11 => DW.OP_reg11, - .r12 => DW.OP_reg12, - .r13 => DW.OP_reg13, - .r14 => DW.OP_reg14, - .r15 => DW.OP_reg15, + .rax => DW.OP.reg0, + .rdx => DW.OP.reg1, + .rcx => DW.OP.reg2, + .rbx => DW.OP.reg3, + .rsi => DW.OP.reg4, + .rdi => DW.OP.reg5, + .rbp => DW.OP.reg6, + .rsp => DW.OP.reg7, + + .r8 => DW.OP.reg8, + .r9 => DW.OP.reg9, + .r10 => DW.OP.reg10, + .r11 => DW.OP.reg11, + .r12 => DW.OP.reg12, + .r13 => DW.OP.reg13, + .r14 => DW.OP.reg14, + .r15 => DW.OP.reg15, else => unreachable, }; diff --git a/src/link.zig b/src/link.zig index 1293fab4d2..dbca4fc956 100644 --- a/src/link.zig +++ b/src/link.zig @@ -179,7 +179,7 @@ pub const File = struct { /// This is where the .debug_info tag for the type is. off: u32, /// Offset from `TextBlock.dbg_info_off` (the buffer that is local to a Decl). - /// List of DW.AT_type / DW.FORM_ref4 that points to the type. + /// List of DW.AT.type / DW.FORM.ref4 that points to the type. relocs: std.ArrayListUnmanaged(u32), }; diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 9ddebd3453..938fede8ab 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -772,48 +772,48 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { // These are LEB encoded but since the values are all less than 127 // we can simply append these bytes. const abbrev_buf = [_]u8{ - abbrev_compile_unit, DW.TAG_compile_unit, DW.CHILDREN_yes, // header - DW.AT_stmt_list, DW.FORM_sec_offset, DW.AT_low_pc, - DW.FORM_addr, DW.AT_high_pc, DW.FORM_addr, - DW.AT_name, DW.FORM_strp, DW.AT_comp_dir, - DW.FORM_strp, DW.AT_producer, DW.FORM_strp, - DW.AT_language, DW.FORM_data2, 0, + abbrev_compile_unit, DW.TAG.compile_unit, DW.CHILDREN.yes, // header + DW.AT.stmt_list, DW.FORM.sec_offset, DW.AT.low_pc, + DW.FORM.addr, DW.AT.high_pc, DW.FORM.addr, + DW.AT.name, DW.FORM.strp, DW.AT.comp_dir, + DW.FORM.strp, DW.AT.producer, DW.FORM.strp, + DW.AT.language, DW.FORM.data2, 0, 0, // table sentinel abbrev_subprogram, - DW.TAG_subprogram, - DW.CHILDREN_yes, // header - DW.AT_low_pc, - DW.FORM_addr, - DW.AT_high_pc, - DW.FORM_data4, - DW.AT_type, - DW.FORM_ref4, - DW.AT_name, - DW.FORM_string, + DW.TAG.subprogram, + DW.CHILDREN.yes, // header + DW.AT.low_pc, + DW.FORM.addr, + DW.AT.high_pc, + DW.FORM.data4, + DW.AT.type, + DW.FORM.ref4, + DW.AT.name, + DW.FORM.string, 0, 0, // table sentinel abbrev_subprogram_retvoid, - DW.TAG_subprogram, DW.CHILDREN_yes, // header - DW.AT_low_pc, DW.FORM_addr, - DW.AT_high_pc, DW.FORM_data4, - DW.AT_name, DW.FORM_string, + DW.TAG.subprogram, DW.CHILDREN.yes, // header + DW.AT.low_pc, DW.FORM.addr, + DW.AT.high_pc, DW.FORM.data4, + DW.AT.name, DW.FORM.string, 0, 0, // table sentinel abbrev_base_type, - DW.TAG_base_type, - DW.CHILDREN_no, // header - DW.AT_encoding, - DW.FORM_data1, - DW.AT_byte_size, - DW.FORM_data1, - DW.AT_name, - DW.FORM_string, 0, 0, // table sentinel - abbrev_pad1, DW.TAG_unspecified_type, DW.CHILDREN_no, // header + DW.TAG.base_type, + DW.CHILDREN.no, // header + DW.AT.encoding, + DW.FORM.data1, + DW.AT.byte_size, + DW.FORM.data1, + DW.AT.name, + DW.FORM.string, 0, 0, // table sentinel + abbrev_pad1, DW.TAG.unspecified_type, DW.CHILDREN.no, // header 0, 0, // table sentinel abbrev_parameter, - DW.TAG_formal_parameter, DW.CHILDREN_no, // header - DW.AT_location, DW.FORM_exprloc, - DW.AT_type, DW.FORM_ref4, - DW.AT_name, DW.FORM_string, + DW.TAG.formal_parameter, DW.CHILDREN.no, // header + DW.AT.location, DW.FORM.exprloc, + DW.AT.type, DW.FORM.ref4, + DW.AT.name, DW.FORM.string, 0, 0, // table sentinel 0, @@ -897,7 +897,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz; di_buf.appendAssumeCapacity(abbrev_compile_unit); - self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // DW.AT_stmt_list, DW.FORM_sec_offset + self.writeDwarfAddrAssumeCapacity(&di_buf, 0); // DW.AT.stmt_list, DW.FORM.sec_offset self.writeDwarfAddrAssumeCapacity(&di_buf, low_pc); self.writeDwarfAddrAssumeCapacity(&di_buf, high_pc); self.writeDwarfAddrAssumeCapacity(&di_buf, name_strp); @@ -906,7 +906,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number: // http://dwarfstd.org/ShowIssue.php?issue=171115.1 // Until then we say it is C99. - mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99, target_endian); + mem.writeInt(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG.C99, target_endian); if (di_buf.items.len > first_dbg_info_decl.dbg_info_off) { // Move the first N decls to the end to make more padding for the header. @@ -1030,7 +1030,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { di_buf.items.len += ptr_width_bytes; // We will come back and write this. const after_header_len = di_buf.items.len; - const opcode_base = DW.LNS_set_isa + 1; + const opcode_base = DW.LNS.set_isa + 1; di_buf.appendSliceAssumeCapacity(&[_]u8{ 1, // minimum_instruction_length 1, // maximum_operations_per_instruction @@ -1041,18 +1041,18 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void { // Standard opcode lengths. The number of items here is based on `opcode_base`. // The value is the number of LEB128 operands the instruction takes. - 0, // `DW.LNS_copy` - 1, // `DW.LNS_advance_pc` - 1, // `DW.LNS_advance_line` - 1, // `DW.LNS_set_file` - 1, // `DW.LNS_set_column` - 0, // `DW.LNS_negate_stmt` - 0, // `DW.LNS_set_basic_block` - 0, // `DW.LNS_const_add_pc` - 1, // `DW.LNS_fixed_advance_pc` - 0, // `DW.LNS_set_prologue_end` - 0, // `DW.LNS_set_epilogue_begin` - 1, // `DW.LNS_set_isa` + 0, // `DW.LNS.copy` + 1, // `DW.LNS.advance_pc` + 1, // `DW.LNS.advance_line` + 1, // `DW.LNS.set_file` + 1, // `DW.LNS.set_column` + 0, // `DW.LNS.negate_stmt` + 0, // `DW.LNS.set_basic_block` + 0, // `DW.LNS.const_add_pc` + 1, // `DW.LNS.fixed_advance_pc` + 0, // `DW.LNS.set_prologue_end` + 0, // `DW.LNS.set_epilogue_begin` + 1, // `DW.LNS.set_isa` 0, // include_directories (none except the compilation unit cwd) }); // file_names[0] @@ -2053,7 +2053,7 @@ fn allocateTextBlock(self: *Elf, text_block: *TextBlock, new_block_size: u64, al // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address // range of the compilation unit. When we expand the text section, this range changes, - // so the DW_TAG_compile_unit tag of the .debug_info section becomes dirty. + // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty. self.debug_info_header_dirty = true; // This becomes dirty for the same reason. We could potentially make this more // fine-grained with the addition of support for more compilation units. It is planned to @@ -2303,22 +2303,22 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven const ptr_width_bytes = self.ptrWidthBytes(); dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ - DW.LNS_extended_op, + DW.LNS.extended_op, ptr_width_bytes + 1, - DW.LNE_set_address, + DW.LNE.set_address, }); // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`. assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len); dbg_line_buffer.items.len += ptr_width_bytes; - dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line); + dbg_line_buffer.appendAssumeCapacity(DW.LNS.advance_line); // This is the "relocatable" relative line offset from the previous function's end curly // to this function's begin curly. assert(self.getRelocDbgLineOff() == dbg_line_buffer.items.len); // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later. leb128.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off); - dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file); + dbg_line_buffer.appendAssumeCapacity(DW.LNS.set_file); assert(self.getRelocDbgFileIndex() == dbg_line_buffer.items.len); // Once we support more than one source file, this will have the ability to be more // than one possible value. @@ -2327,7 +2327,7 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven // Emit a line for the begin curly with prologue_end=false. The codegen will // do the work of setting prologue_end=true and epilogue_begin=true. - dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy); + dbg_line_buffer.appendAssumeCapacity(DW.LNS.copy); // .debug_info subprogram const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1]; @@ -2344,9 +2344,9 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven // "relocations" and have to be in this fixed place so that functions can be // moved in virtual address space. assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len); - dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT_low_pc, DW.FORM_addr + dbg_info_buffer.items.len += ptr_width_bytes; // DW.AT.low_pc, DW.FORM.addr assert(self.getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len); - dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4 + dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4 if (fn_ret_has_bits) { const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, fn_ret_type); if (!gop.found_existing) { @@ -2356,9 +2356,9 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven }; } try gop.value_ptr.relocs.append(self.base.allocator, @intCast(u32, dbg_info_buffer.items.len)); - dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4 + dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4 } - dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string + dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT.name, DW.FORM.string const res = try codegen.generateFunction(&self.base, decl.srcLoc(), func, air, liveness, &code_buffer, .{ .dwarf = .{ @@ -2409,7 +2409,7 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven mem.writeInt(u32, ptr, @intCast(u32, local_sym.st_size), target_endian); } - try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence }); + try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS.extended_op, 1, DW.LNE.end_sequence }); // Now we have the full contents and may allocate a region to store it. @@ -2493,7 +2493,7 @@ pub fn updateFunc(self: *Elf, module: *Module, func: *Module.Fn, air: Air, liven const file_pos = debug_line_sect.sh_offset + src_fn.off; try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos); - // .debug_info - End the TAG_subprogram children. + // .debug_info - End the TAG.subprogram children. try dbg_info_buffer.append(0); return self.finishUpdateDecl(module, decl, &dbg_info_type_relocs, &dbg_info_buffer); @@ -2566,34 +2566,34 @@ fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !vo .Bool => { try dbg_info_buffer.appendSlice(&[_]u8{ abbrev_base_type, - DW.ATE_boolean, // DW.AT_encoding , DW.FORM_data1 - 1, // DW.AT_byte_size, DW.FORM_data1 - 'b', 'o', 'o', 'l', 0, // DW.AT_name, DW.FORM_string + DW.ATE.boolean, // DW.AT.encoding , DW.FORM.data1 + 1, // DW.AT.byte_size, DW.FORM.data1 + 'b', 'o', 'o', 'l', 0, // DW.AT.name, DW.FORM.string }); }, .Int => { const info = ty.intInfo(self.base.options.target); try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 12); dbg_info_buffer.appendAssumeCapacity(abbrev_base_type); - // DW.AT_encoding, DW.FORM_data1 + // DW.AT.encoding, DW.FORM.data1 dbg_info_buffer.appendAssumeCapacity(switch (info.signedness) { - .signed => DW.ATE_signed, - .unsigned => DW.ATE_unsigned, + .signed => DW.ATE.signed, + .unsigned => DW.ATE.unsigned, }); - // DW.AT_byte_size, DW.FORM_data1 + // DW.AT.byte_size, DW.FORM.data1 dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(self.base.options.target))); - // DW.AT_name, DW.FORM_string + // DW.AT.name, DW.FORM.string try dbg_info_buffer.writer().print("{}\x00", .{ty}); }, .Optional => { if (ty.isPtrLikeOptional()) { try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 12); dbg_info_buffer.appendAssumeCapacity(abbrev_base_type); - // DW.AT_encoding, DW.FORM_data1 - dbg_info_buffer.appendAssumeCapacity(DW.ATE_address); - // DW.AT_byte_size, DW.FORM_data1 + // DW.AT.encoding, DW.FORM.data1 + dbg_info_buffer.appendAssumeCapacity(DW.ATE.address); + // DW.AT.byte_size, DW.FORM.data1 dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(self.base.options.target))); - // DW.AT_name, DW.FORM_string + // DW.AT.name, DW.FORM.string try dbg_info_buffer.writer().print("{}\x00", .{ty}); } else { log.err("TODO implement .debug_info for type '{}'", .{ty}); @@ -3034,7 +3034,7 @@ fn archPtrWidthBytes(self: Elf) u8 { /// The reloc offset for the virtual address of a function in its Line Number Program. /// Size is a virtual address integer. const dbg_line_vaddr_reloc_index = 3; -/// The reloc offset for the virtual address of a function in its .debug_info TAG_subprogram. +/// The reloc offset for the virtual address of a function in its .debug_info TAG.subprogram. /// Size is a virtual address integer. const dbg_info_low_pc_reloc_index = 1; @@ -3060,7 +3060,7 @@ fn dbgLineNeededHeaderBytes(self: Elf) u32 { const root_src_dir_path_len = if (self.base.options.module.?.root_pkg.root_src_directory.path) |p| p.len else 1; // "." return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 + directory_count * 8 + file_name_count * 8 + - // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like + // These are encoded as DW.FORM.string rather than DW.FORM.strp as we would like // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly. root_src_dir_path_len + self.base.options.module.?.root_pkg.root_src_path.len); @@ -3088,8 +3088,8 @@ fn pwriteDbgLineNops( const tracy = trace(@src()); defer tracy.end(); - const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096; - const three_byte_nop = [3]u8{ DW.LNS_advance_pc, 0b1000_0000, 0 }; + const page_of_nops = [1]u8{DW.LNS.negate_stmt} ** 4096; + const three_byte_nop = [3]u8{ DW.LNS.advance_pc, 0b1000_0000, 0 }; var vecs: [512]std.os.iovec_const = undefined; var vec_index: usize = 0; { diff --git a/src/link/MachO/DebugSymbols.zig b/src/link/MachO/DebugSymbols.zig index 025959793e..5f7b119bdc 100644 --- a/src/link/MachO/DebugSymbols.zig +++ b/src/link/MachO/DebugSymbols.zig @@ -93,7 +93,7 @@ const abbrev_parameter = 6; /// The reloc offset for the virtual address of a function in its Line Number Program. /// Size is a virtual address integer. const dbg_line_vaddr_reloc_index = 3; -/// The reloc offset for the virtual address of a function in its .debug_info TAG_subprogram. +/// The reloc offset for the virtual address of a function in its .debug_info TAG.subprogram. /// Size is a virtual address integer. const dbg_info_low_pc_reloc_index = 1; @@ -299,40 +299,40 @@ pub fn flushModule(self: *DebugSymbols, allocator: *Allocator, options: link.Opt // These are LEB encoded but since the values are all less than 127 // we can simply append these bytes. const abbrev_buf = [_]u8{ - abbrev_compile_unit, DW.TAG_compile_unit, DW.CHILDREN_yes, // header - DW.AT_stmt_list, DW.FORM_sec_offset, // offset - DW.AT_low_pc, DW.FORM_addr, - DW.AT_high_pc, DW.FORM_addr, - DW.AT_name, DW.FORM_strp, - DW.AT_comp_dir, DW.FORM_strp, - DW.AT_producer, DW.FORM_strp, - DW.AT_language, DW.FORM_data2, + abbrev_compile_unit, DW.TAG.compile_unit, DW.CHILDREN.yes, // header + DW.AT.stmt_list, DW.FORM.sec_offset, // offset + DW.AT.low_pc, DW.FORM.addr, + DW.AT.high_pc, DW.FORM.addr, + DW.AT.name, DW.FORM.strp, + DW.AT.comp_dir, DW.FORM.strp, + DW.AT.producer, DW.FORM.strp, + DW.AT.language, DW.FORM.data2, 0, 0, // table sentinel - abbrev_subprogram, DW.TAG_subprogram, DW.CHILDREN_yes, // header - DW.AT_low_pc, DW.FORM_addr, // start VM address - DW.AT_high_pc, DW.FORM_data4, - DW.AT_type, DW.FORM_ref4, - DW.AT_name, DW.FORM_string, - DW.AT_decl_line, DW.FORM_data4, - DW.AT_decl_file, DW.FORM_data1, + abbrev_subprogram, DW.TAG.subprogram, DW.CHILDREN.yes, // header + DW.AT.low_pc, DW.FORM.addr, // start VM address + DW.AT.high_pc, DW.FORM.data4, + DW.AT.type, DW.FORM.ref4, + DW.AT.name, DW.FORM.string, + DW.AT.decl_line, DW.FORM.data4, + DW.AT.decl_file, DW.FORM.data1, 0, 0, // table sentinel abbrev_subprogram_retvoid, - DW.TAG_subprogram, DW.CHILDREN_yes, // header - DW.AT_low_pc, DW.FORM_addr, - DW.AT_high_pc, DW.FORM_data4, - DW.AT_name, DW.FORM_string, - DW.AT_decl_line, DW.FORM_data4, - DW.AT_decl_file, DW.FORM_data1, + DW.TAG.subprogram, DW.CHILDREN.yes, // header + DW.AT.low_pc, DW.FORM.addr, + DW.AT.high_pc, DW.FORM.data4, + DW.AT.name, DW.FORM.string, + DW.AT.decl_line, DW.FORM.data4, + DW.AT.decl_file, DW.FORM.data1, 0, 0, // table sentinel - abbrev_base_type, DW.TAG_base_type, DW.CHILDREN_no, // header - DW.AT_encoding, DW.FORM_data1, DW.AT_byte_size, - DW.FORM_data1, DW.AT_name, DW.FORM_string, + abbrev_base_type, DW.TAG.base_type, DW.CHILDREN.no, // header + DW.AT.encoding, DW.FORM.data1, DW.AT.byte_size, + DW.FORM.data1, DW.AT.name, DW.FORM.string, 0, 0, // table sentinel - abbrev_pad1, DW.TAG_unspecified_type, DW.CHILDREN_no, // header + abbrev_pad1, DW.TAG.unspecified_type, DW.CHILDREN.no, // header 0, 0, // table sentinel - abbrev_parameter, DW.TAG_formal_parameter, DW.CHILDREN_no, // header - DW.AT_location, DW.FORM_exprloc, DW.AT_type, - DW.FORM_ref4, DW.AT_name, DW.FORM_string, + abbrev_parameter, DW.TAG.formal_parameter, DW.CHILDREN.no, // header + DW.AT.location, DW.FORM.exprloc, DW.AT.type, + DW.FORM.ref4, DW.AT.name, DW.FORM.string, 0, 0, // table sentinel 0, 0, 0, // section sentinel }; @@ -397,7 +397,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: *Allocator, options: link.Opt const high_pc = text_section.addr + text_section.size; di_buf.appendAssumeCapacity(abbrev_compile_unit); - mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // DW.AT_stmt_list, DW.FORM_sec_offset + mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), 0); // DW.AT.stmt_list, DW.FORM.sec_offset mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), low_pc); mem.writeIntLittle(u64, di_buf.addManyAsArrayAssumeCapacity(8), high_pc); mem.writeIntLittle(u32, di_buf.addManyAsArrayAssumeCapacity(4), @intCast(u32, name_strp)); @@ -406,7 +406,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: *Allocator, options: link.Opt // We are still waiting on dwarf-std.org to assign DW_LANG_Zig a number: // http://dwarfstd.org/ShowIssue.php?issue=171115.1 // Until then we say it is C99. - mem.writeIntLittle(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG_C99); + mem.writeIntLittle(u16, di_buf.addManyAsArrayAssumeCapacity(2), DW.LANG.C99); if (di_buf.items.len > first_dbg_info_decl.dbg_info_off) { // Move the first N decls to the end to make more padding for the header. @@ -514,7 +514,7 @@ pub fn flushModule(self: *DebugSymbols, allocator: *Allocator, options: link.Opt di_buf.items.len += @sizeOf(u32); // We will come back and write this. const after_header_len = di_buf.items.len; - const opcode_base = DW.LNS_set_isa + 1; + const opcode_base = DW.LNS.set_isa + 1; di_buf.appendSliceAssumeCapacity(&[_]u8{ 1, // minimum_instruction_length 1, // maximum_operations_per_instruction @@ -525,18 +525,18 @@ pub fn flushModule(self: *DebugSymbols, allocator: *Allocator, options: link.Opt // Standard opcode lengths. The number of items here is based on `opcode_base`. // The value is the number of LEB128 operands the instruction takes. - 0, // `DW.LNS_copy` - 1, // `DW.LNS_advance_pc` - 1, // `DW.LNS_advance_line` - 1, // `DW.LNS_set_file` - 1, // `DW.LNS_set_column` - 0, // `DW.LNS_negate_stmt` - 0, // `DW.LNS_set_basic_block` - 0, // `DW.LNS_const_add_pc` - 1, // `DW.LNS_fixed_advance_pc` - 0, // `DW.LNS_set_prologue_end` - 0, // `DW.LNS_set_epilogue_begin` - 1, // `DW.LNS_set_isa` + 0, // `DW.LNS.copy` + 1, // `DW.LNS.advance_pc` + 1, // `DW.LNS.advance_line` + 1, // `DW.LNS.set_file` + 1, // `DW.LNS.set_column` + 0, // `DW.LNS.negate_stmt` + 0, // `DW.LNS.set_basic_block` + 0, // `DW.LNS.const_add_pc` + 1, // `DW.LNS.fixed_advance_pc` + 0, // `DW.LNS.set_prologue_end` + 0, // `DW.LNS.set_epilogue_begin` + 1, // `DW.LNS.set_isa` 0, // include_directories (none except the compilation unit cwd) }); // file_names[0] @@ -876,22 +876,22 @@ pub fn initDeclDebugBuffers( const line_off = @intCast(u28, decl.src_line + func.lbrace_line); dbg_line_buffer.appendSliceAssumeCapacity(&[_]u8{ - DW.LNS_extended_op, + DW.LNS.extended_op, @sizeOf(u64) + 1, - DW.LNE_set_address, + DW.LNE.set_address, }); // This is the "relocatable" vaddr, corresponding to `code_buffer` index `0`. assert(dbg_line_vaddr_reloc_index == dbg_line_buffer.items.len); dbg_line_buffer.items.len += @sizeOf(u64); - dbg_line_buffer.appendAssumeCapacity(DW.LNS_advance_line); + dbg_line_buffer.appendAssumeCapacity(DW.LNS.advance_line); // This is the "relocatable" relative line offset from the previous function's end curly // to this function's begin curly. assert(getRelocDbgLineOff() == dbg_line_buffer.items.len); // Here we use a ULEB128-fixed-4 to make sure this field can be overwritten later. leb.writeUnsignedFixed(4, dbg_line_buffer.addManyAsArrayAssumeCapacity(4), line_off); - dbg_line_buffer.appendAssumeCapacity(DW.LNS_set_file); + dbg_line_buffer.appendAssumeCapacity(DW.LNS.set_file); assert(getRelocDbgFileIndex() == dbg_line_buffer.items.len); // Once we support more than one source file, this will have the ability to be more // than one possible value. @@ -900,7 +900,7 @@ pub fn initDeclDebugBuffers( // Emit a line for the begin curly with prologue_end=false. The codegen will // do the work of setting prologue_end=true and epilogue_begin=true. - dbg_line_buffer.appendAssumeCapacity(DW.LNS_copy); + dbg_line_buffer.appendAssumeCapacity(DW.LNS.copy); // .debug_info subprogram const decl_name_with_null = decl.name[0 .. mem.lenZ(decl.name) + 1]; @@ -917,9 +917,9 @@ pub fn initDeclDebugBuffers( // "relocations" and have to be in this fixed place so that functions can be // moved in virtual address space. assert(dbg_info_low_pc_reloc_index == dbg_info_buffer.items.len); - dbg_info_buffer.items.len += @sizeOf(u64); // DW.AT_low_pc, DW.FORM_addr + dbg_info_buffer.items.len += @sizeOf(u64); // DW.AT.low_pc, DW.FORM.addr assert(getRelocDbgInfoSubprogramHighPC() == dbg_info_buffer.items.len); - dbg_info_buffer.items.len += 4; // DW.AT_high_pc, DW.FORM_data4 + dbg_info_buffer.items.len += 4; // DW.AT.high_pc, DW.FORM.data4 if (fn_ret_has_bits) { const gop = try dbg_info_type_relocs.getOrPut(allocator, fn_ret_type); if (!gop.found_existing) { @@ -929,11 +929,11 @@ pub fn initDeclDebugBuffers( }; } try gop.value_ptr.relocs.append(allocator, @intCast(u32, dbg_info_buffer.items.len)); - dbg_info_buffer.items.len += 4; // DW.AT_type, DW.FORM_ref4 + dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4 } - dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT_name, DW.FORM_string - mem.writeIntLittle(u32, dbg_info_buffer.addManyAsArrayAssumeCapacity(4), line_off + 1); // DW.AT_decl_line, DW.FORM_data4 - dbg_info_buffer.appendAssumeCapacity(file_index); // DW.AT_decl_file, DW.FORM_data1 + dbg_info_buffer.appendSliceAssumeCapacity(decl_name_with_null); // DW.AT.name, DW.FORM.string + mem.writeIntLittle(u32, dbg_info_buffer.addManyAsArrayAssumeCapacity(4), line_off + 1); // DW.AT.decl_line, DW.FORM.data4 + dbg_info_buffer.appendAssumeCapacity(file_index); // DW.AT.decl_file, DW.FORM.data1 }, else => { // TODO implement .debug_info for global variables @@ -985,16 +985,16 @@ pub fn commitDeclDebugInfo( { // Advance line and PC. // TODO encapsulate logic in a helper function. - try dbg_line_buffer.append(DW.LNS_advance_pc); + try dbg_line_buffer.append(DW.LNS.advance_pc); try leb.writeULEB128(dbg_line_buffer.writer(), text_block.size); - try dbg_line_buffer.append(DW.LNS_advance_line); + try dbg_line_buffer.append(DW.LNS.advance_line); const func = decl.val.castTag(.function).?.data; const line_off = @intCast(u28, func.rbrace_line - func.lbrace_line); try leb.writeULEB128(dbg_line_buffer.writer(), line_off); } - try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS_extended_op, 1, DW.LNE_end_sequence }); + try dbg_line_buffer.appendSlice(&[_]u8{ DW.LNS.extended_op, 1, DW.LNE.end_sequence }); // Now we have the full contents and may allocate a region to store it. @@ -1075,7 +1075,7 @@ pub fn commitDeclDebugInfo( const file_pos = debug_line_sect.offset + src_fn.off; try self.pwriteDbgLineNops(prev_padding_size, dbg_line_buffer.items, next_padding_size, file_pos); - // .debug_info - End the TAG_subprogram children. + // .debug_info - End the TAG.subprogram children. try dbg_info_buffer.append(0); }, else => {}, @@ -1128,27 +1128,27 @@ fn addDbgInfoType( .Bool => { try dbg_info_buffer.appendSlice(&[_]u8{ abbrev_base_type, - DW.ATE_boolean, // DW.AT_encoding , DW.FORM_data1 - 1, // DW.AT_byte_size, DW.FORM_data1 + DW.ATE.boolean, // DW.AT.encoding , DW.FORM.data1 + 1, // DW.AT.byte_size, DW.FORM.data1 'b', 'o', 'o', 'l', - 0, // DW.AT_name, DW.FORM_string + 0, // DW.AT.name, DW.FORM.string }); }, .Int => { const info = ty.intInfo(target); try dbg_info_buffer.ensureCapacity(dbg_info_buffer.items.len + 12); dbg_info_buffer.appendAssumeCapacity(abbrev_base_type); - // DW.AT_encoding, DW.FORM_data1 + // DW.AT.encoding, DW.FORM.data1 dbg_info_buffer.appendAssumeCapacity(switch (info.signedness) { - .signed => DW.ATE_signed, - .unsigned => DW.ATE_unsigned, + .signed => DW.ATE.signed, + .unsigned => DW.ATE.unsigned, }); - // DW.AT_byte_size, DW.FORM_data1 + // DW.AT.byte_size, DW.FORM.data1 dbg_info_buffer.appendAssumeCapacity(@intCast(u8, ty.abiSize(target))); - // DW.AT_name, DW.FORM_string + // DW.AT.name, DW.FORM.string try dbg_info_buffer.writer().print("{}\x00", .{ty}); }, else => { @@ -1306,7 +1306,7 @@ fn dbgLineNeededHeaderBytes(self: DebugSymbols, module: *Module) u32 { const root_src_dir_path_len = if (module.root_pkg.root_src_directory.path) |p| p.len else 1; // "." return @intCast(u32, 53 + directory_entry_format_count * 2 + file_name_entry_format_count * 2 + directory_count * 8 + file_name_count * 8 + - // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like + // These are encoded as DW.FORM.string rather than DW.FORM.strp as we would like // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly. root_src_dir_path_len + module.root_pkg.root_src_path.len); @@ -1332,8 +1332,8 @@ fn pwriteDbgLineNops( const tracy = trace(@src()); defer tracy.end(); - const page_of_nops = [1]u8{DW.LNS_negate_stmt} ** 4096; - const three_byte_nop = [3]u8{ DW.LNS_advance_pc, 0b1000_0000, 0 }; + const page_of_nops = [1]u8{DW.LNS.negate_stmt} ** 4096; + const three_byte_nop = [3]u8{ DW.LNS.advance_pc, 0b1000_0000, 0 }; var vecs: [32]std.os.iovec_const = undefined; var vec_index: usize = 0; { diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 06c76b259d..1051cda694 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -836,8 +836,8 @@ pub fn parseDebugInfo(self: *Object, allocator: *Allocator) !void { }, else => |e| return e, }; - const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_name); - const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT_comp_dir); + const name = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.name); + const comp_dir = try compile_unit.die.getAttrString(&debug_info.inner, dwarf.AT.comp_dir); self.debug_info = debug_info; self.tu_name = try allocator.dupe(u8, name); diff --git a/test/behavior.zig b/test/behavior.zig index 7028d6cbf6..80de1880d8 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -10,6 +10,7 @@ test { _ = @import("behavior/if.zig"); _ = @import("behavior/cast.zig"); _ = @import("behavior/array.zig"); + _ = @import("behavior/usingnamespace.zig"); if (!builtin.zig_is_stage2) { // Tests that only pass for stage1. @@ -148,7 +149,7 @@ test { _ = @import("behavior/undefined.zig"); _ = @import("behavior/underscore.zig"); _ = @import("behavior/union.zig"); - _ = @import("behavior/usingnamespace.zig"); + _ = @import("behavior/usingnamespace_stage1.zig"); _ = @import("behavior/var_args.zig"); _ = @import("behavior/vector.zig"); _ = @import("behavior/void.zig"); diff --git a/test/behavior/eval.zig b/test/behavior/eval.zig index 1b6540cd32..0d103bc49a 100644 --- a/test/behavior/eval.zig +++ b/test/behavior/eval.zig @@ -125,12 +125,6 @@ test "pointer to type" { } } -test "no undeclared identifier error in unanalyzed branches" { - if (false) { - lol_this_doesnt_exist = nonsense; - } -} - test "a type constructed in a global expression" { var l: List = undefined; l.array[0] = 10; diff --git a/test/behavior/usingnamespace.zig b/test/behavior/usingnamespace.zig index b529b24dd4..e819566002 100644 --- a/test/behavior/usingnamespace.zig +++ b/test/behavior/usingnamespace.zig @@ -1,22 +1,13 @@ const std = @import("std"); -fn Foo(comptime T: type) type { - return struct { - usingnamespace T; - }; -} - -test "usingnamespace inside a generic struct" { - const std2 = Foo(std); - const testing2 = Foo(std.testing); - try std2.testing.expect(true); - try testing2.expect(true); -} +const A = struct { + pub const B = bool; +}; -usingnamespace struct { - pub const foo = 42; +const C = struct { + usingnamespace A; }; -test "usingnamespace does not redeclare an imported variable" { - comptime try std.testing.expect(foo == 42); +test "basic usingnamespace" { + try std.testing.expect(C.B == bool); } diff --git a/test/behavior/usingnamespace_stage1.zig b/test/behavior/usingnamespace_stage1.zig new file mode 100644 index 0000000000..b529b24dd4 --- /dev/null +++ b/test/behavior/usingnamespace_stage1.zig @@ -0,0 +1,22 @@ +const std = @import("std"); + +fn Foo(comptime T: type) type { + return struct { + usingnamespace T; + }; +} + +test "usingnamespace inside a generic struct" { + const std2 = Foo(std); + const testing2 = Foo(std.testing); + try std2.testing.expect(true); + try testing2.expect(true); +} + +usingnamespace struct { + pub const foo = 42; +}; + +test "usingnamespace does not redeclare an imported variable" { + comptime try std.testing.expect(foo == 42); +} diff --git a/test/compile_errors.zig b/test/compile_errors.zig index 4c55e39ac7..82ee089970 100644 --- a/test/compile_errors.zig +++ b/test/compile_errors.zig @@ -8846,4 +8846,14 @@ pub fn addCases(ctx: *TestContext) !void { , &[_][]const u8{ "error: invalid operands to binary expression: 'f32' and 'f32'", }); + + ctx.objErrStage1("undeclared identifier in unanalyzed branch", + \\export fn a() void { + \\ if (false) { + \\ lol_this_doesnt_exist = nonsense; + \\ } + \\} + , &[_][]const u8{ + "tmp.zig:3:9: error: use of undeclared identifier 'lol_this_doesnt_exist'", + }); } -- cgit v1.2.3 From 3940a1be18a8312dec9d521c6e30ec4d34c44bd6 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 30 Aug 2021 19:22:04 -0700 Subject: rename std.zig.ast to std.zig.Ast; use top-level fields --- CMakeLists.txt | 2 +- lib/std/zig.zig | 2 +- lib/std/zig/Ast.zig | 2979 +++++++++++++++++++++++++++++++++++++++++++ lib/std/zig/ast.zig | 2978 ------------------------------------------ lib/std/zig/parse.zig | 33 +- lib/std/zig/parser_test.zig | 2 +- lib/std/zig/render.zig | 152 +-- src/AstGen.zig | 504 ++++---- src/Compilation.zig | 2 +- src/Module.zig | 48 +- src/Sema.zig | 6 +- src/Zir.zig | 18 +- src/main.zig | 18 +- src/translate_c.zig | 4 +- src/translate_c/ast.zig | 44 +- 15 files changed, 3396 insertions(+), 3396 deletions(-) create mode 100644 lib/std/zig/Ast.zig delete mode 100644 lib/std/zig/ast.zig (limited to 'src/Module.zig') diff --git a/CMakeLists.txt b/CMakeLists.txt index 695cf5b414..5b1d20f671 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -529,7 +529,7 @@ set(ZIG_STAGE2_SOURCES "${CMAKE_SOURCE_DIR}/lib/std/time.zig" "${CMAKE_SOURCE_DIR}/lib/std/unicode.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig.zig" - "${CMAKE_SOURCE_DIR}/lib/std/zig/ast.zig" + "${CMAKE_SOURCE_DIR}/lib/std/zig/Ast.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig/cross_target.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig/parse.zig" "${CMAKE_SOURCE_DIR}/lib/std/zig/render.zig" diff --git a/lib/std/zig.zig b/lib/std/zig.zig index 9573bfcd48..8d51cd56f9 100644 --- a/lib/std/zig.zig +++ b/lib/std/zig.zig @@ -10,7 +10,7 @@ pub const fmtEscapes = fmt.fmtEscapes; pub const isValidId = fmt.isValidId; pub const parse = @import("zig/parse.zig").parse; pub const string_literal = @import("zig/string_literal.zig"); -pub const ast = @import("zig/ast.zig"); +pub const Ast = @import("zig/Ast.zig"); pub const system = @import("zig/system.zig"); pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget; diff --git a/lib/std/zig/Ast.zig b/lib/std/zig/Ast.zig new file mode 100644 index 0000000000..35e75f4db2 --- /dev/null +++ b/lib/std/zig/Ast.zig @@ -0,0 +1,2979 @@ +//! Abstract Syntax Tree for Zig source code. + +/// Reference to externally-owned data. +source: [:0]const u8, + +tokens: TokenList.Slice, +/// The root AST node is assumed to be index 0. Since there can be no +/// references to the root node, this means 0 is available to indicate null. +nodes: NodeList.Slice, +extra_data: []Node.Index, + +errors: []const Error, + +const std = @import("../std.zig"); +const assert = std.debug.assert; +const testing = std.testing; +const mem = std.mem; +const Token = std.zig.Token; +const Tree = @This(); + +pub const TokenIndex = u32; +pub const ByteOffset = u32; + +pub const TokenList = std.MultiArrayList(struct { + tag: Token.Tag, + start: ByteOffset, +}); +pub const NodeList = std.MultiArrayList(Node); + +pub const Location = struct { + line: usize, + column: usize, + line_start: usize, + line_end: usize, +}; + +pub fn deinit(tree: *Tree, gpa: *mem.Allocator) void { + tree.tokens.deinit(gpa); + tree.nodes.deinit(gpa); + gpa.free(tree.extra_data); + gpa.free(tree.errors); + tree.* = undefined; +} + +pub const RenderError = error{ + /// Ran out of memory allocating call stack frames to complete rendering, or + /// ran out of memory allocating space in the output buffer. + OutOfMemory, +}; + +/// `gpa` is used for allocating the resulting formatted source code, as well as +/// for allocating extra stack memory if needed, because this function utilizes recursion. +/// Note: that's not actually true yet, see https://github.com/ziglang/zig/issues/1006. +/// Caller owns the returned slice of bytes, allocated with `gpa`. +pub fn render(tree: Tree, gpa: *mem.Allocator) RenderError![]u8 { + var buffer = std.ArrayList(u8).init(gpa); + defer buffer.deinit(); + + try tree.renderToArrayList(&buffer); + return buffer.toOwnedSlice(); +} + +pub fn renderToArrayList(tree: Tree, buffer: *std.ArrayList(u8)) RenderError!void { + return @import("./render.zig").renderTree(buffer, tree); +} + +pub fn tokenLocation(self: Tree, start_offset: ByteOffset, token_index: TokenIndex) Location { + var loc = Location{ + .line = 0, + .column = 0, + .line_start = start_offset, + .line_end = self.source.len, + }; + const token_start = self.tokens.items(.start)[token_index]; + for (self.source[start_offset..]) |c, i| { + if (i + start_offset == token_start) { + loc.line_end = i + start_offset; + while (loc.line_end < self.source.len and self.source[loc.line_end] != '\n') { + loc.line_end += 1; + } + return loc; + } + if (c == '\n') { + loc.line += 1; + loc.column = 0; + loc.line_start = i + 1; + } else { + loc.column += 1; + } + } + return loc; +} + +pub fn tokenSlice(tree: Tree, token_index: TokenIndex) []const u8 { + const token_starts = tree.tokens.items(.start); + const token_tags = tree.tokens.items(.tag); + const token_tag = token_tags[token_index]; + + // Many tokens can be determined entirely by their tag. + if (token_tag.lexeme()) |lexeme| { + return lexeme; + } + + // For some tokens, re-tokenization is needed to find the end. + var tokenizer: std.zig.Tokenizer = .{ + .buffer = tree.source, + .index = token_starts[token_index], + .pending_invalid_token = null, + }; + const token = tokenizer.next(); + assert(token.tag == token_tag); + return tree.source[token.loc.start..token.loc.end]; +} + +pub fn extraData(tree: Tree, index: usize, comptime T: type) T { + const fields = std.meta.fields(T); + var result: T = undefined; + inline for (fields) |field, i| { + comptime assert(field.field_type == Node.Index); + @field(result, field.name) = tree.extra_data[index + i]; + } + return result; +} + +pub fn rootDecls(tree: Tree) []const Node.Index { + // Root is always index 0. + const nodes_data = tree.nodes.items(.data); + return tree.extra_data[nodes_data[0].lhs..nodes_data[0].rhs]; +} + +pub fn renderError(tree: Tree, parse_error: Error, stream: anytype) !void { + const token_tags = tree.tokens.items(.tag); + switch (parse_error.tag) { + .asterisk_after_ptr_deref => { + // Note that the token will point at the `.*` but ideally the source + // location would point to the `*` after the `.*`. + return stream.writeAll("'.*' cannot be followed by '*'. Are you missing a space?"); + }, + .decl_between_fields => { + return stream.writeAll("declarations are not allowed between container fields"); + }, + .expected_block => { + return stream.print("expected block or field, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_block_or_assignment => { + return stream.print("expected block or assignment, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_block_or_expr => { + return stream.print("expected block or expression, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_block_or_field => { + return stream.print("expected block or field, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_container_members => { + return stream.print("expected test, comptime, var decl, or container field, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_expr => { + return stream.print("expected expression, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_expr_or_assignment => { + return stream.print("expected expression or assignment, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_fn => { + return stream.print("expected function, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_inlinable => { + return stream.print("expected 'while' or 'for', found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_labelable => { + return stream.print("expected 'while', 'for', 'inline', 'suspend', or '{{', found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_param_list => { + return stream.print("expected parameter list, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_prefix_expr => { + return stream.print("expected prefix expression, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_primary_type_expr => { + return stream.print("expected primary type expression, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_pub_item => { + return stream.writeAll("expected function or variable declaration after pub"); + }, + .expected_return_type => { + return stream.print("expected return type expression, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_semi_or_else => { + return stream.print("expected ';' or 'else', found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_semi_or_lbrace => { + return stream.print("expected ';' or '{{', found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_statement => { + return stream.print("expected statement, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_string_literal => { + return stream.print("expected string literal, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_suffix_op => { + return stream.print("expected pointer dereference, optional unwrap, or field access, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_type_expr => { + return stream.print("expected type expression, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_var_decl => { + return stream.print("expected variable declaration, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_var_decl_or_fn => { + return stream.print("expected variable declaration or function, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_loop_payload => { + return stream.print("expected loop payload, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .expected_container => { + return stream.print("expected a struct, enum or union, found '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .extra_align_qualifier => { + return stream.writeAll("extra align qualifier"); + }, + .extra_allowzero_qualifier => { + return stream.writeAll("extra allowzero qualifier"); + }, + .extra_const_qualifier => { + return stream.writeAll("extra const qualifier"); + }, + .extra_volatile_qualifier => { + return stream.writeAll("extra volatile qualifier"); + }, + .ptr_mod_on_array_child_type => { + return stream.print("pointer modifier '{s}' not allowed on array child type", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .invalid_bit_range => { + return stream.writeAll("bit range not allowed on slices and arrays"); + }, + .invalid_token => { + return stream.print("invalid token: '{s}'", .{ + token_tags[parse_error.token].symbol(), + }); + }, + .same_line_doc_comment => { + return stream.writeAll("same line documentation comment"); + }, + .unattached_doc_comment => { + return stream.writeAll("unattached documentation comment"); + }, + .varargs_nonfinal => { + return stream.writeAll("function prototype has parameter after varargs"); + }, + + .expected_token => { + const found_tag = token_tags[parse_error.token]; + const expected_symbol = parse_error.extra.expected_tag.symbol(); + switch (found_tag) { + .invalid => return stream.print("expected '{s}', found invalid bytes", .{ + expected_symbol, + }), + else => return stream.print("expected '{s}', found '{s}'", .{ + expected_symbol, found_tag.symbol(), + }), + } + }, + } +} + +pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex { + const tags = tree.nodes.items(.tag); + const datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); + const token_tags = tree.tokens.items(.tag); + var end_offset: TokenIndex = 0; + var n = node; + while (true) switch (tags[n]) { + .root => return 0, + + .test_decl, + .@"errdefer", + .@"defer", + .bool_not, + .negation, + .bit_not, + .negation_wrap, + .address_of, + .@"try", + .@"await", + .optional_type, + .@"switch", + .switch_comma, + .if_simple, + .@"if", + .@"suspend", + .@"resume", + .@"continue", + .@"break", + .@"return", + .anyframe_type, + .identifier, + .anyframe_literal, + .char_literal, + .integer_literal, + .float_literal, + .unreachable_literal, + .string_literal, + .multiline_string_literal, + .grouped_expression, + .builtin_call_two, + .builtin_call_two_comma, + .builtin_call, + .builtin_call_comma, + .error_set_decl, + .@"anytype", + .@"comptime", + .@"nosuspend", + .asm_simple, + .@"asm", + .array_type, + .array_type_sentinel, + .error_value, + => return main_tokens[n] - end_offset, + + .array_init_dot, + .array_init_dot_comma, + .array_init_dot_two, + .array_init_dot_two_comma, + .struct_init_dot, + .struct_init_dot_comma, + .struct_init_dot_two, + .struct_init_dot_two_comma, + .enum_literal, + => return main_tokens[n] - 1 - end_offset, + + .@"catch", + .field_access, + .unwrap_optional, + .equal_equal, + .bang_equal, + .less_than, + .greater_than, + .less_or_equal, + .greater_or_equal, + .assign_mul, + .assign_div, + .assign_mod, + .assign_add, + .assign_sub, + .assign_bit_shift_left, + .assign_bit_shift_right, + .assign_bit_and, + .assign_bit_xor, + .assign_bit_or, + .assign_mul_wrap, + .assign_add_wrap, + .assign_sub_wrap, + .assign, + .merge_error_sets, + .mul, + .div, + .mod, + .array_mult, + .mul_wrap, + .add, + .sub, + .array_cat, + .add_wrap, + .sub_wrap, + .bit_shift_left, + .bit_shift_right, + .bit_and, + .bit_xor, + .bit_or, + .@"orelse", + .bool_and, + .bool_or, + .slice_open, + .slice, + .slice_sentinel, + .deref, + .array_access, + .array_init_one, + .array_init_one_comma, + .array_init, + .array_init_comma, + .struct_init_one, + .struct_init_one_comma, + .struct_init, + .struct_init_comma, + .call_one, + .call_one_comma, + .call, + .call_comma, + .switch_range, + .error_union, + => n = datas[n].lhs, + + .fn_decl, + .fn_proto_simple, + .fn_proto_multi, + .fn_proto_one, + .fn_proto, + => { + var i = main_tokens[n]; // fn token + while (i > 0) { + i -= 1; + switch (token_tags[i]) { + .keyword_extern, + .keyword_export, + .keyword_pub, + .keyword_inline, + .keyword_noinline, + .string_literal, + => continue, + + else => return i + 1 - end_offset, + } + } + return i - end_offset; + }, + + .@"usingnamespace" => { + const main_token = main_tokens[n]; + if (main_token > 0 and token_tags[main_token - 1] == .keyword_pub) { + end_offset += 1; + } + return main_token - end_offset; + }, + + .async_call_one, + .async_call_one_comma, + .async_call, + .async_call_comma, + => { + end_offset += 1; // async token + n = datas[n].lhs; + }, + + .container_field_init, + .container_field_align, + .container_field, + => { + const name_token = main_tokens[n]; + if (name_token > 0 and token_tags[name_token - 1] == .keyword_comptime) { + end_offset += 1; + } + return name_token - end_offset; + }, + + .global_var_decl, + .local_var_decl, + .simple_var_decl, + .aligned_var_decl, + => { + var i = main_tokens[n]; // mut token + while (i > 0) { + i -= 1; + switch (token_tags[i]) { + .keyword_extern, + .keyword_export, + .keyword_comptime, + .keyword_pub, + .keyword_threadlocal, + .string_literal, + => continue, + + else => return i + 1 - end_offset, + } + } + return i - end_offset; + }, + + .block, + .block_semicolon, + .block_two, + .block_two_semicolon, + => { + // Look for a label. + const lbrace = main_tokens[n]; + if (token_tags[lbrace - 1] == .colon and + token_tags[lbrace - 2] == .identifier) + { + end_offset += 2; + } + return lbrace - end_offset; + }, + + .container_decl, + .container_decl_trailing, + .container_decl_two, + .container_decl_two_trailing, + .container_decl_arg, + .container_decl_arg_trailing, + .tagged_union, + .tagged_union_trailing, + .tagged_union_two, + .tagged_union_two_trailing, + .tagged_union_enum_tag, + .tagged_union_enum_tag_trailing, + => { + const main_token = main_tokens[n]; + switch (token_tags[main_token - 1]) { + .keyword_packed, .keyword_extern => end_offset += 1, + else => {}, + } + return main_token - end_offset; + }, + + .ptr_type_aligned, + .ptr_type_sentinel, + .ptr_type, + .ptr_type_bit_range, + => { + const main_token = main_tokens[n]; + return switch (token_tags[main_token]) { + .asterisk, + .asterisk_asterisk, + => switch (token_tags[main_token - 1]) { + .l_bracket => main_token - 1, + else => main_token, + }, + .l_bracket => main_token, + else => unreachable, + } - end_offset; + }, + + .switch_case_one => { + if (datas[n].lhs == 0) { + return main_tokens[n] - 1 - end_offset; // else token + } else { + n = datas[n].lhs; + } + }, + .switch_case => { + const extra = tree.extraData(datas[n].lhs, Node.SubRange); + assert(extra.end - extra.start > 0); + n = tree.extra_data[extra.start]; + }, + + .asm_output, .asm_input => { + assert(token_tags[main_tokens[n] - 1] == .l_bracket); + return main_tokens[n] - 1 - end_offset; + }, + + .while_simple, + .while_cont, + .@"while", + .for_simple, + .@"for", + => { + // Look for a label and inline. + const main_token = main_tokens[n]; + var result = main_token; + if (token_tags[result - 1] == .keyword_inline) { + result -= 1; + } + if (token_tags[result - 1] == .colon) { + result -= 2; + } + return result - end_offset; + }, + }; +} + +pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { + const tags = tree.nodes.items(.tag); + const datas = tree.nodes.items(.data); + const main_tokens = tree.nodes.items(.main_token); + const token_starts = tree.tokens.items(.start); + const token_tags = tree.tokens.items(.tag); + var n = node; + var end_offset: TokenIndex = 0; + while (true) switch (tags[n]) { + .root => return @intCast(TokenIndex, tree.tokens.len - 1), + + .@"usingnamespace", + .bool_not, + .negation, + .bit_not, + .negation_wrap, + .address_of, + .@"try", + .@"await", + .optional_type, + .@"resume", + .@"nosuspend", + .@"comptime", + => n = datas[n].lhs, + + .test_decl, + .@"errdefer", + .@"defer", + .@"catch", + .equal_equal, + .bang_equal, + .less_than, + .greater_than, + .less_or_equal, + .greater_or_equal, + .assign_mul, + .assign_div, + .assign_mod, + .assign_add, + .assign_sub, + .assign_bit_shift_left, + .assign_bit_shift_right, + .assign_bit_and, + .assign_bit_xor, + .assign_bit_or, + .assign_mul_wrap, + .assign_add_wrap, + .assign_sub_wrap, + .assign, + .merge_error_sets, + .mul, + .div, + .mod, + .array_mult, + .mul_wrap, + .add, + .sub, + .array_cat, + .add_wrap, + .sub_wrap, + .bit_shift_left, + .bit_shift_right, + .bit_and, + .bit_xor, + .bit_or, + .@"orelse", + .bool_and, + .bool_or, + .anyframe_type, + .error_union, + .if_simple, + .while_simple, + .for_simple, + .fn_proto_simple, + .fn_proto_multi, + .ptr_type_aligned, + .ptr_type_sentinel, + .ptr_type, + .ptr_type_bit_range, + .array_type, + .switch_case_one, + .switch_case, + .switch_range, + => n = datas[n].rhs, + + .field_access, + .unwrap_optional, + .grouped_expression, + .multiline_string_literal, + .error_set_decl, + .asm_simple, + .asm_output, + .asm_input, + .error_value, + => return datas[n].rhs + end_offset, + + .@"anytype", + .anyframe_literal, + .char_literal, + .integer_literal, + .float_literal, + .unreachable_literal, + .identifier, + .deref, + .enum_literal, + .string_literal, + => return main_tokens[n] + end_offset, + + .@"return" => if (datas[n].lhs != 0) { + n = datas[n].lhs; + } else { + return main_tokens[n] + end_offset; + }, + + .call, .async_call => { + end_offset += 1; // for the rparen + const params = tree.extraData(datas[n].rhs, Node.SubRange); + if (params.end - params.start == 0) { + return main_tokens[n] + end_offset; + } + n = tree.extra_data[params.end - 1]; // last parameter + }, + .tagged_union_enum_tag => { + const members = tree.extraData(datas[n].rhs, Node.SubRange); + if (members.end - members.start == 0) { + end_offset += 4; // for the rparen + rparen + lbrace + rbrace + n = datas[n].lhs; + } else { + end_offset += 1; // for the rbrace + n = tree.extra_data[members.end - 1]; // last parameter + } + }, + .call_comma, + .async_call_comma, + .tagged_union_enum_tag_trailing, + => { + end_offset += 2; // for the comma/semicolon + rparen/rbrace + const params = tree.extraData(datas[n].rhs, Node.SubRange); + assert(params.end > params.start); + n = tree.extra_data[params.end - 1]; // last parameter + }, + .@"switch" => { + const cases = tree.extraData(datas[n].rhs, Node.SubRange); + if (cases.end - cases.start == 0) { + end_offset += 3; // rparen, lbrace, rbrace + n = datas[n].lhs; // condition expression + } else { + end_offset += 1; // for the rbrace + n = tree.extra_data[cases.end - 1]; // last case + } + }, + .container_decl_arg => { + const members = tree.extraData(datas[n].rhs, Node.SubRange); + if (members.end - members.start == 0) { + end_offset += 3; // for the rparen + lbrace + rbrace + n = datas[n].lhs; + } else { + end_offset += 1; // for the rbrace + n = tree.extra_data[members.end - 1]; // last parameter + } + }, + .@"asm" => { + const extra = tree.extraData(datas[n].rhs, Node.Asm); + return extra.rparen + end_offset; + }, + .array_init, + .struct_init, + => { + const elements = tree.extraData(datas[n].rhs, Node.SubRange); + assert(elements.end - elements.start > 0); + end_offset += 1; // for the rbrace + n = tree.extra_data[elements.end - 1]; // last element + }, + .array_init_comma, + .struct_init_comma, + .container_decl_arg_trailing, + .switch_comma, + => { + const members = tree.extraData(datas[n].rhs, Node.SubRange); + assert(members.end - members.start > 0); + end_offset += 2; // for the comma + rbrace + n = tree.extra_data[members.end - 1]; // last parameter + }, + .array_init_dot, + .struct_init_dot, + .block, + .container_decl, + .tagged_union, + .builtin_call, + => { + assert(datas[n].rhs - datas[n].lhs > 0); + end_offset += 1; // for the rbrace + n = tree.extra_data[datas[n].rhs - 1]; // last statement + }, + .array_init_dot_comma, + .struct_init_dot_comma, + .block_semicolon, + .container_decl_trailing, + .tagged_union_trailing, + .builtin_call_comma, + => { + assert(datas[n].rhs - datas[n].lhs > 0); + end_offset += 2; // for the comma/semicolon + rbrace/rparen + n = tree.extra_data[datas[n].rhs - 1]; // last member + }, + .call_one, + .async_call_one, + .array_access, + => { + end_offset += 1; // for the rparen/rbracket + if (datas[n].rhs == 0) { + return main_tokens[n] + end_offset; + } + n = datas[n].rhs; + }, + .array_init_dot_two, + .block_two, + .builtin_call_two, + .struct_init_dot_two, + .container_decl_two, + .tagged_union_two, + => { + if (datas[n].rhs != 0) { + end_offset += 1; // for the rparen/rbrace + n = datas[n].rhs; + } else if (datas[n].lhs != 0) { + end_offset += 1; // for the rparen/rbrace + n = datas[n].lhs; + } else { + switch (tags[n]) { + .array_init_dot_two, + .block_two, + .struct_init_dot_two, + => end_offset += 1, // rbrace + .builtin_call_two => end_offset += 2, // lparen/lbrace + rparen/rbrace + .container_decl_two => { + var i: u32 = 2; // lbrace + rbrace + while (token_tags[main_tokens[n] + i] == .container_doc_comment) i += 1; + end_offset += i; + }, + .tagged_union_two => { + var i: u32 = 5; // (enum) {} + while (token_tags[main_tokens[n] + i] == .container_doc_comment) i += 1; + end_offset += i; + }, + else => unreachable, + } + return main_tokens[n] + end_offset; + } + }, + .array_init_dot_two_comma, + .builtin_call_two_comma, + .block_two_semicolon, + .struct_init_dot_two_comma, + .container_decl_two_trailing, + .tagged_union_two_trailing, + => { + end_offset += 2; // for the comma/semicolon + rbrace/rparen + if (datas[n].rhs != 0) { + n = datas[n].rhs; + } else if (datas[n].lhs != 0) { + n = datas[n].lhs; + } else { + unreachable; + } + }, + .simple_var_decl => { + if (datas[n].rhs != 0) { + n = datas[n].rhs; + } else if (datas[n].lhs != 0) { + n = datas[n].lhs; + } else { + end_offset += 1; // from mut token to name + return main_tokens[n] + end_offset; + } + }, + .aligned_var_decl => { + if (datas[n].rhs != 0) { + n = datas[n].rhs; + } else if (datas[n].lhs != 0) { + end_offset += 1; // for the rparen + n = datas[n].lhs; + } else { + end_offset += 1; // from mut token to name + return main_tokens[n] + end_offset; + } + }, + .global_var_decl => { + if (datas[n].rhs != 0) { + n = datas[n].rhs; + } else { + const extra = tree.extraData(datas[n].lhs, Node.GlobalVarDecl); + if (extra.section_node != 0) { + end_offset += 1; // for the rparen + n = extra.section_node; + } else if (extra.align_node != 0) { + end_offset += 1; // for the rparen + n = extra.align_node; + } else if (extra.type_node != 0) { + n = extra.type_node; + } else { + end_offset += 1; // from mut token to name + return main_tokens[n] + end_offset; + } + } + }, + .local_var_decl => { + if (datas[n].rhs != 0) { + n = datas[n].rhs; + } else { + const extra = tree.extraData(datas[n].lhs, Node.LocalVarDecl); + if (extra.align_node != 0) { + end_offset += 1; // for the rparen + n = extra.align_node; + } else if (extra.type_node != 0) { + n = extra.type_node; + } else { + end_offset += 1; // from mut token to name + return main_tokens[n] + end_offset; + } + } + }, + .container_field_init => { + if (datas[n].rhs != 0) { + n = datas[n].rhs; + } else if (datas[n].lhs != 0) { + n = datas[n].lhs; + } else { + return main_tokens[n] + end_offset; + } + }, + .container_field_align => { + if (datas[n].rhs != 0) { + end_offset += 1; // for the rparen + n = datas[n].rhs; + } else if (datas[n].lhs != 0) { + n = datas[n].lhs; + } else { + return main_tokens[n] + end_offset; + } + }, + .container_field => { + const extra = tree.extraData(datas[n].rhs, Node.ContainerField); + if (extra.value_expr != 0) { + n = extra.value_expr; + } else if (extra.align_expr != 0) { + end_offset += 1; // for the rparen + n = extra.align_expr; + } else if (datas[n].lhs != 0) { + n = datas[n].lhs; + } else { + return main_tokens[n] + end_offset; + } + }, + + .array_init_one, + .struct_init_one, + => { + end_offset += 1; // rbrace + if (datas[n].rhs == 0) { + return main_tokens[n] + end_offset; + } else { + n = datas[n].rhs; + } + }, + .slice_open, + .call_one_comma, + .async_call_one_comma, + .array_init_one_comma, + .struct_init_one_comma, + => { + end_offset += 2; // ellipsis2 + rbracket, or comma + rparen + n = datas[n].rhs; + assert(n != 0); + }, + .slice => { + const extra = tree.extraData(datas[n].rhs, Node.Slice); + assert(extra.end != 0); // should have used slice_open + end_offset += 1; // rbracket + n = extra.end; + }, + .slice_sentinel => { + const extra = tree.extraData(datas[n].rhs, Node.SliceSentinel); + assert(extra.sentinel != 0); // should have used slice + end_offset += 1; // rbracket + n = extra.sentinel; + }, + + .@"continue" => { + if (datas[n].lhs != 0) { + return datas[n].lhs + end_offset; + } else { + return main_tokens[n] + end_offset; + } + }, + .@"break" => { + if (datas[n].rhs != 0) { + n = datas[n].rhs; + } else if (datas[n].lhs != 0) { + return datas[n].lhs + end_offset; + } else { + return main_tokens[n] + end_offset; + } + }, + .fn_decl => { + if (datas[n].rhs != 0) { + n = datas[n].rhs; + } else { + n = datas[n].lhs; + } + }, + .fn_proto_one => { + const extra = tree.extraData(datas[n].lhs, Node.FnProtoOne); + // linksection, callconv, align can appear in any order, so we + // find the last one here. + var max_node: Node.Index = datas[n].rhs; + var max_start = token_starts[main_tokens[max_node]]; + var max_offset: TokenIndex = 0; + if (extra.align_expr != 0) { + const start = token_starts[main_tokens[extra.align_expr]]; + if (start > max_start) { + max_node = extra.align_expr; + max_start = start; + max_offset = 1; // for the rparen + } + } + if (extra.section_expr != 0) { + const start = token_starts[main_tokens[extra.section_expr]]; + if (start > max_start) { + max_node = extra.section_expr; + max_start = start; + max_offset = 1; // for the rparen + } + } + if (extra.callconv_expr != 0) { + const start = token_starts[main_tokens[extra.callconv_expr]]; + if (start > max_start) { + max_node = extra.callconv_expr; + max_start = start; + max_offset = 1; // for the rparen + } + } + n = max_node; + end_offset += max_offset; + }, + .fn_proto => { + const extra = tree.extraData(datas[n].lhs, Node.FnProto); + // linksection, callconv, align can appear in any order, so we + // find the last one here. + var max_node: Node.Index = datas[n].rhs; + var max_start = token_starts[main_tokens[max_node]]; + var max_offset: TokenIndex = 0; + if (extra.align_expr != 0) { + const start = token_starts[main_tokens[extra.align_expr]]; + if (start > max_start) { + max_node = extra.align_expr; + max_start = start; + max_offset = 1; // for the rparen + } + } + if (extra.section_expr != 0) { + const start = token_starts[main_tokens[extra.section_expr]]; + if (start > max_start) { + max_node = extra.section_expr; + max_start = start; + max_offset = 1; // for the rparen + } + } + if (extra.callconv_expr != 0) { + const start = token_starts[main_tokens[extra.callconv_expr]]; + if (start > max_start) { + max_node = extra.callconv_expr; + max_start = start; + max_offset = 1; // for the rparen + } + } + n = max_node; + end_offset += max_offset; + }, + .while_cont => { + const extra = tree.extraData(datas[n].rhs, Node.WhileCont); + assert(extra.then_expr != 0); + n = extra.then_expr; + }, + .@"while" => { + const extra = tree.extraData(datas[n].rhs, Node.While); + assert(extra.else_expr != 0); + n = extra.else_expr; + }, + .@"if", .@"for" => { + const extra = tree.extraData(datas[n].rhs, Node.If); + assert(extra.else_expr != 0); + n = extra.else_expr; + }, + .@"suspend" => { + if (datas[n].lhs != 0) { + n = datas[n].lhs; + } else { + return main_tokens[n] + end_offset; + } + }, + .array_type_sentinel => { + const extra = tree.extraData(datas[n].rhs, Node.ArrayTypeSentinel); + n = extra.elem_type; + }, + }; +} + +pub fn tokensOnSameLine(tree: Tree, token1: TokenIndex, token2: TokenIndex) bool { + const token_starts = tree.tokens.items(.start); + const source = tree.source[token_starts[token1]..token_starts[token2]]; + return mem.indexOfScalar(u8, source, '\n') == null; +} + +pub fn getNodeSource(tree: Tree, node: Node.Index) []const u8 { + const token_starts = tree.tokens.items(.start); + const first_token = tree.firstToken(node); + const last_token = tree.lastToken(node); + const start = token_starts[first_token]; + const end = token_starts[last_token] + tree.tokenSlice(last_token).len; + return tree.source[start..end]; +} + +pub fn globalVarDecl(tree: Tree, node: Node.Index) full.VarDecl { + assert(tree.nodes.items(.tag)[node] == .global_var_decl); + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.lhs, Node.GlobalVarDecl); + return tree.fullVarDecl(.{ + .type_node = extra.type_node, + .align_node = extra.align_node, + .section_node = extra.section_node, + .init_node = data.rhs, + .mut_token = tree.nodes.items(.main_token)[node], + }); +} + +pub fn localVarDecl(tree: Tree, node: Node.Index) full.VarDecl { + assert(tree.nodes.items(.tag)[node] == .local_var_decl); + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.lhs, Node.LocalVarDecl); + return tree.fullVarDecl(.{ + .type_node = extra.type_node, + .align_node = extra.align_node, + .section_node = 0, + .init_node = data.rhs, + .mut_token = tree.nodes.items(.main_token)[node], + }); +} + +pub fn simpleVarDecl(tree: Tree, node: Node.Index) full.VarDecl { + assert(tree.nodes.items(.tag)[node] == .simple_var_decl); + const data = tree.nodes.items(.data)[node]; + return tree.fullVarDecl(.{ + .type_node = data.lhs, + .align_node = 0, + .section_node = 0, + .init_node = data.rhs, + .mut_token = tree.nodes.items(.main_token)[node], + }); +} + +pub fn alignedVarDecl(tree: Tree, node: Node.Index) full.VarDecl { + assert(tree.nodes.items(.tag)[node] == .aligned_var_decl); + const data = tree.nodes.items(.data)[node]; + return tree.fullVarDecl(.{ + .type_node = 0, + .align_node = data.lhs, + .section_node = 0, + .init_node = data.rhs, + .mut_token = tree.nodes.items(.main_token)[node], + }); +} + +pub fn ifSimple(tree: Tree, node: Node.Index) full.If { + assert(tree.nodes.items(.tag)[node] == .if_simple); + const data = tree.nodes.items(.data)[node]; + return tree.fullIf(.{ + .cond_expr = data.lhs, + .then_expr = data.rhs, + .else_expr = 0, + .if_token = tree.nodes.items(.main_token)[node], + }); +} + +pub fn ifFull(tree: Tree, node: Node.Index) full.If { + assert(tree.nodes.items(.tag)[node] == .@"if"); + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.rhs, Node.If); + return tree.fullIf(.{ + .cond_expr = data.lhs, + .then_expr = extra.then_expr, + .else_expr = extra.else_expr, + .if_token = tree.nodes.items(.main_token)[node], + }); +} + +pub fn containerField(tree: Tree, node: Node.Index) full.ContainerField { + assert(tree.nodes.items(.tag)[node] == .container_field); + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.rhs, Node.ContainerField); + return tree.fullContainerField(.{ + .name_token = tree.nodes.items(.main_token)[node], + .type_expr = data.lhs, + .value_expr = extra.value_expr, + .align_expr = extra.align_expr, + }); +} + +pub fn containerFieldInit(tree: Tree, node: Node.Index) full.ContainerField { + assert(tree.nodes.items(.tag)[node] == .container_field_init); + const data = tree.nodes.items(.data)[node]; + return tree.fullContainerField(.{ + .name_token = tree.nodes.items(.main_token)[node], + .type_expr = data.lhs, + .value_expr = data.rhs, + .align_expr = 0, + }); +} + +pub fn containerFieldAlign(tree: Tree, node: Node.Index) full.ContainerField { + assert(tree.nodes.items(.tag)[node] == .container_field_align); + const data = tree.nodes.items(.data)[node]; + return tree.fullContainerField(.{ + .name_token = tree.nodes.items(.main_token)[node], + .type_expr = data.lhs, + .value_expr = 0, + .align_expr = data.rhs, + }); +} + +pub fn fnProtoSimple(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnProto { + assert(tree.nodes.items(.tag)[node] == .fn_proto_simple); + const data = tree.nodes.items(.data)[node]; + buffer[0] = data.lhs; + const params = if (data.lhs == 0) buffer[0..0] else buffer[0..1]; + return tree.fullFnProto(.{ + .proto_node = node, + .fn_token = tree.nodes.items(.main_token)[node], + .return_type = data.rhs, + .params = params, + .align_expr = 0, + .section_expr = 0, + .callconv_expr = 0, + }); +} + +pub fn fnProtoMulti(tree: Tree, node: Node.Index) full.FnProto { + assert(tree.nodes.items(.tag)[node] == .fn_proto_multi); + const data = tree.nodes.items(.data)[node]; + const params_range = tree.extraData(data.lhs, Node.SubRange); + const params = tree.extra_data[params_range.start..params_range.end]; + return tree.fullFnProto(.{ + .proto_node = node, + .fn_token = tree.nodes.items(.main_token)[node], + .return_type = data.rhs, + .params = params, + .align_expr = 0, + .section_expr = 0, + .callconv_expr = 0, + }); +} + +pub fn fnProtoOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnProto { + assert(tree.nodes.items(.tag)[node] == .fn_proto_one); + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.lhs, Node.FnProtoOne); + buffer[0] = extra.param; + const params = if (extra.param == 0) buffer[0..0] else buffer[0..1]; + return tree.fullFnProto(.{ + .proto_node = node, + .fn_token = tree.nodes.items(.main_token)[node], + .return_type = data.rhs, + .params = params, + .align_expr = extra.align_expr, + .section_expr = extra.section_expr, + .callconv_expr = extra.callconv_expr, + }); +} + +pub fn fnProto(tree: Tree, node: Node.Index) full.FnProto { + assert(tree.nodes.items(.tag)[node] == .fn_proto); + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.lhs, Node.FnProto); + const params = tree.extra_data[extra.params_start..extra.params_end]; + return tree.fullFnProto(.{ + .proto_node = node, + .fn_token = tree.nodes.items(.main_token)[node], + .return_type = data.rhs, + .params = params, + .align_expr = extra.align_expr, + .section_expr = extra.section_expr, + .callconv_expr = extra.callconv_expr, + }); +} + +pub fn structInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.StructInit { + assert(tree.nodes.items(.tag)[node] == .struct_init_one or + tree.nodes.items(.tag)[node] == .struct_init_one_comma); + const data = tree.nodes.items(.data)[node]; + buffer[0] = data.rhs; + const fields = if (data.rhs == 0) buffer[0..0] else buffer[0..1]; + return tree.fullStructInit(.{ + .lbrace = tree.nodes.items(.main_token)[node], + .fields = fields, + .type_expr = data.lhs, + }); +} + +pub fn structInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.StructInit { + assert(tree.nodes.items(.tag)[node] == .struct_init_dot_two or + tree.nodes.items(.tag)[node] == .struct_init_dot_two_comma); + const data = tree.nodes.items(.data)[node]; + buffer.* = .{ data.lhs, data.rhs }; + const fields = if (data.rhs != 0) + buffer[0..2] + else if (data.lhs != 0) + buffer[0..1] + else + buffer[0..0]; + return tree.fullStructInit(.{ + .lbrace = tree.nodes.items(.main_token)[node], + .fields = fields, + .type_expr = 0, + }); +} + +pub fn structInitDot(tree: Tree, node: Node.Index) full.StructInit { + assert(tree.nodes.items(.tag)[node] == .struct_init_dot or + tree.nodes.items(.tag)[node] == .struct_init_dot_comma); + const data = tree.nodes.items(.data)[node]; + return tree.fullStructInit(.{ + .lbrace = tree.nodes.items(.main_token)[node], + .fields = tree.extra_data[data.lhs..data.rhs], + .type_expr = 0, + }); +} + +pub fn structInit(tree: Tree, node: Node.Index) full.StructInit { + assert(tree.nodes.items(.tag)[node] == .struct_init or + tree.nodes.items(.tag)[node] == .struct_init_comma); + const data = tree.nodes.items(.data)[node]; + const fields_range = tree.extraData(data.rhs, Node.SubRange); + return tree.fullStructInit(.{ + .lbrace = tree.nodes.items(.main_token)[node], + .fields = tree.extra_data[fields_range.start..fields_range.end], + .type_expr = data.lhs, + }); +} + +pub fn arrayInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.ArrayInit { + assert(tree.nodes.items(.tag)[node] == .array_init_one or + tree.nodes.items(.tag)[node] == .array_init_one_comma); + const data = tree.nodes.items(.data)[node]; + buffer[0] = data.rhs; + const elements = if (data.rhs == 0) buffer[0..0] else buffer[0..1]; + return .{ + .ast = .{ + .lbrace = tree.nodes.items(.main_token)[node], + .elements = elements, + .type_expr = data.lhs, + }, + }; +} + +pub fn arrayInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.ArrayInit { + assert(tree.nodes.items(.tag)[node] == .array_init_dot_two or + tree.nodes.items(.tag)[node] == .array_init_dot_two_comma); + const data = tree.nodes.items(.data)[node]; + buffer.* = .{ data.lhs, data.rhs }; + const elements = if (data.rhs != 0) + buffer[0..2] + else if (data.lhs != 0) + buffer[0..1] + else + buffer[0..0]; + return .{ + .ast = .{ + .lbrace = tree.nodes.items(.main_token)[node], + .elements = elements, + .type_expr = 0, + }, + }; +} + +pub fn arrayInitDot(tree: Tree, node: Node.Index) full.ArrayInit { + assert(tree.nodes.items(.tag)[node] == .array_init_dot or + tree.nodes.items(.tag)[node] == .array_init_dot_comma); + const data = tree.nodes.items(.data)[node]; + return .{ + .ast = .{ + .lbrace = tree.nodes.items(.main_token)[node], + .elements = tree.extra_data[data.lhs..data.rhs], + .type_expr = 0, + }, + }; +} + +pub fn arrayInit(tree: Tree, node: Node.Index) full.ArrayInit { + assert(tree.nodes.items(.tag)[node] == .array_init or + tree.nodes.items(.tag)[node] == .array_init_comma); + const data = tree.nodes.items(.data)[node]; + const elem_range = tree.extraData(data.rhs, Node.SubRange); + return .{ + .ast = .{ + .lbrace = tree.nodes.items(.main_token)[node], + .elements = tree.extra_data[elem_range.start..elem_range.end], + .type_expr = data.lhs, + }, + }; +} + +pub fn arrayType(tree: Tree, node: Node.Index) full.ArrayType { + assert(tree.nodes.items(.tag)[node] == .array_type); + const data = tree.nodes.items(.data)[node]; + return .{ + .ast = .{ + .lbracket = tree.nodes.items(.main_token)[node], + .elem_count = data.lhs, + .sentinel = 0, + .elem_type = data.rhs, + }, + }; +} + +pub fn arrayTypeSentinel(tree: Tree, node: Node.Index) full.ArrayType { + assert(tree.nodes.items(.tag)[node] == .array_type_sentinel); + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.rhs, Node.ArrayTypeSentinel); + assert(extra.sentinel != 0); + return .{ + .ast = .{ + .lbracket = tree.nodes.items(.main_token)[node], + .elem_count = data.lhs, + .sentinel = extra.sentinel, + .elem_type = extra.elem_type, + }, + }; +} + +pub fn ptrTypeAligned(tree: Tree, node: Node.Index) full.PtrType { + assert(tree.nodes.items(.tag)[node] == .ptr_type_aligned); + const data = tree.nodes.items(.data)[node]; + return tree.fullPtrType(.{ + .main_token = tree.nodes.items(.main_token)[node], + .align_node = data.lhs, + .sentinel = 0, + .bit_range_start = 0, + .bit_range_end = 0, + .child_type = data.rhs, + }); +} + +pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) full.PtrType { + assert(tree.nodes.items(.tag)[node] == .ptr_type_sentinel); + const data = tree.nodes.items(.data)[node]; + return tree.fullPtrType(.{ + .main_token = tree.nodes.items(.main_token)[node], + .align_node = 0, + .sentinel = data.lhs, + .bit_range_start = 0, + .bit_range_end = 0, + .child_type = data.rhs, + }); +} + +pub fn ptrType(tree: Tree, node: Node.Index) full.PtrType { + assert(tree.nodes.items(.tag)[node] == .ptr_type); + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.lhs, Node.PtrType); + return tree.fullPtrType(.{ + .main_token = tree.nodes.items(.main_token)[node], + .align_node = extra.align_node, + .sentinel = extra.sentinel, + .bit_range_start = 0, + .bit_range_end = 0, + .child_type = data.rhs, + }); +} + +pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) full.PtrType { + assert(tree.nodes.items(.tag)[node] == .ptr_type_bit_range); + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.lhs, Node.PtrTypeBitRange); + return tree.fullPtrType(.{ + .main_token = tree.nodes.items(.main_token)[node], + .align_node = extra.align_node, + .sentinel = extra.sentinel, + .bit_range_start = extra.bit_range_start, + .bit_range_end = extra.bit_range_end, + .child_type = data.rhs, + }); +} + +pub fn sliceOpen(tree: Tree, node: Node.Index) full.Slice { + assert(tree.nodes.items(.tag)[node] == .slice_open); + const data = tree.nodes.items(.data)[node]; + return .{ + .ast = .{ + .sliced = data.lhs, + .lbracket = tree.nodes.items(.main_token)[node], + .start = data.rhs, + .end = 0, + .sentinel = 0, + }, + }; +} + +pub fn slice(tree: Tree, node: Node.Index) full.Slice { + assert(tree.nodes.items(.tag)[node] == .slice); + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.rhs, Node.Slice); + return .{ + .ast = .{ + .sliced = data.lhs, + .lbracket = tree.nodes.items(.main_token)[node], + .start = extra.start, + .end = extra.end, + .sentinel = 0, + }, + }; +} + +pub fn sliceSentinel(tree: Tree, node: Node.Index) full.Slice { + assert(tree.nodes.items(.tag)[node] == .slice_sentinel); + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.rhs, Node.SliceSentinel); + return .{ + .ast = .{ + .sliced = data.lhs, + .lbracket = tree.nodes.items(.main_token)[node], + .start = extra.start, + .end = extra.end, + .sentinel = extra.sentinel, + }, + }; +} + +pub fn containerDeclTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.ContainerDecl { + assert(tree.nodes.items(.tag)[node] == .container_decl_two or + tree.nodes.items(.tag)[node] == .container_decl_two_trailing); + const data = tree.nodes.items(.data)[node]; + buffer.* = .{ data.lhs, data.rhs }; + const members = if (data.rhs != 0) + buffer[0..2] + else if (data.lhs != 0) + buffer[0..1] + else + buffer[0..0]; + return tree.fullContainerDecl(.{ + .main_token = tree.nodes.items(.main_token)[node], + .enum_token = null, + .members = members, + .arg = 0, + }); +} + +pub fn containerDecl(tree: Tree, node: Node.Index) full.ContainerDecl { + assert(tree.nodes.items(.tag)[node] == .container_decl or + tree.nodes.items(.tag)[node] == .container_decl_trailing); + const data = tree.nodes.items(.data)[node]; + return tree.fullContainerDecl(.{ + .main_token = tree.nodes.items(.main_token)[node], + .enum_token = null, + .members = tree.extra_data[data.lhs..data.rhs], + .arg = 0, + }); +} + +pub fn containerDeclArg(tree: Tree, node: Node.Index) full.ContainerDecl { + assert(tree.nodes.items(.tag)[node] == .container_decl_arg or + tree.nodes.items(.tag)[node] == .container_decl_arg_trailing); + const data = tree.nodes.items(.data)[node]; + const members_range = tree.extraData(data.rhs, Node.SubRange); + return tree.fullContainerDecl(.{ + .main_token = tree.nodes.items(.main_token)[node], + .enum_token = null, + .members = tree.extra_data[members_range.start..members_range.end], + .arg = data.lhs, + }); +} + +pub fn taggedUnionTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.ContainerDecl { + assert(tree.nodes.items(.tag)[node] == .tagged_union_two or + tree.nodes.items(.tag)[node] == .tagged_union_two_trailing); + const data = tree.nodes.items(.data)[node]; + buffer.* = .{ data.lhs, data.rhs }; + const members = if (data.rhs != 0) + buffer[0..2] + else if (data.lhs != 0) + buffer[0..1] + else + buffer[0..0]; + const main_token = tree.nodes.items(.main_token)[node]; + return tree.fullContainerDecl(.{ + .main_token = main_token, + .enum_token = main_token + 2, // union lparen enum + .members = members, + .arg = 0, + }); +} + +pub fn taggedUnion(tree: Tree, node: Node.Index) full.ContainerDecl { + assert(tree.nodes.items(.tag)[node] == .tagged_union or + tree.nodes.items(.tag)[node] == .tagged_union_trailing); + const data = tree.nodes.items(.data)[node]; + const main_token = tree.nodes.items(.main_token)[node]; + return tree.fullContainerDecl(.{ + .main_token = main_token, + .enum_token = main_token + 2, // union lparen enum + .members = tree.extra_data[data.lhs..data.rhs], + .arg = 0, + }); +} + +pub fn taggedUnionEnumTag(tree: Tree, node: Node.Index) full.ContainerDecl { + assert(tree.nodes.items(.tag)[node] == .tagged_union_enum_tag or + tree.nodes.items(.tag)[node] == .tagged_union_enum_tag_trailing); + const data = tree.nodes.items(.data)[node]; + const members_range = tree.extraData(data.rhs, Node.SubRange); + const main_token = tree.nodes.items(.main_token)[node]; + return tree.fullContainerDecl(.{ + .main_token = main_token, + .enum_token = main_token + 2, // union lparen enum + .members = tree.extra_data[members_range.start..members_range.end], + .arg = data.lhs, + }); +} + +pub fn switchCaseOne(tree: Tree, node: Node.Index) full.SwitchCase { + const data = &tree.nodes.items(.data)[node]; + const values: *[1]Node.Index = &data.lhs; + return tree.fullSwitchCase(.{ + .values = if (data.lhs == 0) values[0..0] else values[0..1], + .arrow_token = tree.nodes.items(.main_token)[node], + .target_expr = data.rhs, + }); +} + +pub fn switchCase(tree: Tree, node: Node.Index) full.SwitchCase { + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.lhs, Node.SubRange); + return tree.fullSwitchCase(.{ + .values = tree.extra_data[extra.start..extra.end], + .arrow_token = tree.nodes.items(.main_token)[node], + .target_expr = data.rhs, + }); +} + +pub fn asmSimple(tree: Tree, node: Node.Index) full.Asm { + const data = tree.nodes.items(.data)[node]; + return tree.fullAsm(.{ + .asm_token = tree.nodes.items(.main_token)[node], + .template = data.lhs, + .items = &.{}, + .rparen = data.rhs, + }); +} + +pub fn asmFull(tree: Tree, node: Node.Index) full.Asm { + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.rhs, Node.Asm); + return tree.fullAsm(.{ + .asm_token = tree.nodes.items(.main_token)[node], + .template = data.lhs, + .items = tree.extra_data[extra.items_start..extra.items_end], + .rparen = extra.rparen, + }); +} + +pub fn whileSimple(tree: Tree, node: Node.Index) full.While { + const data = tree.nodes.items(.data)[node]; + return tree.fullWhile(.{ + .while_token = tree.nodes.items(.main_token)[node], + .cond_expr = data.lhs, + .cont_expr = 0, + .then_expr = data.rhs, + .else_expr = 0, + }); +} + +pub fn whileCont(tree: Tree, node: Node.Index) full.While { + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.rhs, Node.WhileCont); + return tree.fullWhile(.{ + .while_token = tree.nodes.items(.main_token)[node], + .cond_expr = data.lhs, + .cont_expr = extra.cont_expr, + .then_expr = extra.then_expr, + .else_expr = 0, + }); +} + +pub fn whileFull(tree: Tree, node: Node.Index) full.While { + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.rhs, Node.While); + return tree.fullWhile(.{ + .while_token = tree.nodes.items(.main_token)[node], + .cond_expr = data.lhs, + .cont_expr = extra.cont_expr, + .then_expr = extra.then_expr, + .else_expr = extra.else_expr, + }); +} + +pub fn forSimple(tree: Tree, node: Node.Index) full.While { + const data = tree.nodes.items(.data)[node]; + return tree.fullWhile(.{ + .while_token = tree.nodes.items(.main_token)[node], + .cond_expr = data.lhs, + .cont_expr = 0, + .then_expr = data.rhs, + .else_expr = 0, + }); +} + +pub fn forFull(tree: Tree, node: Node.Index) full.While { + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.rhs, Node.If); + return tree.fullWhile(.{ + .while_token = tree.nodes.items(.main_token)[node], + .cond_expr = data.lhs, + .cont_expr = 0, + .then_expr = extra.then_expr, + .else_expr = extra.else_expr, + }); +} + +pub fn callOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.Call { + const data = tree.nodes.items(.data)[node]; + buffer.* = .{data.rhs}; + const params = if (data.rhs != 0) buffer[0..1] else buffer[0..0]; + return tree.fullCall(.{ + .lparen = tree.nodes.items(.main_token)[node], + .fn_expr = data.lhs, + .params = params, + }); +} + +pub fn callFull(tree: Tree, node: Node.Index) full.Call { + const data = tree.nodes.items(.data)[node]; + const extra = tree.extraData(data.rhs, Node.SubRange); + return tree.fullCall(.{ + .lparen = tree.nodes.items(.main_token)[node], + .fn_expr = data.lhs, + .params = tree.extra_data[extra.start..extra.end], + }); +} + +fn fullVarDecl(tree: Tree, info: full.VarDecl.Components) full.VarDecl { + const token_tags = tree.tokens.items(.tag); + var result: full.VarDecl = .{ + .ast = info, + .visib_token = null, + .extern_export_token = null, + .lib_name = null, + .threadlocal_token = null, + .comptime_token = null, + }; + var i = info.mut_token; + while (i > 0) { + i -= 1; + switch (token_tags[i]) { + .keyword_extern, .keyword_export => result.extern_export_token = i, + .keyword_comptime => result.comptime_token = i, + .keyword_pub => result.visib_token = i, + .keyword_threadlocal => result.threadlocal_token = i, + .string_literal => result.lib_name = i, + else => break, + } + } + return result; +} + +fn fullIf(tree: Tree, info: full.If.Components) full.If { + const token_tags = tree.tokens.items(.tag); + var result: full.If = .{ + .ast = info, + .payload_token = null, + .error_token = null, + .else_token = undefined, + }; + // if (cond_expr) |x| + // ^ ^ + const payload_pipe = tree.lastToken(info.cond_expr) + 2; + if (token_tags[payload_pipe] == .pipe) { + result.payload_token = payload_pipe + 1; + } + if (info.else_expr != 0) { + // then_expr else |x| + // ^ ^ + result.else_token = tree.lastToken(info.then_expr) + 1; + if (token_tags[result.else_token + 1] == .pipe) { + result.error_token = result.else_token + 2; + } + } + return result; +} + +fn fullContainerField(tree: Tree, info: full.ContainerField.Components) full.ContainerField { + const token_tags = tree.tokens.items(.tag); + var result: full.ContainerField = .{ + .ast = info, + .comptime_token = null, + }; + // comptime name: type = init, + // ^ + if (info.name_token > 0 and token_tags[info.name_token - 1] == .keyword_comptime) { + result.comptime_token = info.name_token - 1; + } + return result; +} + +fn fullFnProto(tree: Tree, info: full.FnProto.Components) full.FnProto { + const token_tags = tree.tokens.items(.tag); + var result: full.FnProto = .{ + .ast = info, + .visib_token = null, + .extern_export_inline_token = null, + .lib_name = null, + .name_token = null, + .lparen = undefined, + }; + var i = info.fn_token; + while (i > 0) { + i -= 1; + switch (token_tags[i]) { + .keyword_extern, + .keyword_export, + .keyword_inline, + .keyword_noinline, + => result.extern_export_inline_token = i, + .keyword_pub => result.visib_token = i, + .string_literal => result.lib_name = i, + else => break, + } + } + const after_fn_token = info.fn_token + 1; + if (token_tags[after_fn_token] == .identifier) { + result.name_token = after_fn_token; + result.lparen = after_fn_token + 1; + } else { + result.lparen = after_fn_token; + } + assert(token_tags[result.lparen] == .l_paren); + + return result; +} + +fn fullStructInit(tree: Tree, info: full.StructInit.Components) full.StructInit { + _ = tree; + var result: full.StructInit = .{ + .ast = info, + }; + return result; +} + +fn fullPtrType(tree: Tree, info: full.PtrType.Components) full.PtrType { + const token_tags = tree.tokens.items(.tag); + // TODO: looks like stage1 isn't quite smart enough to handle enum + // literals in some places here + const Size = std.builtin.TypeInfo.Pointer.Size; + const size: Size = switch (token_tags[info.main_token]) { + .asterisk, + .asterisk_asterisk, + => switch (token_tags[info.main_token + 1]) { + .r_bracket, .colon => .Many, + .identifier => if (token_tags[info.main_token - 1] == .l_bracket) Size.C else .One, + else => .One, + }, + .l_bracket => Size.Slice, + else => unreachable, + }; + var result: full.PtrType = .{ + .size = size, + .allowzero_token = null, + .const_token = null, + .volatile_token = null, + .ast = info, + }; + // We need to be careful that we don't iterate over any sub-expressions + // here while looking for modifiers as that could result in false + // positives. Therefore, start after a sentinel if there is one and + // skip over any align node and bit range nodes. + var i = if (info.sentinel != 0) tree.lastToken(info.sentinel) + 1 else info.main_token; + const end = tree.firstToken(info.child_type); + while (i < end) : (i += 1) { + switch (token_tags[i]) { + .keyword_allowzero => result.allowzero_token = i, + .keyword_const => result.const_token = i, + .keyword_volatile => result.volatile_token = i, + .keyword_align => { + assert(info.align_node != 0); + if (info.bit_range_end != 0) { + assert(info.bit_range_start != 0); + i = tree.lastToken(info.bit_range_end) + 1; + } else { + i = tree.lastToken(info.align_node) + 1; + } + }, + else => {}, + } + } + return result; +} + +fn fullContainerDecl(tree: Tree, info: full.ContainerDecl.Components) full.ContainerDecl { + const token_tags = tree.tokens.items(.tag); + var result: full.ContainerDecl = .{ + .ast = info, + .layout_token = null, + }; + switch (token_tags[info.main_token - 1]) { + .keyword_extern, .keyword_packed => result.layout_token = info.main_token - 1, + else => {}, + } + return result; +} + +fn fullSwitchCase(tree: Tree, info: full.SwitchCase.Components) full.SwitchCase { + const token_tags = tree.tokens.items(.tag); + var result: full.SwitchCase = .{ + .ast = info, + .payload_token = null, + }; + if (token_tags[info.arrow_token + 1] == .pipe) { + result.payload_token = info.arrow_token + 2; + } + return result; +} + +fn fullAsm(tree: Tree, info: full.Asm.Components) full.Asm { + const token_tags = tree.tokens.items(.tag); + const node_tags = tree.nodes.items(.tag); + var result: full.Asm = .{ + .ast = info, + .volatile_token = null, + .inputs = &.{}, + .outputs = &.{}, + .first_clobber = null, + }; + if (token_tags[info.asm_token + 1] == .keyword_volatile) { + result.volatile_token = info.asm_token + 1; + } + const outputs_end: usize = for (info.items) |item, i| { + switch (node_tags[item]) { + .asm_output => continue, + else => break i, + } + } else info.items.len; + + result.outputs = info.items[0..outputs_end]; + result.inputs = info.items[outputs_end..]; + + if (info.items.len == 0) { + // asm ("foo" ::: "a", "b"); + const template_token = tree.lastToken(info.template); + if (token_tags[template_token + 1] == .colon and + token_tags[template_token + 2] == .colon and + token_tags[template_token + 3] == .colon and + token_tags[template_token + 4] == .string_literal) + { + result.first_clobber = template_token + 4; + } + } else if (result.inputs.len != 0) { + // asm ("foo" :: [_] "" (y) : "a", "b"); + const last_input = result.inputs[result.inputs.len - 1]; + const rparen = tree.lastToken(last_input); + var i = rparen + 1; + // Allow a (useless) comma right after the closing parenthesis. + if (token_tags[i] == .comma) i += 1; + if (token_tags[i] == .colon and + token_tags[i + 1] == .string_literal) + { + result.first_clobber = i + 1; + } + } else { + // asm ("foo" : [_] "" (x) :: "a", "b"); + const last_output = result.outputs[result.outputs.len - 1]; + const rparen = tree.lastToken(last_output); + var i = rparen + 1; + // Allow a (useless) comma right after the closing parenthesis. + if (token_tags[i] == .comma) i += 1; + if (token_tags[i] == .colon and + token_tags[i + 1] == .colon and + token_tags[i + 2] == .string_literal) + { + result.first_clobber = i + 2; + } + } + + return result; +} + +fn fullWhile(tree: Tree, info: full.While.Components) full.While { + const token_tags = tree.tokens.items(.tag); + var result: full.While = .{ + .ast = info, + .inline_token = null, + .label_token = null, + .payload_token = null, + .else_token = undefined, + .error_token = null, + }; + var tok_i = info.while_token - 1; + if (token_tags[tok_i] == .keyword_inline) { + result.inline_token = tok_i; + tok_i -= 1; + } + if (token_tags[tok_i] == .colon and + token_tags[tok_i - 1] == .identifier) + { + result.label_token = tok_i - 1; + } + const last_cond_token = tree.lastToken(info.cond_expr); + if (token_tags[last_cond_token + 2] == .pipe) { + result.payload_token = last_cond_token + 3; + } + if (info.else_expr != 0) { + // then_expr else |x| + // ^ ^ + result.else_token = tree.lastToken(info.then_expr) + 1; + if (token_tags[result.else_token + 1] == .pipe) { + result.error_token = result.else_token + 2; + } + } + return result; +} + +fn fullCall(tree: Tree, info: full.Call.Components) full.Call { + const token_tags = tree.tokens.items(.tag); + var result: full.Call = .{ + .ast = info, + .async_token = null, + }; + const maybe_async_token = tree.firstToken(info.fn_expr) - 1; + if (token_tags[maybe_async_token] == .keyword_async) { + result.async_token = maybe_async_token; + } + return result; +} + +/// Fully assembled AST node information. +pub const full = struct { + pub const VarDecl = struct { + visib_token: ?TokenIndex, + extern_export_token: ?TokenIndex, + lib_name: ?TokenIndex, + threadlocal_token: ?TokenIndex, + comptime_token: ?TokenIndex, + ast: Components, + + pub const Components = struct { + mut_token: TokenIndex, + type_node: Node.Index, + align_node: Node.Index, + section_node: Node.Index, + init_node: Node.Index, + }; + }; + + pub const If = struct { + /// Points to the first token after the `|`. Will either be an identifier or + /// a `*` (with an identifier immediately after it). + payload_token: ?TokenIndex, + /// Points to the identifier after the `|`. + error_token: ?TokenIndex, + /// Populated only if else_expr != 0. + else_token: TokenIndex, + ast: Components, + + pub const Components = struct { + if_token: TokenIndex, + cond_expr: Node.Index, + then_expr: Node.Index, + else_expr: Node.Index, + }; + }; + + pub const While = struct { + ast: Components, + inline_token: ?TokenIndex, + label_token: ?TokenIndex, + payload_token: ?TokenIndex, + error_token: ?TokenIndex, + /// Populated only if else_expr != 0. + else_token: TokenIndex, + + pub const Components = struct { + while_token: TokenIndex, + cond_expr: Node.Index, + cont_expr: Node.Index, + then_expr: Node.Index, + else_expr: Node.Index, + }; + }; + + pub const ContainerField = struct { + comptime_token: ?TokenIndex, + ast: Components, + + pub const Components = struct { + name_token: TokenIndex, + type_expr: Node.Index, + value_expr: Node.Index, + align_expr: Node.Index, + }; + }; + + pub const FnProto = struct { + visib_token: ?TokenIndex, + extern_export_inline_token: ?TokenIndex, + lib_name: ?TokenIndex, + name_token: ?TokenIndex, + lparen: TokenIndex, + ast: Components, + + pub const Components = struct { + proto_node: Node.Index, + fn_token: TokenIndex, + return_type: Node.Index, + params: []const Node.Index, + align_expr: Node.Index, + section_expr: Node.Index, + callconv_expr: Node.Index, + }; + + pub const Param = struct { + first_doc_comment: ?TokenIndex, + name_token: ?TokenIndex, + comptime_noalias: ?TokenIndex, + anytype_ellipsis3: ?TokenIndex, + type_expr: Node.Index, + }; + + /// Abstracts over the fact that anytype and ... are not included + /// in the params slice, since they are simple identifiers and + /// not sub-expressions. + pub const Iterator = struct { + tree: *const Tree, + fn_proto: *const FnProto, + param_i: usize, + tok_i: TokenIndex, + tok_flag: bool, + + pub fn next(it: *Iterator) ?Param { + const token_tags = it.tree.tokens.items(.tag); + while (true) { + var first_doc_comment: ?TokenIndex = null; + var comptime_noalias: ?TokenIndex = null; + var name_token: ?TokenIndex = null; + if (!it.tok_flag) { + if (it.param_i >= it.fn_proto.ast.params.len) { + return null; + } + const param_type = it.fn_proto.ast.params[it.param_i]; + var tok_i = it.tree.firstToken(param_type) - 1; + while (true) : (tok_i -= 1) switch (token_tags[tok_i]) { + .colon => continue, + .identifier => name_token = tok_i, + .doc_comment => first_doc_comment = tok_i, + .keyword_comptime, .keyword_noalias => comptime_noalias = tok_i, + else => break, + }; + it.param_i += 1; + it.tok_i = it.tree.lastToken(param_type) + 1; + // Look for anytype and ... params afterwards. + if (token_tags[it.tok_i] == .comma) { + it.tok_i += 1; + } + it.tok_flag = true; + return Param{ + .first_doc_comment = first_doc_comment, + .comptime_noalias = comptime_noalias, + .name_token = name_token, + .anytype_ellipsis3 = null, + .type_expr = param_type, + }; + } + if (token_tags[it.tok_i] == .comma) { + it.tok_i += 1; + } + if (token_tags[it.tok_i] == .r_paren) { + return null; + } + if (token_tags[it.tok_i] == .doc_comment) { + first_doc_comment = it.tok_i; + while (token_tags[it.tok_i] == .doc_comment) { + it.tok_i += 1; + } + } + switch (token_tags[it.tok_i]) { + .ellipsis3 => { + it.tok_flag = false; // Next iteration should return null. + return Param{ + .first_doc_comment = first_doc_comment, + .comptime_noalias = null, + .name_token = null, + .anytype_ellipsis3 = it.tok_i, + .type_expr = 0, + }; + }, + .keyword_noalias, .keyword_comptime => { + comptime_noalias = it.tok_i; + it.tok_i += 1; + }, + else => {}, + } + if (token_tags[it.tok_i] == .identifier and + token_tags[it.tok_i + 1] == .colon) + { + name_token = it.tok_i; + it.tok_i += 2; + } + if (token_tags[it.tok_i] == .keyword_anytype) { + it.tok_i += 1; + return Param{ + .first_doc_comment = first_doc_comment, + .comptime_noalias = comptime_noalias, + .name_token = name_token, + .anytype_ellipsis3 = it.tok_i - 1, + .type_expr = 0, + }; + } + it.tok_flag = false; + } + } + }; + + pub fn iterate(fn_proto: FnProto, tree: Tree) Iterator { + return .{ + .tree = &tree, + .fn_proto = &fn_proto, + .param_i = 0, + .tok_i = fn_proto.lparen + 1, + .tok_flag = true, + }; + } + }; + + pub const StructInit = struct { + ast: Components, + + pub const Components = struct { + lbrace: TokenIndex, + fields: []const Node.Index, + type_expr: Node.Index, + }; + }; + + pub const ArrayInit = struct { + ast: Components, + + pub const Components = struct { + lbrace: TokenIndex, + elements: []const Node.Index, + type_expr: Node.Index, + }; + }; + + pub const ArrayType = struct { + ast: Components, + + pub const Components = struct { + lbracket: TokenIndex, + elem_count: Node.Index, + sentinel: Node.Index, + elem_type: Node.Index, + }; + }; + + pub const PtrType = struct { + size: std.builtin.TypeInfo.Pointer.Size, + allowzero_token: ?TokenIndex, + const_token: ?TokenIndex, + volatile_token: ?TokenIndex, + ast: Components, + + pub const Components = struct { + main_token: TokenIndex, + align_node: Node.Index, + sentinel: Node.Index, + bit_range_start: Node.Index, + bit_range_end: Node.Index, + child_type: Node.Index, + }; + }; + + pub const Slice = struct { + ast: Components, + + pub const Components = struct { + sliced: Node.Index, + lbracket: TokenIndex, + start: Node.Index, + end: Node.Index, + sentinel: Node.Index, + }; + }; + + pub const ContainerDecl = struct { + layout_token: ?TokenIndex, + ast: Components, + + pub const Components = struct { + main_token: TokenIndex, + /// Populated when main_token is Keyword_union. + enum_token: ?TokenIndex, + members: []const Node.Index, + arg: Node.Index, + }; + }; + + pub const SwitchCase = struct { + /// Points to the first token after the `|`. Will either be an identifier or + /// a `*` (with an identifier immediately after it). + payload_token: ?TokenIndex, + ast: Components, + + pub const Components = struct { + /// If empty, this is an else case + values: []const Node.Index, + arrow_token: TokenIndex, + target_expr: Node.Index, + }; + }; + + pub const Asm = struct { + ast: Components, + volatile_token: ?TokenIndex, + first_clobber: ?TokenIndex, + outputs: []const Node.Index, + inputs: []const Node.Index, + + pub const Components = struct { + asm_token: TokenIndex, + template: Node.Index, + items: []const Node.Index, + rparen: TokenIndex, + }; + }; + + pub const Call = struct { + ast: Components, + async_token: ?TokenIndex, + + pub const Components = struct { + lparen: TokenIndex, + fn_expr: Node.Index, + params: []const Node.Index, + }; + }; +}; + +pub const Error = struct { + tag: Tag, + token: TokenIndex, + extra: union { + none: void, + expected_tag: Token.Tag, + } = .{ .none = {} }, + + pub const Tag = enum { + asterisk_after_ptr_deref, + decl_between_fields, + expected_block, + expected_block_or_assignment, + expected_block_or_expr, + expected_block_or_field, + expected_container_members, + expected_expr, + expected_expr_or_assignment, + expected_fn, + expected_inlinable, + expected_labelable, + expected_param_list, + expected_prefix_expr, + expected_primary_type_expr, + expected_pub_item, + expected_return_type, + expected_semi_or_else, + expected_semi_or_lbrace, + expected_statement, + expected_string_literal, + expected_suffix_op, + expected_type_expr, + expected_var_decl, + expected_var_decl_or_fn, + expected_loop_payload, + expected_container, + extra_align_qualifier, + extra_allowzero_qualifier, + extra_const_qualifier, + extra_volatile_qualifier, + ptr_mod_on_array_child_type, + invalid_bit_range, + invalid_token, + same_line_doc_comment, + unattached_doc_comment, + varargs_nonfinal, + + /// `expected_tag` is populated. + expected_token, + }; +}; + +pub const Node = struct { + tag: Tag, + main_token: TokenIndex, + data: Data, + + pub const Index = u32; + + comptime { + // Goal is to keep this under one byte for efficiency. + assert(@sizeOf(Tag) == 1); + } + + /// Note: The FooComma/FooSemicolon variants exist to ease the implementation of + /// Tree.lastToken() + pub const Tag = enum { + /// sub_list[lhs...rhs] + root, + /// `usingnamespace lhs;`. rhs unused. main_token is `usingnamespace`. + @"usingnamespace", + /// lhs is test name token (must be string literal), if any. + /// rhs is the body node. + test_decl, + /// lhs is the index into extra_data. + /// rhs is the initialization expression, if any. + /// main_token is `var` or `const`. + global_var_decl, + /// `var a: x align(y) = rhs` + /// lhs is the index into extra_data. + /// main_token is `var` or `const`. + local_var_decl, + /// `var a: lhs = rhs`. lhs and rhs may be unused. + /// Can be local or global. + /// main_token is `var` or `const`. + simple_var_decl, + /// `var a align(lhs) = rhs`. lhs and rhs may be unused. + /// Can be local or global. + /// main_token is `var` or `const`. + aligned_var_decl, + /// lhs is the identifier token payload if any, + /// rhs is the deferred expression. + @"errdefer", + /// lhs is unused. + /// rhs is the deferred expression. + @"defer", + /// lhs catch rhs + /// lhs catch |err| rhs + /// main_token is the `catch` keyword. + /// payload is determined by looking at the next token after the `catch` keyword. + @"catch", + /// `lhs.a`. main_token is the dot. rhs is the identifier token index. + field_access, + /// `lhs.?`. main_token is the dot. rhs is the `?` token index. + unwrap_optional, + /// `lhs == rhs`. main_token is op. + equal_equal, + /// `lhs != rhs`. main_token is op. + bang_equal, + /// `lhs < rhs`. main_token is op. + less_than, + /// `lhs > rhs`. main_token is op. + greater_than, + /// `lhs <= rhs`. main_token is op. + less_or_equal, + /// `lhs >= rhs`. main_token is op. + greater_or_equal, + /// `lhs *= rhs`. main_token is op. + assign_mul, + /// `lhs /= rhs`. main_token is op. + assign_div, + /// `lhs *= rhs`. main_token is op. + assign_mod, + /// `lhs += rhs`. main_token is op. + assign_add, + /// `lhs -= rhs`. main_token is op. + assign_sub, + /// `lhs <<= rhs`. main_token is op. + assign_bit_shift_left, + /// `lhs >>= rhs`. main_token is op. + assign_bit_shift_right, + /// `lhs &= rhs`. main_token is op. + assign_bit_and, + /// `lhs ^= rhs`. main_token is op. + assign_bit_xor, + /// `lhs |= rhs`. main_token is op. + assign_bit_or, + /// `lhs *%= rhs`. main_token is op. + assign_mul_wrap, + /// `lhs +%= rhs`. main_token is op. + assign_add_wrap, + /// `lhs -%= rhs`. main_token is op. + assign_sub_wrap, + /// `lhs = rhs`. main_token is op. + assign, + /// `lhs || rhs`. main_token is the `||`. + merge_error_sets, + /// `lhs * rhs`. main_token is the `*`. + mul, + /// `lhs / rhs`. main_token is the `/`. + div, + /// `lhs % rhs`. main_token is the `%`. + mod, + /// `lhs ** rhs`. main_token is the `**`. + array_mult, + /// `lhs *% rhs`. main_token is the `*%`. + mul_wrap, + /// `lhs + rhs`. main_token is the `+`. + add, + /// `lhs - rhs`. main_token is the `-`. + sub, + /// `lhs ++ rhs`. main_token is the `++`. + array_cat, + /// `lhs +% rhs`. main_token is the `+%`. + add_wrap, + /// `lhs -% rhs`. main_token is the `-%`. + sub_wrap, + /// `lhs << rhs`. main_token is the `<<`. + bit_shift_left, + /// `lhs >> rhs`. main_token is the `>>`. + bit_shift_right, + /// `lhs & rhs`. main_token is the `&`. + bit_and, + /// `lhs ^ rhs`. main_token is the `^`. + bit_xor, + /// `lhs | rhs`. main_token is the `|`. + bit_or, + /// `lhs orelse rhs`. main_token is the `orelse`. + @"orelse", + /// `lhs and rhs`. main_token is the `and`. + bool_and, + /// `lhs or rhs`. main_token is the `or`. + bool_or, + /// `op lhs`. rhs unused. main_token is op. + bool_not, + /// `op lhs`. rhs unused. main_token is op. + negation, + /// `op lhs`. rhs unused. main_token is op. + bit_not, + /// `op lhs`. rhs unused. main_token is op. + negation_wrap, + /// `op lhs`. rhs unused. main_token is op. + address_of, + /// `op lhs`. rhs unused. main_token is op. + @"try", + /// `op lhs`. rhs unused. main_token is op. + @"await", + /// `?lhs`. rhs unused. main_token is the `?`. + optional_type, + /// `[lhs]rhs`. + array_type, + /// `[lhs:a]b`. `ArrayTypeSentinel[rhs]`. + array_type_sentinel, + /// `[*]align(lhs) rhs`. lhs can be omitted. + /// `*align(lhs) rhs`. lhs can be omitted. + /// `[]rhs`. + /// main_token is the asterisk if a pointer or the lbracket if a slice + /// main_token might be a ** token, which is shared with a parent/child + /// pointer type and may require special handling. + ptr_type_aligned, + /// `[*:lhs]rhs`. lhs can be omitted. + /// `*rhs`. + /// `[:lhs]rhs`. + /// main_token is the asterisk if a pointer or the lbracket if a slice + /// main_token might be a ** token, which is shared with a parent/child + /// pointer type and may require special handling. + ptr_type_sentinel, + /// lhs is index into ptr_type. rhs is the element type expression. + /// main_token is the asterisk if a pointer or the lbracket if a slice + /// main_token might be a ** token, which is shared with a parent/child + /// pointer type and may require special handling. + ptr_type, + /// lhs is index into ptr_type_bit_range. rhs is the element type expression. + /// main_token is the asterisk if a pointer or the lbracket if a slice + /// main_token might be a ** token, which is shared with a parent/child + /// pointer type and may require special handling. + ptr_type_bit_range, + /// `lhs[rhs..]` + /// main_token is the lbracket. + slice_open, + /// `lhs[b..c]`. rhs is index into Slice + /// main_token is the lbracket. + slice, + /// `lhs[b..c :d]`. rhs is index into SliceSentinel + /// main_token is the lbracket. + slice_sentinel, + /// `lhs.*`. rhs is unused. + deref, + /// `lhs[rhs]`. + array_access, + /// `lhs{rhs}`. rhs can be omitted. + array_init_one, + /// `lhs{rhs,}`. rhs can *not* be omitted + array_init_one_comma, + /// `.{lhs, rhs}`. lhs and rhs can be omitted. + array_init_dot_two, + /// Same as `array_init_dot_two` except there is known to be a trailing comma + /// before the final rbrace. + array_init_dot_two_comma, + /// `.{a, b}`. `sub_list[lhs..rhs]`. + array_init_dot, + /// Same as `array_init_dot` except there is known to be a trailing comma + /// before the final rbrace. + array_init_dot_comma, + /// `lhs{a, b}`. `sub_range_list[rhs]`. lhs can be omitted which means `.{a, b}`. + array_init, + /// Same as `array_init` except there is known to be a trailing comma + /// before the final rbrace. + array_init_comma, + /// `lhs{.a = rhs}`. rhs can be omitted making it empty. + /// main_token is the lbrace. + struct_init_one, + /// `lhs{.a = rhs,}`. rhs can *not* be omitted. + /// main_token is the lbrace. + struct_init_one_comma, + /// `.{.a = lhs, .b = rhs}`. lhs and rhs can be omitted. + /// main_token is the lbrace. + /// No trailing comma before the rbrace. + struct_init_dot_two, + /// Same as `struct_init_dot_two` except there is known to be a trailing comma + /// before the final rbrace. + struct_init_dot_two_comma, + /// `.{.a = b, .c = d}`. `sub_list[lhs..rhs]`. + /// main_token is the lbrace. + struct_init_dot, + /// Same as `struct_init_dot` except there is known to be a trailing comma + /// before the final rbrace. + struct_init_dot_comma, + /// `lhs{.a = b, .c = d}`. `sub_range_list[rhs]`. + /// lhs can be omitted which means `.{.a = b, .c = d}`. + /// main_token is the lbrace. + struct_init, + /// Same as `struct_init` except there is known to be a trailing comma + /// before the final rbrace. + struct_init_comma, + /// `lhs(rhs)`. rhs can be omitted. + /// main_token is the lparen. + call_one, + /// `lhs(rhs,)`. rhs can be omitted. + /// main_token is the lparen. + call_one_comma, + /// `async lhs(rhs)`. rhs can be omitted. + async_call_one, + /// `async lhs(rhs,)`. + async_call_one_comma, + /// `lhs(a, b, c)`. `SubRange[rhs]`. + /// main_token is the `(`. + call, + /// `lhs(a, b, c,)`. `SubRange[rhs]`. + /// main_token is the `(`. + call_comma, + /// `async lhs(a, b, c)`. `SubRange[rhs]`. + /// main_token is the `(`. + async_call, + /// `async lhs(a, b, c,)`. `SubRange[rhs]`. + /// main_token is the `(`. + async_call_comma, + /// `switch(lhs) {}`. `SubRange[rhs]`. + @"switch", + /// Same as switch except there is known to be a trailing comma + /// before the final rbrace + switch_comma, + /// `lhs => rhs`. If lhs is omitted it means `else`. + /// main_token is the `=>` + switch_case_one, + /// `a, b, c => rhs`. `SubRange[lhs]`. + /// main_token is the `=>` + switch_case, + /// `lhs...rhs`. + switch_range, + /// `while (lhs) rhs`. + /// `while (lhs) |x| rhs`. + while_simple, + /// `while (lhs) : (a) b`. `WhileCont[rhs]`. + /// `while (lhs) : (a) b`. `WhileCont[rhs]`. + while_cont, + /// `while (lhs) : (a) b else c`. `While[rhs]`. + /// `while (lhs) |x| : (a) b else c`. `While[rhs]`. + /// `while (lhs) |x| : (a) b else |y| c`. `While[rhs]`. + @"while", + /// `for (lhs) rhs`. + for_simple, + /// `for (lhs) a else b`. `if_list[rhs]`. + @"for", + /// `if (lhs) rhs`. + /// `if (lhs) |a| rhs`. + if_simple, + /// `if (lhs) a else b`. `If[rhs]`. + /// `if (lhs) |x| a else b`. `If[rhs]`. + /// `if (lhs) |x| a else |y| b`. `If[rhs]`. + @"if", + /// `suspend lhs`. lhs can be omitted. rhs is unused. + @"suspend", + /// `resume lhs`. rhs is unused. + @"resume", + /// `continue`. lhs is token index of label if any. rhs is unused. + @"continue", + /// `break :lhs rhs` + /// both lhs and rhs may be omitted. + @"break", + /// `return lhs`. lhs can be omitted. rhs is unused. + @"return", + /// `fn(a: lhs) rhs`. lhs can be omitted. + /// anytype and ... parameters are omitted from the AST tree. + /// main_token is the `fn` keyword. + /// extern function declarations use this tag. + fn_proto_simple, + /// `fn(a: b, c: d) rhs`. `sub_range_list[lhs]`. + /// anytype and ... parameters are omitted from the AST tree. + /// main_token is the `fn` keyword. + /// extern function declarations use this tag. + fn_proto_multi, + /// `fn(a: b) rhs linksection(e) callconv(f)`. `FnProtoOne[lhs]`. + /// zero or one parameters. + /// anytype and ... parameters are omitted from the AST tree. + /// main_token is the `fn` keyword. + /// extern function declarations use this tag. + fn_proto_one, + /// `fn(a: b, c: d) rhs linksection(e) callconv(f)`. `FnProto[lhs]`. + /// anytype and ... parameters are omitted from the AST tree. + /// main_token is the `fn` keyword. + /// extern function declarations use this tag. + fn_proto, + /// lhs is the fn_proto. + /// rhs is the function body block. + /// Note that extern function declarations use the fn_proto tags rather + /// than this one. + fn_decl, + /// `anyframe->rhs`. main_token is `anyframe`. `lhs` is arrow token index. + anyframe_type, + /// Both lhs and rhs unused. + anyframe_literal, + /// Both lhs and rhs unused. + char_literal, + /// Both lhs and rhs unused. + integer_literal, + /// Both lhs and rhs unused. + float_literal, + /// Both lhs and rhs unused. + unreachable_literal, + /// Both lhs and rhs unused. + /// Most identifiers will not have explicit AST nodes, however for expressions + /// which could be one of many different kinds of AST nodes, there will be an + /// identifier AST node for it. + identifier, + /// lhs is the dot token index, rhs unused, main_token is the identifier. + enum_literal, + /// main_token is the string literal token + /// Both lhs and rhs unused. + string_literal, + /// main_token is the first token index (redundant with lhs) + /// lhs is the first token index; rhs is the last token index. + /// Could be a series of multiline_string_literal_line tokens, or a single + /// string_literal token. + multiline_string_literal, + /// `(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, + /// `error{a, b}`. + /// rhs is the rbrace, lhs is unused. + error_set_decl, + /// `struct {}`, `union {}`, `opaque {}`, `enum {}`. `extra_data[lhs..rhs]`. + /// main_token is `struct`, `union`, `opaque`, `enum` keyword. + container_decl, + /// Same as ContainerDecl but there is known to be a trailing comma + /// or semicolon before the rbrace. + container_decl_trailing, + /// `struct {lhs, rhs}`, `union {lhs, rhs}`, `opaque {lhs, rhs}`, `enum {lhs, rhs}`. + /// lhs or rhs can be omitted. + /// main_token is `struct`, `union`, `opaque`, `enum` keyword. + container_decl_two, + /// Same as ContainerDeclTwo except there is known to be a trailing comma + /// or semicolon before the rbrace. + container_decl_two_trailing, + /// `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`. + container_decl_arg, + /// Same as container_decl_arg but there is known to be a trailing + /// comma or semicolon before the rbrace. + container_decl_arg_trailing, + /// `union(enum) {}`. `sub_list[lhs..rhs]`. + /// Note that tagged unions with explicitly provided enums are represented + /// by `container_decl_arg`. + tagged_union, + /// Same as tagged_union but there is known to be a trailing comma + /// or semicolon before the rbrace. + tagged_union_trailing, + /// `union(enum) {lhs, rhs}`. lhs or rhs may be omitted. + /// Note that tagged unions with explicitly provided enums are represented + /// by `container_decl_arg`. + tagged_union_two, + /// Same as tagged_union_two but there is known to be a trailing comma + /// or semicolon before the rbrace. + tagged_union_two_trailing, + /// `union(enum(lhs)) {}`. `SubRange[rhs]`. + tagged_union_enum_tag, + /// Same as tagged_union_enum_tag but there is known to be a trailing comma + /// or semicolon before the rbrace. + tagged_union_enum_tag_trailing, + /// `a: lhs = rhs,`. lhs and rhs can be omitted. + /// main_token is the field name identifier. + /// lastToken() does not include the possible trailing comma. + container_field_init, + /// `a: lhs align(rhs),`. rhs can be omitted. + /// main_token is the field name identifier. + /// lastToken() does not include the possible trailing comma. + container_field_align, + /// `a: lhs align(c) = d,`. `container_field_list[rhs]`. + /// main_token is the field name identifier. + /// lastToken() does not include the possible trailing comma. + container_field, + /// `anytype`. both lhs and rhs unused. + /// Used by `ContainerField`. + @"anytype", + /// `comptime lhs`. rhs unused. + @"comptime", + /// `nosuspend lhs`. rhs unused. + @"nosuspend", + /// `{lhs rhs}`. rhs or lhs can be omitted. + /// main_token points at the lbrace. + block_two, + /// Same as block_two but there is known to be a semicolon before the rbrace. + block_two_semicolon, + /// `{}`. `sub_list[lhs..rhs]`. + /// main_token points at the lbrace. + block, + /// Same as block but there is known to be a semicolon before the rbrace. + block_semicolon, + /// `asm(lhs)`. rhs is the token index of the rparen. + asm_simple, + /// `asm(lhs, a)`. `Asm[rhs]`. + @"asm", + /// `[a] "b" (c)`. lhs is 0, rhs is token index of the rparen. + /// `[a] "b" (-> lhs)`. rhs is token index of the rparen. + /// main_token is `a`. + asm_output, + /// `[a] "b" (lhs)`. rhs is token index of the rparen. + /// main_token is `a`. + asm_input, + /// `error.a`. lhs is token index of `.`. rhs is token index of `a`. + error_value, + /// `lhs!rhs`. main_token is the `!`. + error_union, + + pub fn isContainerField(tag: Tag) bool { + return switch (tag) { + .container_field_init, + .container_field_align, + .container_field, + => true, + + else => false, + }; + } + }; + + pub const Data = struct { + lhs: Index, + rhs: Index, + }; + + pub const LocalVarDecl = struct { + type_node: Index, + align_node: Index, + }; + + pub const ArrayTypeSentinel = struct { + elem_type: Index, + sentinel: Index, + }; + + pub const PtrType = struct { + sentinel: Index, + align_node: Index, + }; + + pub const PtrTypeBitRange = struct { + sentinel: Index, + align_node: Index, + bit_range_start: Index, + bit_range_end: Index, + }; + + pub const SubRange = struct { + /// Index into sub_list. + start: Index, + /// Index into sub_list. + end: Index, + }; + + pub const If = struct { + then_expr: Index, + else_expr: Index, + }; + + pub const ContainerField = struct { + value_expr: Index, + align_expr: Index, + }; + + pub const GlobalVarDecl = struct { + type_node: Index, + align_node: Index, + section_node: Index, + }; + + pub const Slice = struct { + start: Index, + end: Index, + }; + + pub const SliceSentinel = struct { + start: Index, + /// May be 0 if the slice is "open" + end: Index, + sentinel: Index, + }; + + pub const While = struct { + cont_expr: Index, + then_expr: Index, + else_expr: Index, + }; + + pub const WhileCont = struct { + cont_expr: Index, + then_expr: Index, + }; + + pub const FnProtoOne = struct { + /// Populated if there is exactly 1 parameter. Otherwise there are 0 parameters. + param: Index, + /// Populated if align(A) is present. + align_expr: Index, + /// Populated if linksection(A) is present. + section_expr: Index, + /// Populated if callconv(A) is present. + callconv_expr: Index, + }; + + pub const FnProto = struct { + params_start: Index, + params_end: Index, + /// Populated if align(A) is present. + align_expr: Index, + /// Populated if linksection(A) is present. + section_expr: Index, + /// Populated if callconv(A) is present. + callconv_expr: Index, + }; + + pub const Asm = struct { + items_start: Index, + items_end: Index, + /// Needed to make lastToken() work. + rparen: TokenIndex, + }; +}; diff --git a/lib/std/zig/ast.zig b/lib/std/zig/ast.zig deleted file mode 100644 index 535dc99483..0000000000 --- a/lib/std/zig/ast.zig +++ /dev/null @@ -1,2978 +0,0 @@ -const std = @import("../std.zig"); -const assert = std.debug.assert; -const testing = std.testing; -const mem = std.mem; -const Token = std.zig.Token; - -pub const TokenIndex = u32; -pub const ByteOffset = u32; - -pub const TokenList = std.MultiArrayList(struct { - tag: Token.Tag, - start: ByteOffset, -}); -pub const NodeList = std.MultiArrayList(Node); - -pub const Tree = struct { - /// Reference to externally-owned data. - source: [:0]const u8, - - tokens: TokenList.Slice, - /// The root AST node is assumed to be index 0. Since there can be no - /// references to the root node, this means 0 is available to indicate null. - nodes: NodeList.Slice, - extra_data: []Node.Index, - - errors: []const Error, - - pub const Location = struct { - line: usize, - column: usize, - line_start: usize, - line_end: usize, - }; - - pub fn deinit(tree: *Tree, gpa: *mem.Allocator) void { - tree.tokens.deinit(gpa); - tree.nodes.deinit(gpa); - gpa.free(tree.extra_data); - gpa.free(tree.errors); - tree.* = undefined; - } - - pub const RenderError = error{ - /// Ran out of memory allocating call stack frames to complete rendering, or - /// ran out of memory allocating space in the output buffer. - OutOfMemory, - }; - - /// `gpa` is used for allocating the resulting formatted source code, as well as - /// for allocating extra stack memory if needed, because this function utilizes recursion. - /// Note: that's not actually true yet, see https://github.com/ziglang/zig/issues/1006. - /// Caller owns the returned slice of bytes, allocated with `gpa`. - pub fn render(tree: Tree, gpa: *mem.Allocator) RenderError![]u8 { - var buffer = std.ArrayList(u8).init(gpa); - defer buffer.deinit(); - - try tree.renderToArrayList(&buffer); - return buffer.toOwnedSlice(); - } - - pub fn renderToArrayList(tree: Tree, buffer: *std.ArrayList(u8)) RenderError!void { - return @import("./render.zig").renderTree(buffer, tree); - } - - pub fn tokenLocation(self: Tree, start_offset: ByteOffset, token_index: TokenIndex) Location { - var loc = Location{ - .line = 0, - .column = 0, - .line_start = start_offset, - .line_end = self.source.len, - }; - const token_start = self.tokens.items(.start)[token_index]; - for (self.source[start_offset..]) |c, i| { - if (i + start_offset == token_start) { - loc.line_end = i + start_offset; - while (loc.line_end < self.source.len and self.source[loc.line_end] != '\n') { - loc.line_end += 1; - } - return loc; - } - if (c == '\n') { - loc.line += 1; - loc.column = 0; - loc.line_start = i + 1; - } else { - loc.column += 1; - } - } - return loc; - } - - pub fn tokenSlice(tree: Tree, token_index: TokenIndex) []const u8 { - const token_starts = tree.tokens.items(.start); - const token_tags = tree.tokens.items(.tag); - const token_tag = token_tags[token_index]; - - // Many tokens can be determined entirely by their tag. - if (token_tag.lexeme()) |lexeme| { - return lexeme; - } - - // For some tokens, re-tokenization is needed to find the end. - var tokenizer: std.zig.Tokenizer = .{ - .buffer = tree.source, - .index = token_starts[token_index], - .pending_invalid_token = null, - }; - const token = tokenizer.next(); - assert(token.tag == token_tag); - return tree.source[token.loc.start..token.loc.end]; - } - - pub fn extraData(tree: Tree, index: usize, comptime T: type) T { - const fields = std.meta.fields(T); - var result: T = undefined; - inline for (fields) |field, i| { - comptime assert(field.field_type == Node.Index); - @field(result, field.name) = tree.extra_data[index + i]; - } - return result; - } - - pub fn rootDecls(tree: Tree) []const Node.Index { - // Root is always index 0. - const nodes_data = tree.nodes.items(.data); - return tree.extra_data[nodes_data[0].lhs..nodes_data[0].rhs]; - } - - pub fn renderError(tree: Tree, parse_error: Error, stream: anytype) !void { - const token_tags = tree.tokens.items(.tag); - switch (parse_error.tag) { - .asterisk_after_ptr_deref => { - // Note that the token will point at the `.*` but ideally the source - // location would point to the `*` after the `.*`. - return stream.writeAll("'.*' cannot be followed by '*'. Are you missing a space?"); - }, - .decl_between_fields => { - return stream.writeAll("declarations are not allowed between container fields"); - }, - .expected_block => { - return stream.print("expected block or field, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_block_or_assignment => { - return stream.print("expected block or assignment, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_block_or_expr => { - return stream.print("expected block or expression, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_block_or_field => { - return stream.print("expected block or field, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_container_members => { - return stream.print("expected test, comptime, var decl, or container field, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_expr => { - return stream.print("expected expression, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_expr_or_assignment => { - return stream.print("expected expression or assignment, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_fn => { - return stream.print("expected function, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_inlinable => { - return stream.print("expected 'while' or 'for', found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_labelable => { - return stream.print("expected 'while', 'for', 'inline', 'suspend', or '{{', found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_param_list => { - return stream.print("expected parameter list, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_prefix_expr => { - return stream.print("expected prefix expression, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_primary_type_expr => { - return stream.print("expected primary type expression, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_pub_item => { - return stream.writeAll("expected function or variable declaration after pub"); - }, - .expected_return_type => { - return stream.print("expected return type expression, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_semi_or_else => { - return stream.print("expected ';' or 'else', found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_semi_or_lbrace => { - return stream.print("expected ';' or '{{', found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_statement => { - return stream.print("expected statement, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_string_literal => { - return stream.print("expected string literal, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_suffix_op => { - return stream.print("expected pointer dereference, optional unwrap, or field access, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_type_expr => { - return stream.print("expected type expression, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_var_decl => { - return stream.print("expected variable declaration, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_var_decl_or_fn => { - return stream.print("expected variable declaration or function, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_loop_payload => { - return stream.print("expected loop payload, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .expected_container => { - return stream.print("expected a struct, enum or union, found '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .extra_align_qualifier => { - return stream.writeAll("extra align qualifier"); - }, - .extra_allowzero_qualifier => { - return stream.writeAll("extra allowzero qualifier"); - }, - .extra_const_qualifier => { - return stream.writeAll("extra const qualifier"); - }, - .extra_volatile_qualifier => { - return stream.writeAll("extra volatile qualifier"); - }, - .ptr_mod_on_array_child_type => { - return stream.print("pointer modifier '{s}' not allowed on array child type", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .invalid_bit_range => { - return stream.writeAll("bit range not allowed on slices and arrays"); - }, - .invalid_token => { - return stream.print("invalid token: '{s}'", .{ - token_tags[parse_error.token].symbol(), - }); - }, - .same_line_doc_comment => { - return stream.writeAll("same line documentation comment"); - }, - .unattached_doc_comment => { - return stream.writeAll("unattached documentation comment"); - }, - .varargs_nonfinal => { - return stream.writeAll("function prototype has parameter after varargs"); - }, - - .expected_token => { - const found_tag = token_tags[parse_error.token]; - const expected_symbol = parse_error.extra.expected_tag.symbol(); - switch (found_tag) { - .invalid => return stream.print("expected '{s}', found invalid bytes", .{ - expected_symbol, - }), - else => return stream.print("expected '{s}', found '{s}'", .{ - expected_symbol, found_tag.symbol(), - }), - } - }, - } - } - - pub fn firstToken(tree: Tree, node: Node.Index) TokenIndex { - const tags = tree.nodes.items(.tag); - const datas = tree.nodes.items(.data); - const main_tokens = tree.nodes.items(.main_token); - const token_tags = tree.tokens.items(.tag); - var end_offset: TokenIndex = 0; - var n = node; - while (true) switch (tags[n]) { - .root => return 0, - - .test_decl, - .@"errdefer", - .@"defer", - .bool_not, - .negation, - .bit_not, - .negation_wrap, - .address_of, - .@"try", - .@"await", - .optional_type, - .@"switch", - .switch_comma, - .if_simple, - .@"if", - .@"suspend", - .@"resume", - .@"continue", - .@"break", - .@"return", - .anyframe_type, - .identifier, - .anyframe_literal, - .char_literal, - .integer_literal, - .float_literal, - .unreachable_literal, - .string_literal, - .multiline_string_literal, - .grouped_expression, - .builtin_call_two, - .builtin_call_two_comma, - .builtin_call, - .builtin_call_comma, - .error_set_decl, - .@"anytype", - .@"comptime", - .@"nosuspend", - .asm_simple, - .@"asm", - .array_type, - .array_type_sentinel, - .error_value, - => return main_tokens[n] - end_offset, - - .array_init_dot, - .array_init_dot_comma, - .array_init_dot_two, - .array_init_dot_two_comma, - .struct_init_dot, - .struct_init_dot_comma, - .struct_init_dot_two, - .struct_init_dot_two_comma, - .enum_literal, - => return main_tokens[n] - 1 - end_offset, - - .@"catch", - .field_access, - .unwrap_optional, - .equal_equal, - .bang_equal, - .less_than, - .greater_than, - .less_or_equal, - .greater_or_equal, - .assign_mul, - .assign_div, - .assign_mod, - .assign_add, - .assign_sub, - .assign_bit_shift_left, - .assign_bit_shift_right, - .assign_bit_and, - .assign_bit_xor, - .assign_bit_or, - .assign_mul_wrap, - .assign_add_wrap, - .assign_sub_wrap, - .assign, - .merge_error_sets, - .mul, - .div, - .mod, - .array_mult, - .mul_wrap, - .add, - .sub, - .array_cat, - .add_wrap, - .sub_wrap, - .bit_shift_left, - .bit_shift_right, - .bit_and, - .bit_xor, - .bit_or, - .@"orelse", - .bool_and, - .bool_or, - .slice_open, - .slice, - .slice_sentinel, - .deref, - .array_access, - .array_init_one, - .array_init_one_comma, - .array_init, - .array_init_comma, - .struct_init_one, - .struct_init_one_comma, - .struct_init, - .struct_init_comma, - .call_one, - .call_one_comma, - .call, - .call_comma, - .switch_range, - .error_union, - => n = datas[n].lhs, - - .fn_decl, - .fn_proto_simple, - .fn_proto_multi, - .fn_proto_one, - .fn_proto, - => { - var i = main_tokens[n]; // fn token - while (i > 0) { - i -= 1; - switch (token_tags[i]) { - .keyword_extern, - .keyword_export, - .keyword_pub, - .keyword_inline, - .keyword_noinline, - .string_literal, - => continue, - - else => return i + 1 - end_offset, - } - } - return i - end_offset; - }, - - .@"usingnamespace" => { - const main_token = main_tokens[n]; - if (main_token > 0 and token_tags[main_token - 1] == .keyword_pub) { - end_offset += 1; - } - return main_token - end_offset; - }, - - .async_call_one, - .async_call_one_comma, - .async_call, - .async_call_comma, - => { - end_offset += 1; // async token - n = datas[n].lhs; - }, - - .container_field_init, - .container_field_align, - .container_field, - => { - const name_token = main_tokens[n]; - if (name_token > 0 and token_tags[name_token - 1] == .keyword_comptime) { - end_offset += 1; - } - return name_token - end_offset; - }, - - .global_var_decl, - .local_var_decl, - .simple_var_decl, - .aligned_var_decl, - => { - var i = main_tokens[n]; // mut token - while (i > 0) { - i -= 1; - switch (token_tags[i]) { - .keyword_extern, - .keyword_export, - .keyword_comptime, - .keyword_pub, - .keyword_threadlocal, - .string_literal, - => continue, - - else => return i + 1 - end_offset, - } - } - return i - end_offset; - }, - - .block, - .block_semicolon, - .block_two, - .block_two_semicolon, - => { - // Look for a label. - const lbrace = main_tokens[n]; - if (token_tags[lbrace - 1] == .colon and - token_tags[lbrace - 2] == .identifier) - { - end_offset += 2; - } - return lbrace - end_offset; - }, - - .container_decl, - .container_decl_trailing, - .container_decl_two, - .container_decl_two_trailing, - .container_decl_arg, - .container_decl_arg_trailing, - .tagged_union, - .tagged_union_trailing, - .tagged_union_two, - .tagged_union_two_trailing, - .tagged_union_enum_tag, - .tagged_union_enum_tag_trailing, - => { - const main_token = main_tokens[n]; - switch (token_tags[main_token - 1]) { - .keyword_packed, .keyword_extern => end_offset += 1, - else => {}, - } - return main_token - end_offset; - }, - - .ptr_type_aligned, - .ptr_type_sentinel, - .ptr_type, - .ptr_type_bit_range, - => { - const main_token = main_tokens[n]; - return switch (token_tags[main_token]) { - .asterisk, - .asterisk_asterisk, - => switch (token_tags[main_token - 1]) { - .l_bracket => main_token - 1, - else => main_token, - }, - .l_bracket => main_token, - else => unreachable, - } - end_offset; - }, - - .switch_case_one => { - if (datas[n].lhs == 0) { - return main_tokens[n] - 1 - end_offset; // else token - } else { - n = datas[n].lhs; - } - }, - .switch_case => { - const extra = tree.extraData(datas[n].lhs, Node.SubRange); - assert(extra.end - extra.start > 0); - n = tree.extra_data[extra.start]; - }, - - .asm_output, .asm_input => { - assert(token_tags[main_tokens[n] - 1] == .l_bracket); - return main_tokens[n] - 1 - end_offset; - }, - - .while_simple, - .while_cont, - .@"while", - .for_simple, - .@"for", - => { - // Look for a label and inline. - const main_token = main_tokens[n]; - var result = main_token; - if (token_tags[result - 1] == .keyword_inline) { - result -= 1; - } - if (token_tags[result - 1] == .colon) { - result -= 2; - } - return result - end_offset; - }, - }; - } - - pub fn lastToken(tree: Tree, node: Node.Index) TokenIndex { - const tags = tree.nodes.items(.tag); - const datas = tree.nodes.items(.data); - const main_tokens = tree.nodes.items(.main_token); - const token_starts = tree.tokens.items(.start); - const token_tags = tree.tokens.items(.tag); - var n = node; - var end_offset: TokenIndex = 0; - while (true) switch (tags[n]) { - .root => return @intCast(TokenIndex, tree.tokens.len - 1), - - .@"usingnamespace", - .bool_not, - .negation, - .bit_not, - .negation_wrap, - .address_of, - .@"try", - .@"await", - .optional_type, - .@"resume", - .@"nosuspend", - .@"comptime", - => n = datas[n].lhs, - - .test_decl, - .@"errdefer", - .@"defer", - .@"catch", - .equal_equal, - .bang_equal, - .less_than, - .greater_than, - .less_or_equal, - .greater_or_equal, - .assign_mul, - .assign_div, - .assign_mod, - .assign_add, - .assign_sub, - .assign_bit_shift_left, - .assign_bit_shift_right, - .assign_bit_and, - .assign_bit_xor, - .assign_bit_or, - .assign_mul_wrap, - .assign_add_wrap, - .assign_sub_wrap, - .assign, - .merge_error_sets, - .mul, - .div, - .mod, - .array_mult, - .mul_wrap, - .add, - .sub, - .array_cat, - .add_wrap, - .sub_wrap, - .bit_shift_left, - .bit_shift_right, - .bit_and, - .bit_xor, - .bit_or, - .@"orelse", - .bool_and, - .bool_or, - .anyframe_type, - .error_union, - .if_simple, - .while_simple, - .for_simple, - .fn_proto_simple, - .fn_proto_multi, - .ptr_type_aligned, - .ptr_type_sentinel, - .ptr_type, - .ptr_type_bit_range, - .array_type, - .switch_case_one, - .switch_case, - .switch_range, - => n = datas[n].rhs, - - .field_access, - .unwrap_optional, - .grouped_expression, - .multiline_string_literal, - .error_set_decl, - .asm_simple, - .asm_output, - .asm_input, - .error_value, - => return datas[n].rhs + end_offset, - - .@"anytype", - .anyframe_literal, - .char_literal, - .integer_literal, - .float_literal, - .unreachable_literal, - .identifier, - .deref, - .enum_literal, - .string_literal, - => return main_tokens[n] + end_offset, - - .@"return" => if (datas[n].lhs != 0) { - n = datas[n].lhs; - } else { - return main_tokens[n] + end_offset; - }, - - .call, .async_call => { - end_offset += 1; // for the rparen - const params = tree.extraData(datas[n].rhs, Node.SubRange); - if (params.end - params.start == 0) { - return main_tokens[n] + end_offset; - } - n = tree.extra_data[params.end - 1]; // last parameter - }, - .tagged_union_enum_tag => { - const members = tree.extraData(datas[n].rhs, Node.SubRange); - if (members.end - members.start == 0) { - end_offset += 4; // for the rparen + rparen + lbrace + rbrace - n = datas[n].lhs; - } else { - end_offset += 1; // for the rbrace - n = tree.extra_data[members.end - 1]; // last parameter - } - }, - .call_comma, - .async_call_comma, - .tagged_union_enum_tag_trailing, - => { - end_offset += 2; // for the comma/semicolon + rparen/rbrace - const params = tree.extraData(datas[n].rhs, Node.SubRange); - assert(params.end > params.start); - n = tree.extra_data[params.end - 1]; // last parameter - }, - .@"switch" => { - const cases = tree.extraData(datas[n].rhs, Node.SubRange); - if (cases.end - cases.start == 0) { - end_offset += 3; // rparen, lbrace, rbrace - n = datas[n].lhs; // condition expression - } else { - end_offset += 1; // for the rbrace - n = tree.extra_data[cases.end - 1]; // last case - } - }, - .container_decl_arg => { - const members = tree.extraData(datas[n].rhs, Node.SubRange); - if (members.end - members.start == 0) { - end_offset += 3; // for the rparen + lbrace + rbrace - n = datas[n].lhs; - } else { - end_offset += 1; // for the rbrace - n = tree.extra_data[members.end - 1]; // last parameter - } - }, - .@"asm" => { - const extra = tree.extraData(datas[n].rhs, Node.Asm); - return extra.rparen + end_offset; - }, - .array_init, - .struct_init, - => { - const elements = tree.extraData(datas[n].rhs, Node.SubRange); - assert(elements.end - elements.start > 0); - end_offset += 1; // for the rbrace - n = tree.extra_data[elements.end - 1]; // last element - }, - .array_init_comma, - .struct_init_comma, - .container_decl_arg_trailing, - .switch_comma, - => { - const members = tree.extraData(datas[n].rhs, Node.SubRange); - assert(members.end - members.start > 0); - end_offset += 2; // for the comma + rbrace - n = tree.extra_data[members.end - 1]; // last parameter - }, - .array_init_dot, - .struct_init_dot, - .block, - .container_decl, - .tagged_union, - .builtin_call, - => { - assert(datas[n].rhs - datas[n].lhs > 0); - end_offset += 1; // for the rbrace - n = tree.extra_data[datas[n].rhs - 1]; // last statement - }, - .array_init_dot_comma, - .struct_init_dot_comma, - .block_semicolon, - .container_decl_trailing, - .tagged_union_trailing, - .builtin_call_comma, - => { - assert(datas[n].rhs - datas[n].lhs > 0); - end_offset += 2; // for the comma/semicolon + rbrace/rparen - n = tree.extra_data[datas[n].rhs - 1]; // last member - }, - .call_one, - .async_call_one, - .array_access, - => { - end_offset += 1; // for the rparen/rbracket - if (datas[n].rhs == 0) { - return main_tokens[n] + end_offset; - } - n = datas[n].rhs; - }, - .array_init_dot_two, - .block_two, - .builtin_call_two, - .struct_init_dot_two, - .container_decl_two, - .tagged_union_two, - => { - if (datas[n].rhs != 0) { - end_offset += 1; // for the rparen/rbrace - n = datas[n].rhs; - } else if (datas[n].lhs != 0) { - end_offset += 1; // for the rparen/rbrace - n = datas[n].lhs; - } else { - switch (tags[n]) { - .array_init_dot_two, - .block_two, - .struct_init_dot_two, - => end_offset += 1, // rbrace - .builtin_call_two => end_offset += 2, // lparen/lbrace + rparen/rbrace - .container_decl_two => { - var i: u32 = 2; // lbrace + rbrace - while (token_tags[main_tokens[n] + i] == .container_doc_comment) i += 1; - end_offset += i; - }, - .tagged_union_two => { - var i: u32 = 5; // (enum) {} - while (token_tags[main_tokens[n] + i] == .container_doc_comment) i += 1; - end_offset += i; - }, - else => unreachable, - } - return main_tokens[n] + end_offset; - } - }, - .array_init_dot_two_comma, - .builtin_call_two_comma, - .block_two_semicolon, - .struct_init_dot_two_comma, - .container_decl_two_trailing, - .tagged_union_two_trailing, - => { - end_offset += 2; // for the comma/semicolon + rbrace/rparen - if (datas[n].rhs != 0) { - n = datas[n].rhs; - } else if (datas[n].lhs != 0) { - n = datas[n].lhs; - } else { - unreachable; - } - }, - .simple_var_decl => { - if (datas[n].rhs != 0) { - n = datas[n].rhs; - } else if (datas[n].lhs != 0) { - n = datas[n].lhs; - } else { - end_offset += 1; // from mut token to name - return main_tokens[n] + end_offset; - } - }, - .aligned_var_decl => { - if (datas[n].rhs != 0) { - n = datas[n].rhs; - } else if (datas[n].lhs != 0) { - end_offset += 1; // for the rparen - n = datas[n].lhs; - } else { - end_offset += 1; // from mut token to name - return main_tokens[n] + end_offset; - } - }, - .global_var_decl => { - if (datas[n].rhs != 0) { - n = datas[n].rhs; - } else { - const extra = tree.extraData(datas[n].lhs, Node.GlobalVarDecl); - if (extra.section_node != 0) { - end_offset += 1; // for the rparen - n = extra.section_node; - } else if (extra.align_node != 0) { - end_offset += 1; // for the rparen - n = extra.align_node; - } else if (extra.type_node != 0) { - n = extra.type_node; - } else { - end_offset += 1; // from mut token to name - return main_tokens[n] + end_offset; - } - } - }, - .local_var_decl => { - if (datas[n].rhs != 0) { - n = datas[n].rhs; - } else { - const extra = tree.extraData(datas[n].lhs, Node.LocalVarDecl); - if (extra.align_node != 0) { - end_offset += 1; // for the rparen - n = extra.align_node; - } else if (extra.type_node != 0) { - n = extra.type_node; - } else { - end_offset += 1; // from mut token to name - return main_tokens[n] + end_offset; - } - } - }, - .container_field_init => { - if (datas[n].rhs != 0) { - n = datas[n].rhs; - } else if (datas[n].lhs != 0) { - n = datas[n].lhs; - } else { - return main_tokens[n] + end_offset; - } - }, - .container_field_align => { - if (datas[n].rhs != 0) { - end_offset += 1; // for the rparen - n = datas[n].rhs; - } else if (datas[n].lhs != 0) { - n = datas[n].lhs; - } else { - return main_tokens[n] + end_offset; - } - }, - .container_field => { - const extra = tree.extraData(datas[n].rhs, Node.ContainerField); - if (extra.value_expr != 0) { - n = extra.value_expr; - } else if (extra.align_expr != 0) { - end_offset += 1; // for the rparen - n = extra.align_expr; - } else if (datas[n].lhs != 0) { - n = datas[n].lhs; - } else { - return main_tokens[n] + end_offset; - } - }, - - .array_init_one, - .struct_init_one, - => { - end_offset += 1; // rbrace - if (datas[n].rhs == 0) { - return main_tokens[n] + end_offset; - } else { - n = datas[n].rhs; - } - }, - .slice_open, - .call_one_comma, - .async_call_one_comma, - .array_init_one_comma, - .struct_init_one_comma, - => { - end_offset += 2; // ellipsis2 + rbracket, or comma + rparen - n = datas[n].rhs; - assert(n != 0); - }, - .slice => { - const extra = tree.extraData(datas[n].rhs, Node.Slice); - assert(extra.end != 0); // should have used slice_open - end_offset += 1; // rbracket - n = extra.end; - }, - .slice_sentinel => { - const extra = tree.extraData(datas[n].rhs, Node.SliceSentinel); - assert(extra.sentinel != 0); // should have used slice - end_offset += 1; // rbracket - n = extra.sentinel; - }, - - .@"continue" => { - if (datas[n].lhs != 0) { - return datas[n].lhs + end_offset; - } else { - return main_tokens[n] + end_offset; - } - }, - .@"break" => { - if (datas[n].rhs != 0) { - n = datas[n].rhs; - } else if (datas[n].lhs != 0) { - return datas[n].lhs + end_offset; - } else { - return main_tokens[n] + end_offset; - } - }, - .fn_decl => { - if (datas[n].rhs != 0) { - n = datas[n].rhs; - } else { - n = datas[n].lhs; - } - }, - .fn_proto_one => { - const extra = tree.extraData(datas[n].lhs, Node.FnProtoOne); - // linksection, callconv, align can appear in any order, so we - // find the last one here. - var max_node: Node.Index = datas[n].rhs; - var max_start = token_starts[main_tokens[max_node]]; - var max_offset: TokenIndex = 0; - if (extra.align_expr != 0) { - const start = token_starts[main_tokens[extra.align_expr]]; - if (start > max_start) { - max_node = extra.align_expr; - max_start = start; - max_offset = 1; // for the rparen - } - } - if (extra.section_expr != 0) { - const start = token_starts[main_tokens[extra.section_expr]]; - if (start > max_start) { - max_node = extra.section_expr; - max_start = start; - max_offset = 1; // for the rparen - } - } - if (extra.callconv_expr != 0) { - const start = token_starts[main_tokens[extra.callconv_expr]]; - if (start > max_start) { - max_node = extra.callconv_expr; - max_start = start; - max_offset = 1; // for the rparen - } - } - n = max_node; - end_offset += max_offset; - }, - .fn_proto => { - const extra = tree.extraData(datas[n].lhs, Node.FnProto); - // linksection, callconv, align can appear in any order, so we - // find the last one here. - var max_node: Node.Index = datas[n].rhs; - var max_start = token_starts[main_tokens[max_node]]; - var max_offset: TokenIndex = 0; - if (extra.align_expr != 0) { - const start = token_starts[main_tokens[extra.align_expr]]; - if (start > max_start) { - max_node = extra.align_expr; - max_start = start; - max_offset = 1; // for the rparen - } - } - if (extra.section_expr != 0) { - const start = token_starts[main_tokens[extra.section_expr]]; - if (start > max_start) { - max_node = extra.section_expr; - max_start = start; - max_offset = 1; // for the rparen - } - } - if (extra.callconv_expr != 0) { - const start = token_starts[main_tokens[extra.callconv_expr]]; - if (start > max_start) { - max_node = extra.callconv_expr; - max_start = start; - max_offset = 1; // for the rparen - } - } - n = max_node; - end_offset += max_offset; - }, - .while_cont => { - const extra = tree.extraData(datas[n].rhs, Node.WhileCont); - assert(extra.then_expr != 0); - n = extra.then_expr; - }, - .@"while" => { - const extra = tree.extraData(datas[n].rhs, Node.While); - assert(extra.else_expr != 0); - n = extra.else_expr; - }, - .@"if", .@"for" => { - const extra = tree.extraData(datas[n].rhs, Node.If); - assert(extra.else_expr != 0); - n = extra.else_expr; - }, - .@"suspend" => { - if (datas[n].lhs != 0) { - n = datas[n].lhs; - } else { - return main_tokens[n] + end_offset; - } - }, - .array_type_sentinel => { - const extra = tree.extraData(datas[n].rhs, Node.ArrayTypeSentinel); - n = extra.elem_type; - }, - }; - } - - pub fn tokensOnSameLine(tree: Tree, token1: TokenIndex, token2: TokenIndex) bool { - const token_starts = tree.tokens.items(.start); - const source = tree.source[token_starts[token1]..token_starts[token2]]; - return mem.indexOfScalar(u8, source, '\n') == null; - } - - pub fn getNodeSource(tree: Tree, node: Node.Index) []const u8 { - const token_starts = tree.tokens.items(.start); - const first_token = tree.firstToken(node); - const last_token = tree.lastToken(node); - const start = token_starts[first_token]; - const end = token_starts[last_token] + tree.tokenSlice(last_token).len; - return tree.source[start..end]; - } - - pub fn globalVarDecl(tree: Tree, node: Node.Index) full.VarDecl { - assert(tree.nodes.items(.tag)[node] == .global_var_decl); - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.lhs, Node.GlobalVarDecl); - return tree.fullVarDecl(.{ - .type_node = extra.type_node, - .align_node = extra.align_node, - .section_node = extra.section_node, - .init_node = data.rhs, - .mut_token = tree.nodes.items(.main_token)[node], - }); - } - - pub fn localVarDecl(tree: Tree, node: Node.Index) full.VarDecl { - assert(tree.nodes.items(.tag)[node] == .local_var_decl); - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.lhs, Node.LocalVarDecl); - return tree.fullVarDecl(.{ - .type_node = extra.type_node, - .align_node = extra.align_node, - .section_node = 0, - .init_node = data.rhs, - .mut_token = tree.nodes.items(.main_token)[node], - }); - } - - pub fn simpleVarDecl(tree: Tree, node: Node.Index) full.VarDecl { - assert(tree.nodes.items(.tag)[node] == .simple_var_decl); - const data = tree.nodes.items(.data)[node]; - return tree.fullVarDecl(.{ - .type_node = data.lhs, - .align_node = 0, - .section_node = 0, - .init_node = data.rhs, - .mut_token = tree.nodes.items(.main_token)[node], - }); - } - - pub fn alignedVarDecl(tree: Tree, node: Node.Index) full.VarDecl { - assert(tree.nodes.items(.tag)[node] == .aligned_var_decl); - const data = tree.nodes.items(.data)[node]; - return tree.fullVarDecl(.{ - .type_node = 0, - .align_node = data.lhs, - .section_node = 0, - .init_node = data.rhs, - .mut_token = tree.nodes.items(.main_token)[node], - }); - } - - pub fn ifSimple(tree: Tree, node: Node.Index) full.If { - assert(tree.nodes.items(.tag)[node] == .if_simple); - const data = tree.nodes.items(.data)[node]; - return tree.fullIf(.{ - .cond_expr = data.lhs, - .then_expr = data.rhs, - .else_expr = 0, - .if_token = tree.nodes.items(.main_token)[node], - }); - } - - pub fn ifFull(tree: Tree, node: Node.Index) full.If { - assert(tree.nodes.items(.tag)[node] == .@"if"); - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.rhs, Node.If); - return tree.fullIf(.{ - .cond_expr = data.lhs, - .then_expr = extra.then_expr, - .else_expr = extra.else_expr, - .if_token = tree.nodes.items(.main_token)[node], - }); - } - - pub fn containerField(tree: Tree, node: Node.Index) full.ContainerField { - assert(tree.nodes.items(.tag)[node] == .container_field); - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.rhs, Node.ContainerField); - return tree.fullContainerField(.{ - .name_token = tree.nodes.items(.main_token)[node], - .type_expr = data.lhs, - .value_expr = extra.value_expr, - .align_expr = extra.align_expr, - }); - } - - pub fn containerFieldInit(tree: Tree, node: Node.Index) full.ContainerField { - assert(tree.nodes.items(.tag)[node] == .container_field_init); - const data = tree.nodes.items(.data)[node]; - return tree.fullContainerField(.{ - .name_token = tree.nodes.items(.main_token)[node], - .type_expr = data.lhs, - .value_expr = data.rhs, - .align_expr = 0, - }); - } - - pub fn containerFieldAlign(tree: Tree, node: Node.Index) full.ContainerField { - assert(tree.nodes.items(.tag)[node] == .container_field_align); - const data = tree.nodes.items(.data)[node]; - return tree.fullContainerField(.{ - .name_token = tree.nodes.items(.main_token)[node], - .type_expr = data.lhs, - .value_expr = 0, - .align_expr = data.rhs, - }); - } - - pub fn fnProtoSimple(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnProto { - assert(tree.nodes.items(.tag)[node] == .fn_proto_simple); - const data = tree.nodes.items(.data)[node]; - buffer[0] = data.lhs; - const params = if (data.lhs == 0) buffer[0..0] else buffer[0..1]; - return tree.fullFnProto(.{ - .proto_node = node, - .fn_token = tree.nodes.items(.main_token)[node], - .return_type = data.rhs, - .params = params, - .align_expr = 0, - .section_expr = 0, - .callconv_expr = 0, - }); - } - - pub fn fnProtoMulti(tree: Tree, node: Node.Index) full.FnProto { - assert(tree.nodes.items(.tag)[node] == .fn_proto_multi); - const data = tree.nodes.items(.data)[node]; - const params_range = tree.extraData(data.lhs, Node.SubRange); - const params = tree.extra_data[params_range.start..params_range.end]; - return tree.fullFnProto(.{ - .proto_node = node, - .fn_token = tree.nodes.items(.main_token)[node], - .return_type = data.rhs, - .params = params, - .align_expr = 0, - .section_expr = 0, - .callconv_expr = 0, - }); - } - - pub fn fnProtoOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.FnProto { - assert(tree.nodes.items(.tag)[node] == .fn_proto_one); - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.lhs, Node.FnProtoOne); - buffer[0] = extra.param; - const params = if (extra.param == 0) buffer[0..0] else buffer[0..1]; - return tree.fullFnProto(.{ - .proto_node = node, - .fn_token = tree.nodes.items(.main_token)[node], - .return_type = data.rhs, - .params = params, - .align_expr = extra.align_expr, - .section_expr = extra.section_expr, - .callconv_expr = extra.callconv_expr, - }); - } - - pub fn fnProto(tree: Tree, node: Node.Index) full.FnProto { - assert(tree.nodes.items(.tag)[node] == .fn_proto); - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.lhs, Node.FnProto); - const params = tree.extra_data[extra.params_start..extra.params_end]; - return tree.fullFnProto(.{ - .proto_node = node, - .fn_token = tree.nodes.items(.main_token)[node], - .return_type = data.rhs, - .params = params, - .align_expr = extra.align_expr, - .section_expr = extra.section_expr, - .callconv_expr = extra.callconv_expr, - }); - } - - pub fn structInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.StructInit { - assert(tree.nodes.items(.tag)[node] == .struct_init_one or - tree.nodes.items(.tag)[node] == .struct_init_one_comma); - const data = tree.nodes.items(.data)[node]; - buffer[0] = data.rhs; - const fields = if (data.rhs == 0) buffer[0..0] else buffer[0..1]; - return tree.fullStructInit(.{ - .lbrace = tree.nodes.items(.main_token)[node], - .fields = fields, - .type_expr = data.lhs, - }); - } - - pub fn structInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.StructInit { - assert(tree.nodes.items(.tag)[node] == .struct_init_dot_two or - tree.nodes.items(.tag)[node] == .struct_init_dot_two_comma); - const data = tree.nodes.items(.data)[node]; - buffer.* = .{ data.lhs, data.rhs }; - const fields = if (data.rhs != 0) - buffer[0..2] - else if (data.lhs != 0) - buffer[0..1] - else - buffer[0..0]; - return tree.fullStructInit(.{ - .lbrace = tree.nodes.items(.main_token)[node], - .fields = fields, - .type_expr = 0, - }); - } - - pub fn structInitDot(tree: Tree, node: Node.Index) full.StructInit { - assert(tree.nodes.items(.tag)[node] == .struct_init_dot or - tree.nodes.items(.tag)[node] == .struct_init_dot_comma); - const data = tree.nodes.items(.data)[node]; - return tree.fullStructInit(.{ - .lbrace = tree.nodes.items(.main_token)[node], - .fields = tree.extra_data[data.lhs..data.rhs], - .type_expr = 0, - }); - } - - pub fn structInit(tree: Tree, node: Node.Index) full.StructInit { - assert(tree.nodes.items(.tag)[node] == .struct_init or - tree.nodes.items(.tag)[node] == .struct_init_comma); - const data = tree.nodes.items(.data)[node]; - const fields_range = tree.extraData(data.rhs, Node.SubRange); - return tree.fullStructInit(.{ - .lbrace = tree.nodes.items(.main_token)[node], - .fields = tree.extra_data[fields_range.start..fields_range.end], - .type_expr = data.lhs, - }); - } - - pub fn arrayInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.ArrayInit { - assert(tree.nodes.items(.tag)[node] == .array_init_one or - tree.nodes.items(.tag)[node] == .array_init_one_comma); - const data = tree.nodes.items(.data)[node]; - buffer[0] = data.rhs; - const elements = if (data.rhs == 0) buffer[0..0] else buffer[0..1]; - return .{ - .ast = .{ - .lbrace = tree.nodes.items(.main_token)[node], - .elements = elements, - .type_expr = data.lhs, - }, - }; - } - - pub fn arrayInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.ArrayInit { - assert(tree.nodes.items(.tag)[node] == .array_init_dot_two or - tree.nodes.items(.tag)[node] == .array_init_dot_two_comma); - const data = tree.nodes.items(.data)[node]; - buffer.* = .{ data.lhs, data.rhs }; - const elements = if (data.rhs != 0) - buffer[0..2] - else if (data.lhs != 0) - buffer[0..1] - else - buffer[0..0]; - return .{ - .ast = .{ - .lbrace = tree.nodes.items(.main_token)[node], - .elements = elements, - .type_expr = 0, - }, - }; - } - - pub fn arrayInitDot(tree: Tree, node: Node.Index) full.ArrayInit { - assert(tree.nodes.items(.tag)[node] == .array_init_dot or - tree.nodes.items(.tag)[node] == .array_init_dot_comma); - const data = tree.nodes.items(.data)[node]; - return .{ - .ast = .{ - .lbrace = tree.nodes.items(.main_token)[node], - .elements = tree.extra_data[data.lhs..data.rhs], - .type_expr = 0, - }, - }; - } - - pub fn arrayInit(tree: Tree, node: Node.Index) full.ArrayInit { - assert(tree.nodes.items(.tag)[node] == .array_init or - tree.nodes.items(.tag)[node] == .array_init_comma); - const data = tree.nodes.items(.data)[node]; - const elem_range = tree.extraData(data.rhs, Node.SubRange); - return .{ - .ast = .{ - .lbrace = tree.nodes.items(.main_token)[node], - .elements = tree.extra_data[elem_range.start..elem_range.end], - .type_expr = data.lhs, - }, - }; - } - - pub fn arrayType(tree: Tree, node: Node.Index) full.ArrayType { - assert(tree.nodes.items(.tag)[node] == .array_type); - const data = tree.nodes.items(.data)[node]; - return .{ - .ast = .{ - .lbracket = tree.nodes.items(.main_token)[node], - .elem_count = data.lhs, - .sentinel = 0, - .elem_type = data.rhs, - }, - }; - } - - pub fn arrayTypeSentinel(tree: Tree, node: Node.Index) full.ArrayType { - assert(tree.nodes.items(.tag)[node] == .array_type_sentinel); - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.rhs, Node.ArrayTypeSentinel); - assert(extra.sentinel != 0); - return .{ - .ast = .{ - .lbracket = tree.nodes.items(.main_token)[node], - .elem_count = data.lhs, - .sentinel = extra.sentinel, - .elem_type = extra.elem_type, - }, - }; - } - - pub fn ptrTypeAligned(tree: Tree, node: Node.Index) full.PtrType { - assert(tree.nodes.items(.tag)[node] == .ptr_type_aligned); - const data = tree.nodes.items(.data)[node]; - return tree.fullPtrType(.{ - .main_token = tree.nodes.items(.main_token)[node], - .align_node = data.lhs, - .sentinel = 0, - .bit_range_start = 0, - .bit_range_end = 0, - .child_type = data.rhs, - }); - } - - pub fn ptrTypeSentinel(tree: Tree, node: Node.Index) full.PtrType { - assert(tree.nodes.items(.tag)[node] == .ptr_type_sentinel); - const data = tree.nodes.items(.data)[node]; - return tree.fullPtrType(.{ - .main_token = tree.nodes.items(.main_token)[node], - .align_node = 0, - .sentinel = data.lhs, - .bit_range_start = 0, - .bit_range_end = 0, - .child_type = data.rhs, - }); - } - - pub fn ptrType(tree: Tree, node: Node.Index) full.PtrType { - assert(tree.nodes.items(.tag)[node] == .ptr_type); - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.lhs, Node.PtrType); - return tree.fullPtrType(.{ - .main_token = tree.nodes.items(.main_token)[node], - .align_node = extra.align_node, - .sentinel = extra.sentinel, - .bit_range_start = 0, - .bit_range_end = 0, - .child_type = data.rhs, - }); - } - - pub fn ptrTypeBitRange(tree: Tree, node: Node.Index) full.PtrType { - assert(tree.nodes.items(.tag)[node] == .ptr_type_bit_range); - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.lhs, Node.PtrTypeBitRange); - return tree.fullPtrType(.{ - .main_token = tree.nodes.items(.main_token)[node], - .align_node = extra.align_node, - .sentinel = extra.sentinel, - .bit_range_start = extra.bit_range_start, - .bit_range_end = extra.bit_range_end, - .child_type = data.rhs, - }); - } - - pub fn sliceOpen(tree: Tree, node: Node.Index) full.Slice { - assert(tree.nodes.items(.tag)[node] == .slice_open); - const data = tree.nodes.items(.data)[node]; - return .{ - .ast = .{ - .sliced = data.lhs, - .lbracket = tree.nodes.items(.main_token)[node], - .start = data.rhs, - .end = 0, - .sentinel = 0, - }, - }; - } - - pub fn slice(tree: Tree, node: Node.Index) full.Slice { - assert(tree.nodes.items(.tag)[node] == .slice); - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.rhs, Node.Slice); - return .{ - .ast = .{ - .sliced = data.lhs, - .lbracket = tree.nodes.items(.main_token)[node], - .start = extra.start, - .end = extra.end, - .sentinel = 0, - }, - }; - } - - pub fn sliceSentinel(tree: Tree, node: Node.Index) full.Slice { - assert(tree.nodes.items(.tag)[node] == .slice_sentinel); - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.rhs, Node.SliceSentinel); - return .{ - .ast = .{ - .sliced = data.lhs, - .lbracket = tree.nodes.items(.main_token)[node], - .start = extra.start, - .end = extra.end, - .sentinel = extra.sentinel, - }, - }; - } - - pub fn containerDeclTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.ContainerDecl { - assert(tree.nodes.items(.tag)[node] == .container_decl_two or - tree.nodes.items(.tag)[node] == .container_decl_two_trailing); - const data = tree.nodes.items(.data)[node]; - buffer.* = .{ data.lhs, data.rhs }; - const members = if (data.rhs != 0) - buffer[0..2] - else if (data.lhs != 0) - buffer[0..1] - else - buffer[0..0]; - return tree.fullContainerDecl(.{ - .main_token = tree.nodes.items(.main_token)[node], - .enum_token = null, - .members = members, - .arg = 0, - }); - } - - pub fn containerDecl(tree: Tree, node: Node.Index) full.ContainerDecl { - assert(tree.nodes.items(.tag)[node] == .container_decl or - tree.nodes.items(.tag)[node] == .container_decl_trailing); - const data = tree.nodes.items(.data)[node]; - return tree.fullContainerDecl(.{ - .main_token = tree.nodes.items(.main_token)[node], - .enum_token = null, - .members = tree.extra_data[data.lhs..data.rhs], - .arg = 0, - }); - } - - pub fn containerDeclArg(tree: Tree, node: Node.Index) full.ContainerDecl { - assert(tree.nodes.items(.tag)[node] == .container_decl_arg or - tree.nodes.items(.tag)[node] == .container_decl_arg_trailing); - const data = tree.nodes.items(.data)[node]; - const members_range = tree.extraData(data.rhs, Node.SubRange); - return tree.fullContainerDecl(.{ - .main_token = tree.nodes.items(.main_token)[node], - .enum_token = null, - .members = tree.extra_data[members_range.start..members_range.end], - .arg = data.lhs, - }); - } - - pub fn taggedUnionTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) full.ContainerDecl { - assert(tree.nodes.items(.tag)[node] == .tagged_union_two or - tree.nodes.items(.tag)[node] == .tagged_union_two_trailing); - const data = tree.nodes.items(.data)[node]; - buffer.* = .{ data.lhs, data.rhs }; - const members = if (data.rhs != 0) - buffer[0..2] - else if (data.lhs != 0) - buffer[0..1] - else - buffer[0..0]; - const main_token = tree.nodes.items(.main_token)[node]; - return tree.fullContainerDecl(.{ - .main_token = main_token, - .enum_token = main_token + 2, // union lparen enum - .members = members, - .arg = 0, - }); - } - - pub fn taggedUnion(tree: Tree, node: Node.Index) full.ContainerDecl { - assert(tree.nodes.items(.tag)[node] == .tagged_union or - tree.nodes.items(.tag)[node] == .tagged_union_trailing); - const data = tree.nodes.items(.data)[node]; - const main_token = tree.nodes.items(.main_token)[node]; - return tree.fullContainerDecl(.{ - .main_token = main_token, - .enum_token = main_token + 2, // union lparen enum - .members = tree.extra_data[data.lhs..data.rhs], - .arg = 0, - }); - } - - pub fn taggedUnionEnumTag(tree: Tree, node: Node.Index) full.ContainerDecl { - assert(tree.nodes.items(.tag)[node] == .tagged_union_enum_tag or - tree.nodes.items(.tag)[node] == .tagged_union_enum_tag_trailing); - const data = tree.nodes.items(.data)[node]; - const members_range = tree.extraData(data.rhs, Node.SubRange); - const main_token = tree.nodes.items(.main_token)[node]; - return tree.fullContainerDecl(.{ - .main_token = main_token, - .enum_token = main_token + 2, // union lparen enum - .members = tree.extra_data[members_range.start..members_range.end], - .arg = data.lhs, - }); - } - - pub fn switchCaseOne(tree: Tree, node: Node.Index) full.SwitchCase { - const data = &tree.nodes.items(.data)[node]; - const values: *[1]Node.Index = &data.lhs; - return tree.fullSwitchCase(.{ - .values = if (data.lhs == 0) values[0..0] else values[0..1], - .arrow_token = tree.nodes.items(.main_token)[node], - .target_expr = data.rhs, - }); - } - - pub fn switchCase(tree: Tree, node: Node.Index) full.SwitchCase { - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.lhs, Node.SubRange); - return tree.fullSwitchCase(.{ - .values = tree.extra_data[extra.start..extra.end], - .arrow_token = tree.nodes.items(.main_token)[node], - .target_expr = data.rhs, - }); - } - - pub fn asmSimple(tree: Tree, node: Node.Index) full.Asm { - const data = tree.nodes.items(.data)[node]; - return tree.fullAsm(.{ - .asm_token = tree.nodes.items(.main_token)[node], - .template = data.lhs, - .items = &.{}, - .rparen = data.rhs, - }); - } - - pub fn asmFull(tree: Tree, node: Node.Index) full.Asm { - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.rhs, Node.Asm); - return tree.fullAsm(.{ - .asm_token = tree.nodes.items(.main_token)[node], - .template = data.lhs, - .items = tree.extra_data[extra.items_start..extra.items_end], - .rparen = extra.rparen, - }); - } - - pub fn whileSimple(tree: Tree, node: Node.Index) full.While { - const data = tree.nodes.items(.data)[node]; - return tree.fullWhile(.{ - .while_token = tree.nodes.items(.main_token)[node], - .cond_expr = data.lhs, - .cont_expr = 0, - .then_expr = data.rhs, - .else_expr = 0, - }); - } - - pub fn whileCont(tree: Tree, node: Node.Index) full.While { - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.rhs, Node.WhileCont); - return tree.fullWhile(.{ - .while_token = tree.nodes.items(.main_token)[node], - .cond_expr = data.lhs, - .cont_expr = extra.cont_expr, - .then_expr = extra.then_expr, - .else_expr = 0, - }); - } - - pub fn whileFull(tree: Tree, node: Node.Index) full.While { - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.rhs, Node.While); - return tree.fullWhile(.{ - .while_token = tree.nodes.items(.main_token)[node], - .cond_expr = data.lhs, - .cont_expr = extra.cont_expr, - .then_expr = extra.then_expr, - .else_expr = extra.else_expr, - }); - } - - pub fn forSimple(tree: Tree, node: Node.Index) full.While { - const data = tree.nodes.items(.data)[node]; - return tree.fullWhile(.{ - .while_token = tree.nodes.items(.main_token)[node], - .cond_expr = data.lhs, - .cont_expr = 0, - .then_expr = data.rhs, - .else_expr = 0, - }); - } - - pub fn forFull(tree: Tree, node: Node.Index) full.While { - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.rhs, Node.If); - return tree.fullWhile(.{ - .while_token = tree.nodes.items(.main_token)[node], - .cond_expr = data.lhs, - .cont_expr = 0, - .then_expr = extra.then_expr, - .else_expr = extra.else_expr, - }); - } - - pub fn callOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) full.Call { - const data = tree.nodes.items(.data)[node]; - buffer.* = .{data.rhs}; - const params = if (data.rhs != 0) buffer[0..1] else buffer[0..0]; - return tree.fullCall(.{ - .lparen = tree.nodes.items(.main_token)[node], - .fn_expr = data.lhs, - .params = params, - }); - } - - pub fn callFull(tree: Tree, node: Node.Index) full.Call { - const data = tree.nodes.items(.data)[node]; - const extra = tree.extraData(data.rhs, Node.SubRange); - return tree.fullCall(.{ - .lparen = tree.nodes.items(.main_token)[node], - .fn_expr = data.lhs, - .params = tree.extra_data[extra.start..extra.end], - }); - } - - fn fullVarDecl(tree: Tree, info: full.VarDecl.Ast) full.VarDecl { - const token_tags = tree.tokens.items(.tag); - var result: full.VarDecl = .{ - .ast = info, - .visib_token = null, - .extern_export_token = null, - .lib_name = null, - .threadlocal_token = null, - .comptime_token = null, - }; - var i = info.mut_token; - while (i > 0) { - i -= 1; - switch (token_tags[i]) { - .keyword_extern, .keyword_export => result.extern_export_token = i, - .keyword_comptime => result.comptime_token = i, - .keyword_pub => result.visib_token = i, - .keyword_threadlocal => result.threadlocal_token = i, - .string_literal => result.lib_name = i, - else => break, - } - } - return result; - } - - fn fullIf(tree: Tree, info: full.If.Ast) full.If { - const token_tags = tree.tokens.items(.tag); - var result: full.If = .{ - .ast = info, - .payload_token = null, - .error_token = null, - .else_token = undefined, - }; - // if (cond_expr) |x| - // ^ ^ - const payload_pipe = tree.lastToken(info.cond_expr) + 2; - if (token_tags[payload_pipe] == .pipe) { - result.payload_token = payload_pipe + 1; - } - if (info.else_expr != 0) { - // then_expr else |x| - // ^ ^ - result.else_token = tree.lastToken(info.then_expr) + 1; - if (token_tags[result.else_token + 1] == .pipe) { - result.error_token = result.else_token + 2; - } - } - return result; - } - - fn fullContainerField(tree: Tree, info: full.ContainerField.Ast) full.ContainerField { - const token_tags = tree.tokens.items(.tag); - var result: full.ContainerField = .{ - .ast = info, - .comptime_token = null, - }; - // comptime name: type = init, - // ^ - if (info.name_token > 0 and token_tags[info.name_token - 1] == .keyword_comptime) { - result.comptime_token = info.name_token - 1; - } - return result; - } - - fn fullFnProto(tree: Tree, info: full.FnProto.Ast) full.FnProto { - const token_tags = tree.tokens.items(.tag); - var result: full.FnProto = .{ - .ast = info, - .visib_token = null, - .extern_export_inline_token = null, - .lib_name = null, - .name_token = null, - .lparen = undefined, - }; - var i = info.fn_token; - while (i > 0) { - i -= 1; - switch (token_tags[i]) { - .keyword_extern, - .keyword_export, - .keyword_inline, - .keyword_noinline, - => result.extern_export_inline_token = i, - .keyword_pub => result.visib_token = i, - .string_literal => result.lib_name = i, - else => break, - } - } - const after_fn_token = info.fn_token + 1; - if (token_tags[after_fn_token] == .identifier) { - result.name_token = after_fn_token; - result.lparen = after_fn_token + 1; - } else { - result.lparen = after_fn_token; - } - assert(token_tags[result.lparen] == .l_paren); - - return result; - } - - fn fullStructInit(tree: Tree, info: full.StructInit.Ast) full.StructInit { - _ = tree; - var result: full.StructInit = .{ - .ast = info, - }; - return result; - } - - fn fullPtrType(tree: Tree, info: full.PtrType.Ast) full.PtrType { - const token_tags = tree.tokens.items(.tag); - // TODO: looks like stage1 isn't quite smart enough to handle enum - // literals in some places here - const Size = std.builtin.TypeInfo.Pointer.Size; - const size: Size = switch (token_tags[info.main_token]) { - .asterisk, - .asterisk_asterisk, - => switch (token_tags[info.main_token + 1]) { - .r_bracket, .colon => .Many, - .identifier => if (token_tags[info.main_token - 1] == .l_bracket) Size.C else .One, - else => .One, - }, - .l_bracket => Size.Slice, - else => unreachable, - }; - var result: full.PtrType = .{ - .size = size, - .allowzero_token = null, - .const_token = null, - .volatile_token = null, - .ast = info, - }; - // We need to be careful that we don't iterate over any sub-expressions - // here while looking for modifiers as that could result in false - // positives. Therefore, start after a sentinel if there is one and - // skip over any align node and bit range nodes. - var i = if (info.sentinel != 0) tree.lastToken(info.sentinel) + 1 else info.main_token; - const end = tree.firstToken(info.child_type); - while (i < end) : (i += 1) { - switch (token_tags[i]) { - .keyword_allowzero => result.allowzero_token = i, - .keyword_const => result.const_token = i, - .keyword_volatile => result.volatile_token = i, - .keyword_align => { - assert(info.align_node != 0); - if (info.bit_range_end != 0) { - assert(info.bit_range_start != 0); - i = tree.lastToken(info.bit_range_end) + 1; - } else { - i = tree.lastToken(info.align_node) + 1; - } - }, - else => {}, - } - } - return result; - } - - fn fullContainerDecl(tree: Tree, info: full.ContainerDecl.Ast) full.ContainerDecl { - const token_tags = tree.tokens.items(.tag); - var result: full.ContainerDecl = .{ - .ast = info, - .layout_token = null, - }; - switch (token_tags[info.main_token - 1]) { - .keyword_extern, .keyword_packed => result.layout_token = info.main_token - 1, - else => {}, - } - return result; - } - - fn fullSwitchCase(tree: Tree, info: full.SwitchCase.Ast) full.SwitchCase { - const token_tags = tree.tokens.items(.tag); - var result: full.SwitchCase = .{ - .ast = info, - .payload_token = null, - }; - if (token_tags[info.arrow_token + 1] == .pipe) { - result.payload_token = info.arrow_token + 2; - } - return result; - } - - fn fullAsm(tree: Tree, info: full.Asm.Ast) full.Asm { - const token_tags = tree.tokens.items(.tag); - const node_tags = tree.nodes.items(.tag); - var result: full.Asm = .{ - .ast = info, - .volatile_token = null, - .inputs = &.{}, - .outputs = &.{}, - .first_clobber = null, - }; - if (token_tags[info.asm_token + 1] == .keyword_volatile) { - result.volatile_token = info.asm_token + 1; - } - const outputs_end: usize = for (info.items) |item, i| { - switch (node_tags[item]) { - .asm_output => continue, - else => break i, - } - } else info.items.len; - - result.outputs = info.items[0..outputs_end]; - result.inputs = info.items[outputs_end..]; - - if (info.items.len == 0) { - // asm ("foo" ::: "a", "b"); - const template_token = tree.lastToken(info.template); - if (token_tags[template_token + 1] == .colon and - token_tags[template_token + 2] == .colon and - token_tags[template_token + 3] == .colon and - token_tags[template_token + 4] == .string_literal) - { - result.first_clobber = template_token + 4; - } - } else if (result.inputs.len != 0) { - // asm ("foo" :: [_] "" (y) : "a", "b"); - const last_input = result.inputs[result.inputs.len - 1]; - const rparen = tree.lastToken(last_input); - var i = rparen + 1; - // Allow a (useless) comma right after the closing parenthesis. - if (token_tags[i] == .comma) i += 1; - if (token_tags[i] == .colon and - token_tags[i + 1] == .string_literal) - { - result.first_clobber = i + 1; - } - } else { - // asm ("foo" : [_] "" (x) :: "a", "b"); - const last_output = result.outputs[result.outputs.len - 1]; - const rparen = tree.lastToken(last_output); - var i = rparen + 1; - // Allow a (useless) comma right after the closing parenthesis. - if (token_tags[i] == .comma) i += 1; - if (token_tags[i] == .colon and - token_tags[i + 1] == .colon and - token_tags[i + 2] == .string_literal) - { - result.first_clobber = i + 2; - } - } - - return result; - } - - fn fullWhile(tree: Tree, info: full.While.Ast) full.While { - const token_tags = tree.tokens.items(.tag); - var result: full.While = .{ - .ast = info, - .inline_token = null, - .label_token = null, - .payload_token = null, - .else_token = undefined, - .error_token = null, - }; - var tok_i = info.while_token - 1; - if (token_tags[tok_i] == .keyword_inline) { - result.inline_token = tok_i; - tok_i -= 1; - } - if (token_tags[tok_i] == .colon and - token_tags[tok_i - 1] == .identifier) - { - result.label_token = tok_i - 1; - } - const last_cond_token = tree.lastToken(info.cond_expr); - if (token_tags[last_cond_token + 2] == .pipe) { - result.payload_token = last_cond_token + 3; - } - if (info.else_expr != 0) { - // then_expr else |x| - // ^ ^ - result.else_token = tree.lastToken(info.then_expr) + 1; - if (token_tags[result.else_token + 1] == .pipe) { - result.error_token = result.else_token + 2; - } - } - return result; - } - - fn fullCall(tree: Tree, info: full.Call.Ast) full.Call { - const token_tags = tree.tokens.items(.tag); - var result: full.Call = .{ - .ast = info, - .async_token = null, - }; - const maybe_async_token = tree.firstToken(info.fn_expr) - 1; - if (token_tags[maybe_async_token] == .keyword_async) { - result.async_token = maybe_async_token; - } - return result; - } -}; - -/// Fully assembled AST node information. -pub const full = struct { - pub const VarDecl = struct { - visib_token: ?TokenIndex, - extern_export_token: ?TokenIndex, - lib_name: ?TokenIndex, - threadlocal_token: ?TokenIndex, - comptime_token: ?TokenIndex, - ast: Ast, - - pub const Ast = struct { - mut_token: TokenIndex, - type_node: Node.Index, - align_node: Node.Index, - section_node: Node.Index, - init_node: Node.Index, - }; - }; - - pub const If = struct { - /// Points to the first token after the `|`. Will either be an identifier or - /// a `*` (with an identifier immediately after it). - payload_token: ?TokenIndex, - /// Points to the identifier after the `|`. - error_token: ?TokenIndex, - /// Populated only if else_expr != 0. - else_token: TokenIndex, - ast: Ast, - - pub const Ast = struct { - if_token: TokenIndex, - cond_expr: Node.Index, - then_expr: Node.Index, - else_expr: Node.Index, - }; - }; - - pub const While = struct { - ast: Ast, - inline_token: ?TokenIndex, - label_token: ?TokenIndex, - payload_token: ?TokenIndex, - error_token: ?TokenIndex, - /// Populated only if else_expr != 0. - else_token: TokenIndex, - - pub const Ast = struct { - while_token: TokenIndex, - cond_expr: Node.Index, - cont_expr: Node.Index, - then_expr: Node.Index, - else_expr: Node.Index, - }; - }; - - pub const ContainerField = struct { - comptime_token: ?TokenIndex, - ast: Ast, - - pub const Ast = struct { - name_token: TokenIndex, - type_expr: Node.Index, - value_expr: Node.Index, - align_expr: Node.Index, - }; - }; - - pub const FnProto = struct { - visib_token: ?TokenIndex, - extern_export_inline_token: ?TokenIndex, - lib_name: ?TokenIndex, - name_token: ?TokenIndex, - lparen: TokenIndex, - ast: Ast, - - pub const Ast = struct { - proto_node: Node.Index, - fn_token: TokenIndex, - return_type: Node.Index, - params: []const Node.Index, - align_expr: Node.Index, - section_expr: Node.Index, - callconv_expr: Node.Index, - }; - - pub const Param = struct { - first_doc_comment: ?TokenIndex, - name_token: ?TokenIndex, - comptime_noalias: ?TokenIndex, - anytype_ellipsis3: ?TokenIndex, - type_expr: Node.Index, - }; - - /// Abstracts over the fact that anytype and ... are not included - /// in the params slice, since they are simple identifiers and - /// not sub-expressions. - pub const Iterator = struct { - tree: *const Tree, - fn_proto: *const FnProto, - param_i: usize, - tok_i: TokenIndex, - tok_flag: bool, - - pub fn next(it: *Iterator) ?Param { - const token_tags = it.tree.tokens.items(.tag); - while (true) { - var first_doc_comment: ?TokenIndex = null; - var comptime_noalias: ?TokenIndex = null; - var name_token: ?TokenIndex = null; - if (!it.tok_flag) { - if (it.param_i >= it.fn_proto.ast.params.len) { - return null; - } - const param_type = it.fn_proto.ast.params[it.param_i]; - var tok_i = it.tree.firstToken(param_type) - 1; - while (true) : (tok_i -= 1) switch (token_tags[tok_i]) { - .colon => continue, - .identifier => name_token = tok_i, - .doc_comment => first_doc_comment = tok_i, - .keyword_comptime, .keyword_noalias => comptime_noalias = tok_i, - else => break, - }; - it.param_i += 1; - it.tok_i = it.tree.lastToken(param_type) + 1; - // Look for anytype and ... params afterwards. - if (token_tags[it.tok_i] == .comma) { - it.tok_i += 1; - } - it.tok_flag = true; - return Param{ - .first_doc_comment = first_doc_comment, - .comptime_noalias = comptime_noalias, - .name_token = name_token, - .anytype_ellipsis3 = null, - .type_expr = param_type, - }; - } - if (token_tags[it.tok_i] == .comma) { - it.tok_i += 1; - } - if (token_tags[it.tok_i] == .r_paren) { - return null; - } - if (token_tags[it.tok_i] == .doc_comment) { - first_doc_comment = it.tok_i; - while (token_tags[it.tok_i] == .doc_comment) { - it.tok_i += 1; - } - } - switch (token_tags[it.tok_i]) { - .ellipsis3 => { - it.tok_flag = false; // Next iteration should return null. - return Param{ - .first_doc_comment = first_doc_comment, - .comptime_noalias = null, - .name_token = null, - .anytype_ellipsis3 = it.tok_i, - .type_expr = 0, - }; - }, - .keyword_noalias, .keyword_comptime => { - comptime_noalias = it.tok_i; - it.tok_i += 1; - }, - else => {}, - } - if (token_tags[it.tok_i] == .identifier and - token_tags[it.tok_i + 1] == .colon) - { - name_token = it.tok_i; - it.tok_i += 2; - } - if (token_tags[it.tok_i] == .keyword_anytype) { - it.tok_i += 1; - return Param{ - .first_doc_comment = first_doc_comment, - .comptime_noalias = comptime_noalias, - .name_token = name_token, - .anytype_ellipsis3 = it.tok_i - 1, - .type_expr = 0, - }; - } - it.tok_flag = false; - } - } - }; - - pub fn iterate(fn_proto: FnProto, tree: Tree) Iterator { - return .{ - .tree = &tree, - .fn_proto = &fn_proto, - .param_i = 0, - .tok_i = fn_proto.lparen + 1, - .tok_flag = true, - }; - } - }; - - pub const StructInit = struct { - ast: Ast, - - pub const Ast = struct { - lbrace: TokenIndex, - fields: []const Node.Index, - type_expr: Node.Index, - }; - }; - - pub const ArrayInit = struct { - ast: Ast, - - pub const Ast = struct { - lbrace: TokenIndex, - elements: []const Node.Index, - type_expr: Node.Index, - }; - }; - - pub const ArrayType = struct { - ast: Ast, - - pub const Ast = struct { - lbracket: TokenIndex, - elem_count: Node.Index, - sentinel: Node.Index, - elem_type: Node.Index, - }; - }; - - pub const PtrType = struct { - size: std.builtin.TypeInfo.Pointer.Size, - allowzero_token: ?TokenIndex, - const_token: ?TokenIndex, - volatile_token: ?TokenIndex, - ast: Ast, - - pub const Ast = struct { - main_token: TokenIndex, - align_node: Node.Index, - sentinel: Node.Index, - bit_range_start: Node.Index, - bit_range_end: Node.Index, - child_type: Node.Index, - }; - }; - - pub const Slice = struct { - ast: Ast, - - pub const Ast = struct { - sliced: Node.Index, - lbracket: TokenIndex, - start: Node.Index, - end: Node.Index, - sentinel: Node.Index, - }; - }; - - pub const ContainerDecl = struct { - layout_token: ?TokenIndex, - ast: Ast, - - pub const Ast = struct { - main_token: TokenIndex, - /// Populated when main_token is Keyword_union. - enum_token: ?TokenIndex, - members: []const Node.Index, - arg: Node.Index, - }; - }; - - pub const SwitchCase = struct { - /// Points to the first token after the `|`. Will either be an identifier or - /// a `*` (with an identifier immediately after it). - payload_token: ?TokenIndex, - ast: Ast, - - pub const Ast = struct { - /// If empty, this is an else case - values: []const Node.Index, - arrow_token: TokenIndex, - target_expr: Node.Index, - }; - }; - - pub const Asm = struct { - ast: Ast, - volatile_token: ?TokenIndex, - first_clobber: ?TokenIndex, - outputs: []const Node.Index, - inputs: []const Node.Index, - - pub const Ast = struct { - asm_token: TokenIndex, - template: Node.Index, - items: []const Node.Index, - rparen: TokenIndex, - }; - }; - - pub const Call = struct { - ast: Ast, - async_token: ?TokenIndex, - - pub const Ast = struct { - lparen: TokenIndex, - fn_expr: Node.Index, - params: []const Node.Index, - }; - }; -}; - -pub const Error = struct { - tag: Tag, - token: TokenIndex, - extra: union { - none: void, - expected_tag: Token.Tag, - } = .{ .none = {} }, - - pub const Tag = enum { - asterisk_after_ptr_deref, - decl_between_fields, - expected_block, - expected_block_or_assignment, - expected_block_or_expr, - expected_block_or_field, - expected_container_members, - expected_expr, - expected_expr_or_assignment, - expected_fn, - expected_inlinable, - expected_labelable, - expected_param_list, - expected_prefix_expr, - expected_primary_type_expr, - expected_pub_item, - expected_return_type, - expected_semi_or_else, - expected_semi_or_lbrace, - expected_statement, - expected_string_literal, - expected_suffix_op, - expected_type_expr, - expected_var_decl, - expected_var_decl_or_fn, - expected_loop_payload, - expected_container, - extra_align_qualifier, - extra_allowzero_qualifier, - extra_const_qualifier, - extra_volatile_qualifier, - ptr_mod_on_array_child_type, - invalid_bit_range, - invalid_token, - same_line_doc_comment, - unattached_doc_comment, - varargs_nonfinal, - - /// `expected_tag` is populated. - expected_token, - }; -}; - -pub const Node = struct { - tag: Tag, - main_token: TokenIndex, - data: Data, - - pub const Index = u32; - - comptime { - // Goal is to keep this under one byte for efficiency. - assert(@sizeOf(Tag) == 1); - } - - /// Note: The FooComma/FooSemicolon variants exist to ease the implementation of - /// Tree.lastToken() - pub const Tag = enum { - /// sub_list[lhs...rhs] - root, - /// `usingnamespace lhs;`. rhs unused. main_token is `usingnamespace`. - @"usingnamespace", - /// lhs is test name token (must be string literal), if any. - /// rhs is the body node. - test_decl, - /// lhs is the index into extra_data. - /// rhs is the initialization expression, if any. - /// main_token is `var` or `const`. - global_var_decl, - /// `var a: x align(y) = rhs` - /// lhs is the index into extra_data. - /// main_token is `var` or `const`. - local_var_decl, - /// `var a: lhs = rhs`. lhs and rhs may be unused. - /// Can be local or global. - /// main_token is `var` or `const`. - simple_var_decl, - /// `var a align(lhs) = rhs`. lhs and rhs may be unused. - /// Can be local or global. - /// main_token is `var` or `const`. - aligned_var_decl, - /// lhs is the identifier token payload if any, - /// rhs is the deferred expression. - @"errdefer", - /// lhs is unused. - /// rhs is the deferred expression. - @"defer", - /// lhs catch rhs - /// lhs catch |err| rhs - /// main_token is the `catch` keyword. - /// payload is determined by looking at the next token after the `catch` keyword. - @"catch", - /// `lhs.a`. main_token is the dot. rhs is the identifier token index. - field_access, - /// `lhs.?`. main_token is the dot. rhs is the `?` token index. - unwrap_optional, - /// `lhs == rhs`. main_token is op. - equal_equal, - /// `lhs != rhs`. main_token is op. - bang_equal, - /// `lhs < rhs`. main_token is op. - less_than, - /// `lhs > rhs`. main_token is op. - greater_than, - /// `lhs <= rhs`. main_token is op. - less_or_equal, - /// `lhs >= rhs`. main_token is op. - greater_or_equal, - /// `lhs *= rhs`. main_token is op. - assign_mul, - /// `lhs /= rhs`. main_token is op. - assign_div, - /// `lhs *= rhs`. main_token is op. - assign_mod, - /// `lhs += rhs`. main_token is op. - assign_add, - /// `lhs -= rhs`. main_token is op. - assign_sub, - /// `lhs <<= rhs`. main_token is op. - assign_bit_shift_left, - /// `lhs >>= rhs`. main_token is op. - assign_bit_shift_right, - /// `lhs &= rhs`. main_token is op. - assign_bit_and, - /// `lhs ^= rhs`. main_token is op. - assign_bit_xor, - /// `lhs |= rhs`. main_token is op. - assign_bit_or, - /// `lhs *%= rhs`. main_token is op. - assign_mul_wrap, - /// `lhs +%= rhs`. main_token is op. - assign_add_wrap, - /// `lhs -%= rhs`. main_token is op. - assign_sub_wrap, - /// `lhs = rhs`. main_token is op. - assign, - /// `lhs || rhs`. main_token is the `||`. - merge_error_sets, - /// `lhs * rhs`. main_token is the `*`. - mul, - /// `lhs / rhs`. main_token is the `/`. - div, - /// `lhs % rhs`. main_token is the `%`. - mod, - /// `lhs ** rhs`. main_token is the `**`. - array_mult, - /// `lhs *% rhs`. main_token is the `*%`. - mul_wrap, - /// `lhs + rhs`. main_token is the `+`. - add, - /// `lhs - rhs`. main_token is the `-`. - sub, - /// `lhs ++ rhs`. main_token is the `++`. - array_cat, - /// `lhs +% rhs`. main_token is the `+%`. - add_wrap, - /// `lhs -% rhs`. main_token is the `-%`. - sub_wrap, - /// `lhs << rhs`. main_token is the `<<`. - bit_shift_left, - /// `lhs >> rhs`. main_token is the `>>`. - bit_shift_right, - /// `lhs & rhs`. main_token is the `&`. - bit_and, - /// `lhs ^ rhs`. main_token is the `^`. - bit_xor, - /// `lhs | rhs`. main_token is the `|`. - bit_or, - /// `lhs orelse rhs`. main_token is the `orelse`. - @"orelse", - /// `lhs and rhs`. main_token is the `and`. - bool_and, - /// `lhs or rhs`. main_token is the `or`. - bool_or, - /// `op lhs`. rhs unused. main_token is op. - bool_not, - /// `op lhs`. rhs unused. main_token is op. - negation, - /// `op lhs`. rhs unused. main_token is op. - bit_not, - /// `op lhs`. rhs unused. main_token is op. - negation_wrap, - /// `op lhs`. rhs unused. main_token is op. - address_of, - /// `op lhs`. rhs unused. main_token is op. - @"try", - /// `op lhs`. rhs unused. main_token is op. - @"await", - /// `?lhs`. rhs unused. main_token is the `?`. - optional_type, - /// `[lhs]rhs`. - array_type, - /// `[lhs:a]b`. `ArrayTypeSentinel[rhs]`. - array_type_sentinel, - /// `[*]align(lhs) rhs`. lhs can be omitted. - /// `*align(lhs) rhs`. lhs can be omitted. - /// `[]rhs`. - /// main_token is the asterisk if a pointer or the lbracket if a slice - /// main_token might be a ** token, which is shared with a parent/child - /// pointer type and may require special handling. - ptr_type_aligned, - /// `[*:lhs]rhs`. lhs can be omitted. - /// `*rhs`. - /// `[:lhs]rhs`. - /// main_token is the asterisk if a pointer or the lbracket if a slice - /// main_token might be a ** token, which is shared with a parent/child - /// pointer type and may require special handling. - ptr_type_sentinel, - /// lhs is index into ptr_type. rhs is the element type expression. - /// main_token is the asterisk if a pointer or the lbracket if a slice - /// main_token might be a ** token, which is shared with a parent/child - /// pointer type and may require special handling. - ptr_type, - /// lhs is index into ptr_type_bit_range. rhs is the element type expression. - /// main_token is the asterisk if a pointer or the lbracket if a slice - /// main_token might be a ** token, which is shared with a parent/child - /// pointer type and may require special handling. - ptr_type_bit_range, - /// `lhs[rhs..]` - /// main_token is the lbracket. - slice_open, - /// `lhs[b..c]`. rhs is index into Slice - /// main_token is the lbracket. - slice, - /// `lhs[b..c :d]`. rhs is index into SliceSentinel - /// main_token is the lbracket. - slice_sentinel, - /// `lhs.*`. rhs is unused. - deref, - /// `lhs[rhs]`. - array_access, - /// `lhs{rhs}`. rhs can be omitted. - array_init_one, - /// `lhs{rhs,}`. rhs can *not* be omitted - array_init_one_comma, - /// `.{lhs, rhs}`. lhs and rhs can be omitted. - array_init_dot_two, - /// Same as `array_init_dot_two` except there is known to be a trailing comma - /// before the final rbrace. - array_init_dot_two_comma, - /// `.{a, b}`. `sub_list[lhs..rhs]`. - array_init_dot, - /// Same as `array_init_dot` except there is known to be a trailing comma - /// before the final rbrace. - array_init_dot_comma, - /// `lhs{a, b}`. `sub_range_list[rhs]`. lhs can be omitted which means `.{a, b}`. - array_init, - /// Same as `array_init` except there is known to be a trailing comma - /// before the final rbrace. - array_init_comma, - /// `lhs{.a = rhs}`. rhs can be omitted making it empty. - /// main_token is the lbrace. - struct_init_one, - /// `lhs{.a = rhs,}`. rhs can *not* be omitted. - /// main_token is the lbrace. - struct_init_one_comma, - /// `.{.a = lhs, .b = rhs}`. lhs and rhs can be omitted. - /// main_token is the lbrace. - /// No trailing comma before the rbrace. - struct_init_dot_two, - /// Same as `struct_init_dot_two` except there is known to be a trailing comma - /// before the final rbrace. - struct_init_dot_two_comma, - /// `.{.a = b, .c = d}`. `sub_list[lhs..rhs]`. - /// main_token is the lbrace. - struct_init_dot, - /// Same as `struct_init_dot` except there is known to be a trailing comma - /// before the final rbrace. - struct_init_dot_comma, - /// `lhs{.a = b, .c = d}`. `sub_range_list[rhs]`. - /// lhs can be omitted which means `.{.a = b, .c = d}`. - /// main_token is the lbrace. - struct_init, - /// Same as `struct_init` except there is known to be a trailing comma - /// before the final rbrace. - struct_init_comma, - /// `lhs(rhs)`. rhs can be omitted. - /// main_token is the lparen. - call_one, - /// `lhs(rhs,)`. rhs can be omitted. - /// main_token is the lparen. - call_one_comma, - /// `async lhs(rhs)`. rhs can be omitted. - async_call_one, - /// `async lhs(rhs,)`. - async_call_one_comma, - /// `lhs(a, b, c)`. `SubRange[rhs]`. - /// main_token is the `(`. - call, - /// `lhs(a, b, c,)`. `SubRange[rhs]`. - /// main_token is the `(`. - call_comma, - /// `async lhs(a, b, c)`. `SubRange[rhs]`. - /// main_token is the `(`. - async_call, - /// `async lhs(a, b, c,)`. `SubRange[rhs]`. - /// main_token is the `(`. - async_call_comma, - /// `switch(lhs) {}`. `SubRange[rhs]`. - @"switch", - /// Same as switch except there is known to be a trailing comma - /// before the final rbrace - switch_comma, - /// `lhs => rhs`. If lhs is omitted it means `else`. - /// main_token is the `=>` - switch_case_one, - /// `a, b, c => rhs`. `SubRange[lhs]`. - /// main_token is the `=>` - switch_case, - /// `lhs...rhs`. - switch_range, - /// `while (lhs) rhs`. - /// `while (lhs) |x| rhs`. - while_simple, - /// `while (lhs) : (a) b`. `WhileCont[rhs]`. - /// `while (lhs) : (a) b`. `WhileCont[rhs]`. - while_cont, - /// `while (lhs) : (a) b else c`. `While[rhs]`. - /// `while (lhs) |x| : (a) b else c`. `While[rhs]`. - /// `while (lhs) |x| : (a) b else |y| c`. `While[rhs]`. - @"while", - /// `for (lhs) rhs`. - for_simple, - /// `for (lhs) a else b`. `if_list[rhs]`. - @"for", - /// `if (lhs) rhs`. - /// `if (lhs) |a| rhs`. - if_simple, - /// `if (lhs) a else b`. `If[rhs]`. - /// `if (lhs) |x| a else b`. `If[rhs]`. - /// `if (lhs) |x| a else |y| b`. `If[rhs]`. - @"if", - /// `suspend lhs`. lhs can be omitted. rhs is unused. - @"suspend", - /// `resume lhs`. rhs is unused. - @"resume", - /// `continue`. lhs is token index of label if any. rhs is unused. - @"continue", - /// `break :lhs rhs` - /// both lhs and rhs may be omitted. - @"break", - /// `return lhs`. lhs can be omitted. rhs is unused. - @"return", - /// `fn(a: lhs) rhs`. lhs can be omitted. - /// anytype and ... parameters are omitted from the AST tree. - /// main_token is the `fn` keyword. - /// extern function declarations use this tag. - fn_proto_simple, - /// `fn(a: b, c: d) rhs`. `sub_range_list[lhs]`. - /// anytype and ... parameters are omitted from the AST tree. - /// main_token is the `fn` keyword. - /// extern function declarations use this tag. - fn_proto_multi, - /// `fn(a: b) rhs linksection(e) callconv(f)`. `FnProtoOne[lhs]`. - /// zero or one parameters. - /// anytype and ... parameters are omitted from the AST tree. - /// main_token is the `fn` keyword. - /// extern function declarations use this tag. - fn_proto_one, - /// `fn(a: b, c: d) rhs linksection(e) callconv(f)`. `FnProto[lhs]`. - /// anytype and ... parameters are omitted from the AST tree. - /// main_token is the `fn` keyword. - /// extern function declarations use this tag. - fn_proto, - /// lhs is the fn_proto. - /// rhs is the function body block. - /// Note that extern function declarations use the fn_proto tags rather - /// than this one. - fn_decl, - /// `anyframe->rhs`. main_token is `anyframe`. `lhs` is arrow token index. - anyframe_type, - /// Both lhs and rhs unused. - anyframe_literal, - /// Both lhs and rhs unused. - char_literal, - /// Both lhs and rhs unused. - integer_literal, - /// Both lhs and rhs unused. - float_literal, - /// Both lhs and rhs unused. - unreachable_literal, - /// Both lhs and rhs unused. - /// Most identifiers will not have explicit AST nodes, however for expressions - /// which could be one of many different kinds of AST nodes, there will be an - /// identifier AST node for it. - identifier, - /// lhs is the dot token index, rhs unused, main_token is the identifier. - enum_literal, - /// main_token is the string literal token - /// Both lhs and rhs unused. - string_literal, - /// main_token is the first token index (redundant with lhs) - /// lhs is the first token index; rhs is the last token index. - /// Could be a series of multiline_string_literal_line tokens, or a single - /// string_literal token. - multiline_string_literal, - /// `(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, - /// `error{a, b}`. - /// rhs is the rbrace, lhs is unused. - error_set_decl, - /// `struct {}`, `union {}`, `opaque {}`, `enum {}`. `extra_data[lhs..rhs]`. - /// main_token is `struct`, `union`, `opaque`, `enum` keyword. - container_decl, - /// Same as ContainerDecl but there is known to be a trailing comma - /// or semicolon before the rbrace. - container_decl_trailing, - /// `struct {lhs, rhs}`, `union {lhs, rhs}`, `opaque {lhs, rhs}`, `enum {lhs, rhs}`. - /// lhs or rhs can be omitted. - /// main_token is `struct`, `union`, `opaque`, `enum` keyword. - container_decl_two, - /// Same as ContainerDeclTwo except there is known to be a trailing comma - /// or semicolon before the rbrace. - container_decl_two_trailing, - /// `union(lhs)` / `enum(lhs)`. `SubRange[rhs]`. - container_decl_arg, - /// Same as container_decl_arg but there is known to be a trailing - /// comma or semicolon before the rbrace. - container_decl_arg_trailing, - /// `union(enum) {}`. `sub_list[lhs..rhs]`. - /// Note that tagged unions with explicitly provided enums are represented - /// by `container_decl_arg`. - tagged_union, - /// Same as tagged_union but there is known to be a trailing comma - /// or semicolon before the rbrace. - tagged_union_trailing, - /// `union(enum) {lhs, rhs}`. lhs or rhs may be omitted. - /// Note that tagged unions with explicitly provided enums are represented - /// by `container_decl_arg`. - tagged_union_two, - /// Same as tagged_union_two but there is known to be a trailing comma - /// or semicolon before the rbrace. - tagged_union_two_trailing, - /// `union(enum(lhs)) {}`. `SubRange[rhs]`. - tagged_union_enum_tag, - /// Same as tagged_union_enum_tag but there is known to be a trailing comma - /// or semicolon before the rbrace. - tagged_union_enum_tag_trailing, - /// `a: lhs = rhs,`. lhs and rhs can be omitted. - /// main_token is the field name identifier. - /// lastToken() does not include the possible trailing comma. - container_field_init, - /// `a: lhs align(rhs),`. rhs can be omitted. - /// main_token is the field name identifier. - /// lastToken() does not include the possible trailing comma. - container_field_align, - /// `a: lhs align(c) = d,`. `container_field_list[rhs]`. - /// main_token is the field name identifier. - /// lastToken() does not include the possible trailing comma. - container_field, - /// `anytype`. both lhs and rhs unused. - /// Used by `ContainerField`. - @"anytype", - /// `comptime lhs`. rhs unused. - @"comptime", - /// `nosuspend lhs`. rhs unused. - @"nosuspend", - /// `{lhs rhs}`. rhs or lhs can be omitted. - /// main_token points at the lbrace. - block_two, - /// Same as block_two but there is known to be a semicolon before the rbrace. - block_two_semicolon, - /// `{}`. `sub_list[lhs..rhs]`. - /// main_token points at the lbrace. - block, - /// Same as block but there is known to be a semicolon before the rbrace. - block_semicolon, - /// `asm(lhs)`. rhs is the token index of the rparen. - asm_simple, - /// `asm(lhs, a)`. `Asm[rhs]`. - @"asm", - /// `[a] "b" (c)`. lhs is 0, rhs is token index of the rparen. - /// `[a] "b" (-> lhs)`. rhs is token index of the rparen. - /// main_token is `a`. - asm_output, - /// `[a] "b" (lhs)`. rhs is token index of the rparen. - /// main_token is `a`. - asm_input, - /// `error.a`. lhs is token index of `.`. rhs is token index of `a`. - error_value, - /// `lhs!rhs`. main_token is the `!`. - error_union, - - pub fn isContainerField(tag: Tag) bool { - return switch (tag) { - .container_field_init, - .container_field_align, - .container_field, - => true, - - else => false, - }; - } - }; - - pub const Data = struct { - lhs: Index, - rhs: Index, - }; - - pub const LocalVarDecl = struct { - type_node: Index, - align_node: Index, - }; - - pub const ArrayTypeSentinel = struct { - elem_type: Index, - sentinel: Index, - }; - - pub const PtrType = struct { - sentinel: Index, - align_node: Index, - }; - - pub const PtrTypeBitRange = struct { - sentinel: Index, - align_node: Index, - bit_range_start: Index, - bit_range_end: Index, - }; - - pub const SubRange = struct { - /// Index into sub_list. - start: Index, - /// Index into sub_list. - end: Index, - }; - - pub const If = struct { - then_expr: Index, - else_expr: Index, - }; - - pub const ContainerField = struct { - value_expr: Index, - align_expr: Index, - }; - - pub const GlobalVarDecl = struct { - type_node: Index, - align_node: Index, - section_node: Index, - }; - - pub const Slice = struct { - start: Index, - end: Index, - }; - - pub const SliceSentinel = struct { - start: Index, - /// May be 0 if the slice is "open" - end: Index, - sentinel: Index, - }; - - pub const While = struct { - cont_expr: Index, - then_expr: Index, - else_expr: Index, - }; - - pub const WhileCont = struct { - cont_expr: Index, - then_expr: Index, - }; - - pub const FnProtoOne = struct { - /// Populated if there is exactly 1 parameter. Otherwise there are 0 parameters. - param: Index, - /// Populated if align(A) is present. - align_expr: Index, - /// Populated if linksection(A) is present. - section_expr: Index, - /// Populated if callconv(A) is present. - callconv_expr: Index, - }; - - pub const FnProto = struct { - params_start: Index, - params_end: Index, - /// Populated if align(A) is present. - align_expr: Index, - /// Populated if linksection(A) is present. - section_expr: Index, - /// Populated if callconv(A) is present. - callconv_expr: Index, - }; - - pub const Asm = struct { - items_start: Index, - items_end: Index, - /// Needed to make lastToken() work. - rparen: TokenIndex, - }; -}; diff --git a/lib/std/zig/parse.zig b/lib/std/zig/parse.zig index 5904e1816f..842847a295 100644 --- a/lib/std/zig/parse.zig +++ b/lib/std/zig/parse.zig @@ -1,19 +1,18 @@ const std = @import("../std.zig"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; -const ast = std.zig.ast; -const Node = ast.Node; -const Tree = ast.Tree; -const AstError = ast.Error; -const TokenIndex = ast.TokenIndex; +const Ast = std.zig.Ast; +const Node = Ast.Node; +const AstError = Ast.Error; +const TokenIndex = Ast.TokenIndex; const Token = std.zig.Token; pub const Error = error{ParseError} || Allocator.Error; /// Result should be freed with tree.deinit() when there are /// no more references to any of the tokens or nodes. -pub fn parse(gpa: *Allocator, source: [:0]const u8) Allocator.Error!Tree { - var tokens = ast.TokenList{}; +pub fn parse(gpa: *Allocator, source: [:0]const u8) Allocator.Error!Ast { + var tokens = Ast.TokenList{}; defer tokens.deinit(gpa); // Empirically, the zig std lib has an 8:1 ratio of source bytes to token count. @@ -69,7 +68,7 @@ pub fn parse(gpa: *Allocator, source: [:0]const u8) Allocator.Error!Tree { }; // TODO experiment with compacting the MultiArrayList slices here - return Tree{ + return Ast{ .source = source, .tokens = tokens.toOwnedSlice(), .nodes = parser.nodes.toOwnedSlice(), @@ -80,15 +79,15 @@ pub fn parse(gpa: *Allocator, source: [:0]const u8) Allocator.Error!Tree { const null_node: Node.Index = 0; -/// Represents in-progress parsing, will be converted to an ast.Tree after completion. +/// Represents in-progress parsing, will be converted to an Ast after completion. const Parser = struct { gpa: *Allocator, source: []const u8, token_tags: []const Token.Tag, - token_starts: []const ast.ByteOffset, + token_starts: []const Ast.ByteOffset, tok_i: TokenIndex, errors: std.ArrayListUnmanaged(AstError), - nodes: ast.NodeList, + nodes: Ast.NodeList, extra_data: std.ArrayListUnmanaged(Node.Index), scratch: std.ArrayListUnmanaged(Node.Index), @@ -121,13 +120,13 @@ const Parser = struct { }; } - fn addNode(p: *Parser, elem: ast.NodeList.Elem) Allocator.Error!Node.Index { + fn addNode(p: *Parser, elem: Ast.NodeList.Elem) Allocator.Error!Node.Index { const result = @intCast(Node.Index, p.nodes.len); try p.nodes.append(p.gpa, elem); return result; } - fn setNode(p: *Parser, i: usize, elem: ast.NodeList.Elem) Node.Index { + fn setNode(p: *Parser, i: usize, elem: Ast.NodeList.Elem) Node.Index { p.nodes.set(i, elem); return @intCast(Node.Index, i); } @@ -148,7 +147,7 @@ const Parser = struct { return result; } - fn warn(p: *Parser, tag: ast.Error.Tag) error{OutOfMemory}!void { + fn warn(p: *Parser, tag: Ast.Error.Tag) error{OutOfMemory}!void { @setCold(true); try p.warnMsg(.{ .tag = tag, .token = p.tok_i }); } @@ -161,12 +160,12 @@ const Parser = struct { .extra = .{ .expected_tag = expected_token }, }); } - fn warnMsg(p: *Parser, msg: ast.Error) error{OutOfMemory}!void { + fn warnMsg(p: *Parser, msg: Ast.Error) error{OutOfMemory}!void { @setCold(true); try p.errors.append(p.gpa, msg); } - fn fail(p: *Parser, tag: ast.Error.Tag) error{ ParseError, OutOfMemory } { + fn fail(p: *Parser, tag: Ast.Error.Tag) error{ ParseError, OutOfMemory } { @setCold(true); return p.failMsg(.{ .tag = tag, .token = p.tok_i }); } @@ -180,7 +179,7 @@ const Parser = struct { }); } - fn failMsg(p: *Parser, msg: ast.Error) error{ ParseError, OutOfMemory } { + fn failMsg(p: *Parser, msg: Ast.Error) error{ ParseError, OutOfMemory } { @setCold(true); try p.warnMsg(msg); return error.ParseError; diff --git a/lib/std/zig/parser_test.zig b/lib/std/zig/parser_test.zig index 95fb3f6bc0..24992569b1 100644 --- a/lib/std/zig/parser_test.zig +++ b/lib/std/zig/parser_test.zig @@ -5308,7 +5308,7 @@ fn testCanonical(source: [:0]const u8) !void { return testTransform(source, source); } -const Error = std.zig.ast.Error.Tag; +const Error = std.zig.Ast.Error.Tag; fn testError(source: [:0]const u8, expected_errors: []const Error) !void { var tree = try std.zig.parse(std.testing.allocator, source); diff --git a/lib/std/zig/render.zig b/lib/std/zig/render.zig index eecb04b35c..bc1dc42855 100644 --- a/lib/std/zig/render.zig +++ b/lib/std/zig/render.zig @@ -3,17 +3,17 @@ const assert = std.debug.assert; const mem = std.mem; const Allocator = std.mem.Allocator; const meta = std.meta; -const ast = std.zig.ast; +const Ast = std.zig.Ast; const Token = std.zig.Token; const indent_delta = 4; const asm_indent_delta = 2; -pub const Error = ast.Tree.RenderError; +pub const Error = Ast.RenderError; const Ais = AutoIndentingStream(std.ArrayList(u8).Writer); -pub fn renderTree(buffer: *std.ArrayList(u8), tree: ast.Tree) Error!void { +pub fn renderTree(buffer: *std.ArrayList(u8), tree: Ast) Error!void { assert(tree.errors.len == 0); // Cannot render an invalid tree. var auto_indenting_stream = Ais{ .indent_delta = indent_delta, @@ -37,7 +37,7 @@ pub fn renderTree(buffer: *std.ArrayList(u8), tree: ast.Tree) Error!void { } /// Render all members in the given slice, keeping empty lines where appropriate -fn renderMembers(gpa: *Allocator, ais: *Ais, tree: ast.Tree, members: []const ast.Node.Index) Error!void { +fn renderMembers(gpa: *Allocator, ais: *Ais, tree: Ast, members: []const Ast.Node.Index) Error!void { if (members.len == 0) return; try renderMember(gpa, ais, tree, members[0], .newline); for (members[1..]) |member| { @@ -46,7 +46,7 @@ fn renderMembers(gpa: *Allocator, ais: *Ais, tree: ast.Tree, members: []const as } } -fn renderMember(gpa: *Allocator, ais: *Ais, tree: ast.Tree, decl: ast.Node.Index, space: Space) Error!void { +fn renderMember(gpa: *Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, space: Space) Error!void { const token_tags = tree.tokens.items(.tag); const main_tokens = tree.nodes.items(.main_token); const datas = tree.nodes.items(.data); @@ -83,9 +83,9 @@ fn renderMember(gpa: *Allocator, ais: *Ais, tree: ast.Tree, decl: ast.Node.Index switch (tree.nodes.items(.tag)[fn_proto]) { .fn_proto_one, .fn_proto => { const callconv_expr = if (tree.nodes.items(.tag)[fn_proto] == .fn_proto_one) - tree.extraData(datas[fn_proto].lhs, ast.Node.FnProtoOne).callconv_expr + tree.extraData(datas[fn_proto].lhs, Ast.Node.FnProtoOne).callconv_expr else - tree.extraData(datas[fn_proto].lhs, ast.Node.FnProto).callconv_expr; + tree.extraData(datas[fn_proto].lhs, Ast.Node.FnProto).callconv_expr; if (callconv_expr != 0 and tree.nodes.items(.tag)[callconv_expr] == .enum_literal) { if (mem.eql(u8, "Inline", tree.tokenSlice(main_tokens[callconv_expr]))) { try ais.writer().writeAll("inline "); @@ -168,7 +168,7 @@ fn renderMember(gpa: *Allocator, ais: *Ais, tree: ast.Tree, decl: ast.Node.Index } /// Render all expressions in the slice, keeping empty lines where appropriate -fn renderExpressions(gpa: *Allocator, ais: *Ais, tree: ast.Tree, expressions: []const ast.Node.Index, space: Space) Error!void { +fn renderExpressions(gpa: *Allocator, ais: *Ais, tree: Ast, expressions: []const Ast.Node.Index, space: Space) Error!void { if (expressions.len == 0) return; try renderExpression(gpa, ais, tree, expressions[0], space); for (expressions[1..]) |expression| { @@ -177,7 +177,7 @@ fn renderExpressions(gpa: *Allocator, ais: *Ais, tree: ast.Tree, expressions: [] } } -fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void { +fn renderExpression(gpa: *Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, space: Space) Error!void { const token_tags = tree.tokens.items(.tag); const main_tokens = tree.nodes.items(.main_token); const node_tags = tree.nodes.items(.tag); @@ -220,7 +220,7 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I .block_two, .block_two_semicolon, => { - const statements = [2]ast.Node.Index{ datas[node].lhs, datas[node].rhs }; + const statements = [2]Ast.Node.Index{ datas[node].lhs, datas[node].rhs }; if (datas[node].lhs == 0) { return renderBlock(gpa, ais, tree, node, statements[0..0], space); } else if (datas[node].rhs == 0) { @@ -413,11 +413,11 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I .ptr_type_bit_range => return renderPtrType(gpa, ais, tree, tree.ptrTypeBitRange(node), space), .array_init_one, .array_init_one_comma => { - var elements: [1]ast.Node.Index = undefined; + var elements: [1]Ast.Node.Index = undefined; return renderArrayInit(gpa, ais, tree, tree.arrayInitOne(&elements, node), space); }, .array_init_dot_two, .array_init_dot_two_comma => { - var elements: [2]ast.Node.Index = undefined; + var elements: [2]Ast.Node.Index = undefined; return renderArrayInit(gpa, ais, tree, tree.arrayInitDotTwo(&elements, node), space); }, .array_init_dot, @@ -428,11 +428,11 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I => return renderArrayInit(gpa, ais, tree, tree.arrayInit(node), space), .struct_init_one, .struct_init_one_comma => { - var fields: [1]ast.Node.Index = undefined; + var fields: [1]Ast.Node.Index = undefined; return renderStructInit(gpa, ais, tree, node, tree.structInitOne(&fields, node), space); }, .struct_init_dot_two, .struct_init_dot_two_comma => { - var fields: [2]ast.Node.Index = undefined; + var fields: [2]Ast.Node.Index = undefined; return renderStructInit(gpa, ais, tree, node, tree.structInitDotTwo(&fields, node), space); }, .struct_init_dot, @@ -443,7 +443,7 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I => return renderStructInit(gpa, ais, tree, node, tree.structInit(node), space), .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; return renderCall(gpa, ais, tree, tree.callOne(¶ms, node), space); }, @@ -536,7 +536,7 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I => return renderContainerDecl(gpa, ais, tree, node, tree.containerDecl(node), space), .container_decl_two, .container_decl_two_trailing => { - var buffer: [2]ast.Node.Index = undefined; + var buffer: [2]Ast.Node.Index = undefined; return renderContainerDecl(gpa, ais, tree, node, tree.containerDeclTwo(&buffer, node), space); }, .container_decl_arg, @@ -548,7 +548,7 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I => return renderContainerDecl(gpa, ais, tree, node, tree.taggedUnion(node), space), .tagged_union_two, .tagged_union_two_trailing => { - var buffer: [2]ast.Node.Index = undefined; + var buffer: [2]Ast.Node.Index = undefined; return renderContainerDecl(gpa, ais, tree, node, tree.taggedUnionTwo(&buffer, node), space); }, .tagged_union_enum_tag, @@ -619,12 +619,12 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I }, .fn_proto_simple => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; return renderFnProto(gpa, ais, tree, tree.fnProtoSimple(¶ms, node), space); }, .fn_proto_multi => return renderFnProto(gpa, ais, tree, tree.fnProtoMulti(node), space), .fn_proto_one => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; return renderFnProto(gpa, ais, tree, tree.fnProtoOne(¶ms, node), space); }, .fn_proto => return renderFnProto(gpa, ais, tree, tree.fnProto(node), space), @@ -645,7 +645,7 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I => { const switch_token = main_tokens[node]; const condition = datas[node].lhs; - const extra = tree.extraData(datas[node].rhs, ast.Node.SubRange); + const extra = tree.extraData(datas[node].rhs, Ast.Node.SubRange); const cases = tree.extra_data[extra.start..extra.end]; const rparen = tree.lastToken(condition) + 1; @@ -704,8 +704,8 @@ fn renderExpression(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.I fn renderArrayType( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - array_type: ast.full.ArrayType, + tree: Ast, + array_type: Ast.full.ArrayType, space: Space, ) Error!void { const rbracket = tree.firstToken(array_type.ast.elem_type) - 1; @@ -726,8 +726,8 @@ fn renderArrayType( fn renderPtrType( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - ptr_type: ast.full.PtrType, + tree: Ast, + ptr_type: Ast.full.PtrType, space: Space, ) Error!void { switch (ptr_type.size) { @@ -811,9 +811,9 @@ fn renderPtrType( fn renderSlice( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - slice_node: ast.Node.Index, - slice: ast.full.Slice, + tree: Ast, + slice_node: Ast.Node.Index, + slice: Ast.full.Slice, space: Space, ) Error!void { const node_tags = tree.nodes.items(.tag); @@ -847,8 +847,8 @@ fn renderSlice( fn renderAsmOutput( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - asm_output: ast.Node.Index, + tree: Ast, + asm_output: Ast.Node.Index, space: Space, ) Error!void { const token_tags = tree.tokens.items(.tag); @@ -877,8 +877,8 @@ fn renderAsmOutput( fn renderAsmInput( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - asm_input: ast.Node.Index, + tree: Ast, + asm_input: Ast.Node.Index, space: Space, ) Error!void { const node_tags = tree.nodes.items(.tag); @@ -896,7 +896,7 @@ fn renderAsmInput( return renderToken(ais, tree, datas[asm_input].rhs, space); // rparen } -fn renderVarDecl(gpa: *Allocator, ais: *Ais, tree: ast.Tree, var_decl: ast.full.VarDecl) Error!void { +fn renderVarDecl(gpa: *Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDecl) Error!void { if (var_decl.visib_token) |visib_token| { try renderToken(ais, tree, visib_token, Space.space); // pub } @@ -985,7 +985,7 @@ fn renderVarDecl(gpa: *Allocator, ais: *Ais, tree: ast.Tree, var_decl: ast.full. return renderToken(ais, tree, var_decl.ast.mut_token + 2, .newline); // ; } -fn renderIf(gpa: *Allocator, ais: *Ais, tree: ast.Tree, if_node: ast.full.If, space: Space) Error!void { +fn renderIf(gpa: *Allocator, ais: *Ais, tree: Ast, if_node: Ast.full.If, space: Space) Error!void { return renderWhile(gpa, ais, tree, .{ .ast = .{ .while_token = if_node.ast.if_token, @@ -1004,7 +1004,7 @@ fn renderIf(gpa: *Allocator, ais: *Ais, tree: ast.Tree, if_node: ast.full.If, sp /// Note that this function is additionally used to render if and for expressions, with /// respective values set to null. -fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full.While, space: Space) Error!void { +fn renderWhile(gpa: *Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While, space: Space) Error!void { const node_tags = tree.nodes.items(.tag); const token_tags = tree.tokens.items(.tag); @@ -1109,8 +1109,8 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full. fn renderContainerField( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - field: ast.full.ContainerField, + tree: Ast, + field: Ast.full.ContainerField, space: Space, ) Error!void { if (field.comptime_token) |t| { @@ -1183,9 +1183,9 @@ fn renderContainerField( fn renderBuiltinCall( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - builtin_token: ast.TokenIndex, - params: []const ast.Node.Index, + tree: Ast, + builtin_token: Ast.TokenIndex, + params: []const Ast.Node.Index, space: Space, ) Error!void { const token_tags = tree.tokens.items(.tag); @@ -1238,7 +1238,7 @@ fn renderBuiltinCall( } } -fn renderFnProto(gpa: *Allocator, ais: *Ais, tree: ast.Tree, fn_proto: ast.full.FnProto, space: Space) Error!void { +fn renderFnProto(gpa: *Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProto, space: Space) Error!void { const token_tags = tree.tokens.items(.tag); const token_starts = tree.tokens.items(.start); @@ -1438,8 +1438,8 @@ fn renderFnProto(gpa: *Allocator, ais: *Ais, tree: ast.Tree, fn_proto: ast.full. fn renderSwitchCase( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - switch_case: ast.full.SwitchCase, + tree: Ast, + switch_case: Ast.full.SwitchCase, space: Space, ) Error!void { const node_tags = tree.nodes.items(.tag); @@ -1491,9 +1491,9 @@ fn renderSwitchCase( fn renderBlock( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - block_node: ast.Node.Index, - statements: []const ast.Node.Index, + tree: Ast, + block_node: Ast.Node.Index, + statements: []const Ast.Node.Index, space: Space, ) Error!void { const token_tags = tree.tokens.items(.tag); @@ -1531,9 +1531,9 @@ fn renderBlock( fn renderStructInit( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - struct_node: ast.Node.Index, - struct_init: ast.full.StructInit, + tree: Ast, + struct_node: Ast.Node.Index, + struct_init: Ast.full.StructInit, space: Space, ) Error!void { const token_tags = tree.tokens.items(.tag); @@ -1590,8 +1590,8 @@ fn renderStructInit( fn renderArrayInit( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - array_init: ast.full.ArrayInit, + tree: Ast, + array_init: Ast.full.ArrayInit, space: Space, ) Error!void { const token_tags = tree.tokens.items(.tag); @@ -1787,9 +1787,9 @@ fn renderArrayInit( fn renderContainerDecl( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - container_decl_node: ast.Node.Index, - container_decl: ast.full.ContainerDecl, + tree: Ast, + container_decl_node: Ast.Node.Index, + container_decl: Ast.full.ContainerDecl, space: Space, ) Error!void { const token_tags = tree.tokens.items(.tag); @@ -1799,7 +1799,7 @@ fn renderContainerDecl( try renderToken(ais, tree, layout_token, .space); } - var lbrace: ast.TokenIndex = undefined; + var lbrace: Ast.TokenIndex = undefined; if (container_decl.ast.enum_token) |enum_token| { try renderToken(ais, tree, container_decl.ast.main_token, .none); // union try renderToken(ais, tree, enum_token - 1, .none); // lparen @@ -1869,8 +1869,8 @@ fn renderContainerDecl( fn renderAsm( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - asm_node: ast.full.Asm, + tree: Ast, + asm_node: Ast.full.Asm, space: Space, ) Error!void { const token_tags = tree.tokens.items(.tag); @@ -2018,8 +2018,8 @@ fn renderAsm( fn renderCall( gpa: *Allocator, ais: *Ais, - tree: ast.Tree, - call: ast.full.Call, + tree: Ast, + call: Ast.full.Call, space: Space, ) Error!void { const token_tags = tree.tokens.items(.tag); @@ -2091,7 +2091,7 @@ fn renderCall( /// Renders the given expression indented, popping the indent before rendering /// any following line comments -fn renderExpressionIndented(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void { +fn renderExpressionIndented(gpa: *Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, space: Space) Error!void { const token_starts = tree.tokens.items(.start); const token_tags = tree.tokens.items(.tag); @@ -2148,7 +2148,7 @@ fn renderExpressionIndented(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: as } /// Render an expression, and the comma that follows it, if it is present in the source. -fn renderExpressionComma(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Space) Error!void { +fn renderExpressionComma(gpa: *Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, space: Space) Error!void { const token_tags = tree.tokens.items(.tag); const maybe_comma = tree.lastToken(node) + 1; if (token_tags[maybe_comma] == .comma) { @@ -2159,7 +2159,7 @@ fn renderExpressionComma(gpa: *Allocator, ais: *Ais, tree: ast.Tree, node: ast.N } } -fn renderTokenComma(ais: *Ais, tree: ast.Tree, token: ast.TokenIndex, space: Space) Error!void { +fn renderTokenComma(ais: *Ais, tree: Ast, token: Ast.TokenIndex, space: Space) Error!void { const token_tags = tree.tokens.items(.tag); const maybe_comma = token + 1; if (token_tags[maybe_comma] == .comma) { @@ -2191,7 +2191,7 @@ const Space = enum { skip, }; -fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Space) Error!void { +fn renderToken(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Space) Error!void { const token_tags = tree.tokens.items(.tag); const token_starts = tree.tokens.items(.start); @@ -2238,7 +2238,7 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp /// `start_token` to `end_token`. This is used to determine if e.g. a /// fn_proto should be wrapped and have a trailing comma inserted even if /// there is none in the source. -fn hasComment(tree: ast.Tree, start_token: ast.TokenIndex, end_token: ast.TokenIndex) bool { +fn hasComment(tree: Ast, start_token: Ast.TokenIndex, end_token: Ast.TokenIndex) bool { const token_starts = tree.tokens.items(.start); var i = start_token; @@ -2253,7 +2253,7 @@ fn hasComment(tree: ast.Tree, start_token: ast.TokenIndex, end_token: ast.TokenI /// Returns true if there exists a multiline string literal between the start /// of token `start_token` and the start of token `end_token`. -fn hasMultilineString(tree: ast.Tree, start_token: ast.TokenIndex, end_token: ast.TokenIndex) bool { +fn hasMultilineString(tree: Ast, start_token: Ast.TokenIndex, end_token: Ast.TokenIndex) bool { const token_tags = tree.tokens.items(.tag); for (token_tags[start_token..end_token]) |tag| { @@ -2268,7 +2268,7 @@ fn hasMultilineString(tree: ast.Tree, start_token: ast.TokenIndex, end_token: as /// Assumes that start is the first byte past the previous token and /// that end is the last byte before the next token. -fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize) Error!bool { +fn renderComments(ais: *Ais, tree: Ast, start: usize, end: usize) Error!bool { var index: usize = start; while (mem.indexOf(u8, tree.source[index..end], "//")) |offset| { const comment_start = index + offset; @@ -2325,12 +2325,12 @@ fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize) Error!boo return index != start; } -fn renderExtraNewline(ais: *Ais, tree: ast.Tree, node: ast.Node.Index) Error!void { +fn renderExtraNewline(ais: *Ais, tree: Ast, node: Ast.Node.Index) Error!void { return renderExtraNewlineToken(ais, tree, tree.firstToken(node)); } /// Check if there is an empty line immediately before the given token. If so, render it. -fn renderExtraNewlineToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex) Error!void { +fn renderExtraNewlineToken(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex) Error!void { const token_starts = tree.tokens.items(.start); const token_start = token_starts[token_index]; if (token_start == 0) return; @@ -2355,7 +2355,7 @@ fn renderExtraNewlineToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenInde /// end_token is the token one past the last doc comment token. This function /// searches backwards from there. -fn renderDocComments(ais: *Ais, tree: ast.Tree, end_token: ast.TokenIndex) Error!void { +fn renderDocComments(ais: *Ais, tree: Ast, end_token: Ast.TokenIndex) Error!void { // Search backwards for the first doc comment. const token_tags = tree.tokens.items(.tag); if (end_token == 0) return; @@ -2376,7 +2376,7 @@ fn renderDocComments(ais: *Ais, tree: ast.Tree, end_token: ast.TokenIndex) Error } /// start_token is first container doc comment token. -fn renderContainerDocComments(ais: *Ais, tree: ast.Tree, start_token: ast.TokenIndex) Error!void { +fn renderContainerDocComments(ais: *Ais, tree: Ast, start_token: Ast.TokenIndex) Error!void { const token_tags = tree.tokens.items(.tag); var tok = start_token; while (token_tags[tok] == .container_doc_comment) : (tok += 1) { @@ -2390,7 +2390,7 @@ fn renderContainerDocComments(ais: *Ais, tree: ast.Tree, start_token: ast.TokenI } } -fn tokenSliceForRender(tree: ast.Tree, token_index: ast.TokenIndex) []const u8 { +fn tokenSliceForRender(tree: Ast, token_index: Ast.TokenIndex) []const u8 { var ret = tree.tokenSlice(token_index); if (tree.tokens.items(.tag)[token_index] == .multiline_string_literal_line) { assert(ret[ret.len - 1] == '\n'); @@ -2399,7 +2399,7 @@ fn tokenSliceForRender(tree: ast.Tree, token_index: ast.TokenIndex) []const u8 { return ret; } -fn hasSameLineComment(tree: ast.Tree, token_index: ast.TokenIndex) bool { +fn hasSameLineComment(tree: Ast, token_index: Ast.TokenIndex) bool { const token_starts = tree.tokens.items(.start); const between_source = tree.source[token_starts[token_index]..token_starts[token_index + 1]]; for (between_source) |byte| switch (byte) { @@ -2412,7 +2412,7 @@ fn hasSameLineComment(tree: ast.Tree, token_index: ast.TokenIndex) bool { /// Returns `true` if and only if there are any tokens or line comments between /// start_token and end_token. -fn anythingBetween(tree: ast.Tree, start_token: ast.TokenIndex, end_token: ast.TokenIndex) bool { +fn anythingBetween(tree: Ast, start_token: Ast.TokenIndex, end_token: Ast.TokenIndex) bool { if (start_token + 1 != end_token) return true; const token_starts = tree.tokens.items(.start); const between_source = tree.source[token_starts[start_token]..token_starts[start_token + 1]]; @@ -2431,7 +2431,7 @@ fn writeFixingWhitespace(writer: std.ArrayList(u8).Writer, slice: []const u8) Er }; } -fn nodeIsBlock(tag: ast.Node.Tag) bool { +fn nodeIsBlock(tag: Ast.Node.Tag) bool { return switch (tag) { .block, .block_semicolon, @@ -2450,7 +2450,7 @@ fn nodeIsBlock(tag: ast.Node.Tag) bool { }; } -fn nodeIsIfForWhileSwitch(tag: ast.Node.Tag) bool { +fn nodeIsIfForWhileSwitch(tag: Ast.Node.Tag) bool { return switch (tag) { .@"if", .if_simple, @@ -2466,7 +2466,7 @@ fn nodeIsIfForWhileSwitch(tag: ast.Node.Tag) bool { }; } -fn nodeCausesSliceOpSpace(tag: ast.Node.Tag) bool { +fn nodeCausesSliceOpSpace(tag: Ast.Node.Tag) bool { return switch (tag) { .@"catch", .add, @@ -2516,7 +2516,7 @@ fn nodeCausesSliceOpSpace(tag: ast.Node.Tag) bool { } // Returns the number of nodes in `expr` that are on the same line as `rtoken`. -fn rowSize(tree: ast.Tree, exprs: []const ast.Node.Index, rtoken: ast.TokenIndex) usize { +fn rowSize(tree: Ast, exprs: []const Ast.Node.Index, rtoken: Ast.TokenIndex) usize { const token_tags = tree.tokens.items(.tag); const first_token = tree.firstToken(exprs[0]); diff --git a/src/AstGen.zig b/src/AstGen.zig index 570b2cd943..849dae613f 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -2,7 +2,7 @@ const AstGen = @This(); const std = @import("std"); -const ast = std.zig.ast; +const Ast = std.zig.Ast; const mem = std.mem; const Allocator = std.mem.Allocator; const assert = std.debug.assert; @@ -13,7 +13,7 @@ const trace = @import("tracy.zig").trace; const BuiltinFn = @import("BuiltinFn.zig"); gpa: *Allocator, -tree: *const ast.Tree, +tree: *const Ast, instructions: std.MultiArrayList(Zir.Inst) = .{}, extra: ArrayListUnmanaged(u32) = .{}, string_bytes: ArrayListUnmanaged(u8) = .{}, @@ -36,7 +36,7 @@ compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{}, fn_block: ?*GenZir = null, /// Maps string table indexes to the first `@import` ZIR instruction /// that uses this string as the operand. -imports: std.AutoArrayHashMapUnmanaged(u32, ast.TokenIndex) = .{}, +imports: std.AutoArrayHashMapUnmanaged(u32, Ast.TokenIndex) = .{}, const InnerError = error{ OutOfMemory, AnalysisFail }; @@ -70,7 +70,7 @@ fn appendRefsAssumeCapacity(astgen: *AstGen, refs: []const Zir.Inst.Ref) void { astgen.extra.appendSliceAssumeCapacity(coerced); } -pub fn generate(gpa: *Allocator, tree: ast.Tree) Allocator.Error!Zir { +pub fn generate(gpa: *Allocator, tree: Ast) Allocator.Error!Zir { var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); @@ -106,7 +106,7 @@ pub fn generate(gpa: *Allocator, tree: ast.Tree) Allocator.Error!Zir { }; defer gen_scope.instructions.deinit(gpa); - const container_decl: ast.full.ContainerDecl = .{ + const container_decl: Ast.full.ContainerDecl = .{ .layout_token = null, .ast = .{ .main_token = undefined, @@ -265,7 +265,7 @@ pub const bool_rl: ResultLoc = .{ .ty = .bool_type }; pub const type_rl: ResultLoc = .{ .ty = .type_type }; pub const coerced_type_rl: ResultLoc = .{ .coerced_ty = .type_type }; -fn typeExpr(gz: *GenZir, scope: *Scope, type_node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn typeExpr(gz: *GenZir, scope: *Scope, type_node: Ast.Node.Index) InnerError!Zir.Inst.Ref { const prev_force_comptime = gz.force_comptime; gz.force_comptime = true; defer gz.force_comptime = prev_force_comptime; @@ -278,8 +278,8 @@ fn reachableExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - src_node: ast.Node.Index, + node: Ast.Node.Index, + src_node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const result_inst = try expr(gz, scope, rl, node); if (gz.refIsNoReturn(result_inst)) { @@ -290,7 +290,7 @@ fn reachableExpr( return result_inst; } -fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn lvalExpr(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; const node_tags = tree.nodes.items(.tag); @@ -481,7 +481,7 @@ fn lvalExpr(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Ins /// When `rl` is discard, ptr, inferred_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. -fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); @@ -640,13 +640,13 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr .builtin_call_two, .builtin_call_two_comma => { if (node_datas[node].lhs == 0) { - const params = [_]ast.Node.Index{}; + const params = [_]Ast.Node.Index{}; return builtinCall(gz, scope, rl, node, ¶ms); } else if (node_datas[node].rhs == 0) { - const params = [_]ast.Node.Index{node_datas[node].lhs}; + const params = [_]Ast.Node.Index{node_datas[node].lhs}; return builtinCall(gz, scope, rl, node, ¶ms); } else { - const params = [_]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs }; + const params = [_]Ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs }; return builtinCall(gz, scope, rl, node, ¶ms); } }, @@ -656,7 +656,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr }, .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; return callExpr(gz, scope, rl, node, tree.callOne(¶ms, node)); }, .call, .call_comma, .async_call, .async_call_comma => { @@ -704,7 +704,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr }, .slice => { const lhs = try expr(gz, scope, .ref, node_datas[node].lhs); - const extra = tree.extraData(node_datas[node].rhs, ast.Node.Slice); + const extra = tree.extraData(node_datas[node].rhs, Ast.Node.Slice); const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start); const end = try expr(gz, scope, .{ .ty = .usize_type }, extra.end); const result = try gz.addPlNode(.slice_end, node, Zir.Inst.SliceEnd{ @@ -722,7 +722,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr }, .slice_sentinel => { const lhs = try expr(gz, scope, .ref, node_datas[node].lhs); - const extra = tree.extraData(node_datas[node].rhs, ast.Node.SliceSentinel); + const extra = tree.extraData(node_datas[node].rhs, Ast.Node.SliceSentinel); const start = try expr(gz, scope, .{ .ty = .usize_type }, extra.start); const end = if (extra.end != 0) try expr(gz, scope, .{ .ty = .usize_type }, extra.end) else .none; const sentinel = try expr(gz, scope, .{ .ty = .usize_type }, extra.sentinel); @@ -773,7 +773,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr ), node), }, .block_two, .block_two_semicolon => { - const statements = [2]ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs }; + const statements = [2]Ast.Node.Index{ node_datas[node].lhs, node_datas[node].rhs }; if (node_datas[node].lhs == 0) { return blockExpr(gz, scope, rl, node, statements[0..0]); } else if (node_datas[node].rhs == 0) { @@ -796,7 +796,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr }, .@"catch" => { const catch_token = main_tokens[node]; - const payload_token: ?ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe) + const payload_token: ?Ast.TokenIndex = if (token_tags[catch_token + 1] == .pipe) catch_token + 2 else null; @@ -863,7 +863,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr .container_decl_trailing, => return containerDecl(gz, scope, rl, node, tree.containerDecl(node)), .container_decl_two, .container_decl_two_trailing => { - var buffer: [2]ast.Node.Index = undefined; + var buffer: [2]Ast.Node.Index = undefined; return containerDecl(gz, scope, rl, node, tree.containerDeclTwo(&buffer, node)); }, .container_decl_arg, @@ -874,7 +874,7 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr .tagged_union_trailing, => return containerDecl(gz, scope, rl, node, tree.taggedUnion(node)), .tagged_union_two, .tagged_union_two_trailing => { - var buffer: [2]ast.Node.Index = undefined; + var buffer: [2]Ast.Node.Index = undefined; return containerDecl(gz, scope, rl, node, tree.taggedUnionTwo(&buffer, node)); }, .tagged_union_enum_tag, @@ -900,11 +900,11 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr .@"try" => return tryExpr(gz, scope, rl, node, node_datas[node].lhs), .array_init_one, .array_init_one_comma => { - var elements: [1]ast.Node.Index = undefined; + var elements: [1]Ast.Node.Index = undefined; return arrayInitExpr(gz, scope, rl, node, tree.arrayInitOne(&elements, node)); }, .array_init_dot_two, .array_init_dot_two_comma => { - var elements: [2]ast.Node.Index = undefined; + var elements: [2]Ast.Node.Index = undefined; return arrayInitExpr(gz, scope, rl, node, tree.arrayInitDotTwo(&elements, node)); }, .array_init_dot, @@ -915,11 +915,11 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr => return arrayInitExpr(gz, scope, rl, node, tree.arrayInit(node)), .struct_init_one, .struct_init_one_comma => { - var fields: [1]ast.Node.Index = undefined; + var fields: [1]Ast.Node.Index = undefined; return structInitExpr(gz, scope, rl, node, tree.structInitOne(&fields, node)); }, .struct_init_dot_two, .struct_init_dot_two_comma => { - var fields: [2]ast.Node.Index = undefined; + var fields: [2]Ast.Node.Index = undefined; return structInitExpr(gz, scope, rl, node, tree.structInitDotTwo(&fields, node)); }, .struct_init_dot, @@ -930,14 +930,14 @@ fn expr(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerEr => return structInitExpr(gz, scope, rl, node, tree.structInit(node)), .fn_proto_simple => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; return fnProtoExpr(gz, scope, rl, tree.fnProtoSimple(¶ms, node)); }, .fn_proto_multi => { return fnProtoExpr(gz, scope, rl, tree.fnProtoMulti(node)); }, .fn_proto_one => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; return fnProtoExpr(gz, scope, rl, tree.fnProtoOne(¶ms, node)); }, .fn_proto => { @@ -950,7 +950,7 @@ fn nosuspendExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; @@ -971,7 +971,7 @@ fn nosuspendExpr( fn suspendExpr( gz: *GenZir, scope: *Scope, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; @@ -1011,7 +1011,7 @@ fn awaitExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; @@ -1033,7 +1033,7 @@ fn resumeExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; @@ -1048,7 +1048,7 @@ fn fnProtoExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, - fn_proto: ast.full.FnProto, + fn_proto: Ast.full.FnProto, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; @@ -1159,8 +1159,8 @@ fn arrayInitExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - array_init: ast.full.ArrayInit, + node: Ast.Node.Index, + array_init: Ast.full.ArrayInit, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; @@ -1179,7 +1179,7 @@ fn arrayInitExpr( }; infer: { - const array_type: ast.full.ArrayType = switch (node_tags[array_init.ast.type_expr]) { + const array_type: Ast.full.ArrayType = switch (node_tags[array_init.ast.type_expr]) { .array_type => tree.arrayType(array_init.ast.type_expr), .array_type_sentinel => tree.arrayTypeSentinel(array_init.ast.type_expr), else => break :infer, @@ -1256,8 +1256,8 @@ fn arrayInitExpr( fn arrayInitExprRlNone( gz: *GenZir, scope: *Scope, - node: ast.Node.Index, - elements: []const ast.Node.Index, + node: Ast.Node.Index, + elements: []const Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; @@ -1278,8 +1278,8 @@ fn arrayInitExprRlNone( fn arrayInitExprRlTy( gz: *GenZir, scope: *Scope, - node: ast.Node.Index, - elements: []const ast.Node.Index, + node: Ast.Node.Index, + elements: []const Ast.Node.Index, elem_ty_inst: Zir.Inst.Ref, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { @@ -1304,8 +1304,8 @@ fn arrayInitExprRlTy( fn arrayInitExprRlPtr( gz: *GenZir, scope: *Scope, - node: ast.Node.Index, - elements: []const ast.Node.Index, + node: Ast.Node.Index, + elements: []const Ast.Node.Index, result_ptr: Zir.Inst.Ref, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; @@ -1334,8 +1334,8 @@ fn structInitExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - struct_init: ast.full.StructInit, + node: Ast.Node.Index, + struct_init: Ast.full.StructInit, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; @@ -1347,7 +1347,7 @@ fn structInitExpr( } else array: { const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); - const array_type: ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) { + const array_type: Ast.full.ArrayType = switch (node_tags[struct_init.ast.type_expr]) { .array_type => tree.arrayType(struct_init.ast.type_expr), .array_type_sentinel => tree.arrayTypeSentinel(struct_init.ast.type_expr), else => break :array, @@ -1420,8 +1420,8 @@ fn structInitExpr( fn structInitExprRlNone( gz: *GenZir, scope: *Scope, - node: ast.Node.Index, - struct_init: ast.full.StructInit, + node: Ast.Node.Index, + struct_init: Ast.full.StructInit, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; @@ -1454,8 +1454,8 @@ fn structInitExprRlNone( fn structInitExprRlPtr( gz: *GenZir, scope: *Scope, - node: ast.Node.Index, - struct_init: ast.full.StructInit, + node: Ast.Node.Index, + struct_init: Ast.full.StructInit, result_ptr: Zir.Inst.Ref, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; @@ -1488,8 +1488,8 @@ fn structInitExprRlPtr( fn structInitExprRlTy( gz: *GenZir, scope: *Scope, - node: ast.Node.Index, - struct_init: ast.full.StructInit, + node: Ast.Node.Index, + struct_init: Ast.full.StructInit, ty_inst: Zir.Inst.Ref, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { @@ -1530,7 +1530,7 @@ fn comptimeExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const prev_force_comptime = gz.force_comptime; gz.force_comptime = true; @@ -1546,7 +1546,7 @@ fn comptimeExprAst( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; if (gz.force_comptime) { @@ -1561,7 +1561,7 @@ fn comptimeExprAst( return result; } -fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; const tree = astgen.tree; const node_datas = tree.nodes.items(.data); @@ -1636,7 +1636,7 @@ fn breakExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) Inn } } -fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn continueExpr(parent_gz: *GenZir, parent_scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; const tree = astgen.tree; const node_datas = tree.nodes.items(.data); @@ -1694,8 +1694,8 @@ fn blockExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, - block_node: ast.Node.Index, - statements: []const ast.Node.Index, + block_node: Ast.Node.Index, + statements: []const Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const tracy = trace(@src()); defer tracy.end(); @@ -1716,7 +1716,7 @@ fn blockExpr( return rvalue(gz, rl, .void_value, block_node); } -fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: ast.TokenIndex) !void { +fn checkLabelRedefinition(astgen: *AstGen, parent_scope: *Scope, label: Ast.TokenIndex) !void { // Look for the label in the scope. var scope = parent_scope; while (true) { @@ -1752,8 +1752,8 @@ fn labeledBlockExpr( gz: *GenZir, parent_scope: *Scope, rl: ResultLoc, - block_node: ast.Node.Index, - statements: []const ast.Node.Index, + block_node: Ast.Node.Index, + statements: []const Ast.Node.Index, zir_tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const tracy = trace(@src()); @@ -1829,7 +1829,7 @@ fn labeledBlockExpr( } } -fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Node.Index) !void { +fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const Ast.Node.Index) !void { const astgen = gz.astgen; const tree = astgen.tree; const node_tags = tree.nodes.items(.tag); @@ -1837,7 +1837,7 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Nod var block_arena = std.heap.ArenaAllocator.init(gz.astgen.gpa); defer block_arena.deinit(); - var noreturn_src_node: ast.Node.Index = 0; + var noreturn_src_node: Ast.Node.Index = 0; var scope = parent_scope; for (statements) |statement| { if (noreturn_src_node != 0) { @@ -1892,12 +1892,12 @@ fn blockExprStmts(gz: *GenZir, parent_scope: *Scope, statements: []const ast.Nod /// Returns AST source node of the thing that is noreturn if the statement is definitely `noreturn`. /// Otherwise returns 0. -fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: ast.Node.Index) InnerError!ast.Node.Index { +fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) InnerError!Ast.Node.Index { try emitDbgNode(gz, statement); // We need to emit an error if the result is not `noreturn` or `void`, but // we want to avoid adding the ZIR instruction if possible for performance. const maybe_unused_result = try expr(gz, scope, .none, statement); - var noreturn_src_node: ast.Node.Index = 0; + var noreturn_src_node: Ast.Node.Index = 0; const elide_check = if (refToIndex(maybe_unused_result)) |inst| b: { // Note that this array becomes invalid after appending more items to it // in the above while loop. @@ -2344,7 +2344,7 @@ fn checkUsed( fn makeDeferScope( scope: *Scope, - node: ast.Node.Index, + node: Ast.Node.Index, block_arena: *Allocator, scope_tag: Scope.Tag, ) InnerError!*Scope { @@ -2360,9 +2360,9 @@ fn makeDeferScope( fn varDecl( gz: *GenZir, scope: *Scope, - node: ast.Node.Index, + node: Ast.Node.Index, block_arena: *Allocator, - var_decl: ast.full.VarDecl, + var_decl: Ast.full.VarDecl, ) InnerError!*Scope { try emitDbgNode(gz, node); const astgen = gz.astgen; @@ -2574,7 +2574,7 @@ fn varDecl( } } -fn emitDbgNode(gz: *GenZir, node: ast.Node.Index) !void { +fn emitDbgNode(gz: *GenZir, node: Ast.Node.Index) !void { // The instruction emitted here is for debugging runtime code. // If the current block will be evaluated only during semantic analysis // then no dbg_stmt ZIR instruction is needed. @@ -2598,7 +2598,7 @@ fn emitDbgNode(gz: *GenZir, node: ast.Node.Index) !void { } }); } -fn assign(gz: *GenZir, scope: *Scope, infix_node: ast.Node.Index) InnerError!void { +fn assign(gz: *GenZir, scope: *Scope, infix_node: Ast.Node.Index) InnerError!void { try emitDbgNode(gz, infix_node); const astgen = gz.astgen; const tree = astgen.tree; @@ -2623,7 +2623,7 @@ fn assign(gz: *GenZir, scope: *Scope, infix_node: ast.Node.Index) InnerError!voi fn assignOp( gz: *GenZir, scope: *Scope, - infix_node: ast.Node.Index, + infix_node: Ast.Node.Index, op_inst_tag: Zir.Inst.Tag, ) InnerError!void { try emitDbgNode(gz, infix_node); @@ -2646,7 +2646,7 @@ fn assignOp( fn assignShift( gz: *GenZir, scope: *Scope, - infix_node: ast.Node.Index, + infix_node: Ast.Node.Index, op_inst_tag: Zir.Inst.Tag, ) InnerError!void { try emitDbgNode(gz, infix_node); @@ -2666,7 +2666,7 @@ fn assignShift( _ = try gz.addBin(.store, lhs_ptr, result); } -fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; const node_datas = tree.nodes.items(.data); @@ -2676,7 +2676,7 @@ fn boolNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) Inne return rvalue(gz, rl, result, node); } -fn bitNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn bitNot(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; const node_datas = tree.nodes.items(.data); @@ -2690,7 +2690,7 @@ fn negation( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; @@ -2706,8 +2706,8 @@ fn ptrType( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - ptr_info: ast.full.PtrType, + node: Ast.Node.Index, + ptr_info: Ast.full.PtrType, ) InnerError!Zir.Inst.Ref { const elem_type = try typeExpr(gz, scope, ptr_info.ast.child_type); @@ -2788,7 +2788,7 @@ fn ptrType( return rvalue(gz, rl, result, node); } -fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { +fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) !Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; const node_datas = tree.nodes.items(.data); @@ -2808,13 +2808,13 @@ fn arrayType(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Z return rvalue(gz, rl, result, node); } -fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { +fn arrayTypeSentinel(gz: *GenZir, scope: *Scope, rl: ResultLoc, node: Ast.Node.Index) !Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); - const extra = tree.extraData(node_datas[node].rhs, ast.Node.ArrayTypeSentinel); + const extra = tree.extraData(node_datas[node].rhs, Ast.Node.ArrayTypeSentinel); const len_node = node_datas[node].lhs; if (node_tags[len_node] == .identifier and @@ -2870,9 +2870,9 @@ fn fnDecl( gz: *GenZir, scope: *Scope, wip_decls: *WipDecls, - decl_node: ast.Node.Index, - body_node: ast.Node.Index, - fn_proto: ast.full.FnProto, + decl_node: Ast.Node.Index, + body_node: Ast.Node.Index, + fn_proto: Ast.full.FnProto, ) InnerError!void { const gpa = astgen.gpa; const tree = astgen.tree; @@ -3135,8 +3135,8 @@ fn globalVarDecl( gz: *GenZir, scope: *Scope, wip_decls: *WipDecls, - node: ast.Node.Index, - var_decl: ast.full.VarDecl, + node: Ast.Node.Index, + var_decl: Ast.full.VarDecl, ) InnerError!void { const gpa = astgen.gpa; const tree = astgen.tree; @@ -3279,7 +3279,7 @@ fn comptimeDecl( gz: *GenZir, scope: *Scope, wip_decls: *WipDecls, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!void { const gpa = astgen.gpa; const tree = astgen.tree; @@ -3326,7 +3326,7 @@ fn usingnamespaceDecl( gz: *GenZir, scope: *Scope, wip_decls: *WipDecls, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!void { const gpa = astgen.gpa; const tree = astgen.tree; @@ -3377,7 +3377,7 @@ fn testDecl( gz: *GenZir, scope: *Scope, wip_decls: *WipDecls, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!void { const gpa = astgen.gpa; const tree = astgen.tree; @@ -3468,8 +3468,8 @@ fn testDecl( fn structDeclInner( gz: *GenZir, scope: *Scope, - node: ast.Node.Index, - container_decl: ast.full.ContainerDecl, + node: Ast.Node.Index, + container_decl: Ast.full.ContainerDecl, layout: std.builtin.TypeInfo.ContainerLayout, ) InnerError!Zir.Inst.Ref { if (container_decl.ast.members.len == 0) { @@ -3537,7 +3537,7 @@ fn structDeclInner( const body = node_datas[member_node].rhs; switch (node_tags[fn_proto]) { .fn_proto_simple => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(¶ms, fn_proto)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -3552,7 +3552,7 @@ fn structDeclInner( continue; }, .fn_proto_one => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(¶ms, fn_proto)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -3570,7 +3570,7 @@ fn structDeclInner( } }, .fn_proto_simple => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(¶ms, member_node)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -3585,7 +3585,7 @@ fn structDeclInner( continue; }, .fn_proto_one => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(¶ms, member_node)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -3750,10 +3750,10 @@ fn structDeclInner( fn unionDeclInner( gz: *GenZir, scope: *Scope, - node: ast.Node.Index, - members: []const ast.Node.Index, + node: Ast.Node.Index, + members: []const Ast.Node.Index, layout: std.builtin.TypeInfo.ContainerLayout, - arg_node: ast.Node.Index, + arg_node: Ast.Node.Index, have_auto_enum: bool, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; @@ -3812,7 +3812,7 @@ fn unionDeclInner( const body = node_datas[member_node].rhs; switch (node_tags[fn_proto]) { .fn_proto_simple => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(¶ms, fn_proto)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -3827,7 +3827,7 @@ fn unionDeclInner( continue; }, .fn_proto_one => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(¶ms, fn_proto)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -3845,7 +3845,7 @@ fn unionDeclInner( } }, .fn_proto_simple => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(¶ms, member_node)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -3860,7 +3860,7 @@ fn unionDeclInner( continue; }, .fn_proto_one => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(¶ms, member_node)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -4033,8 +4033,8 @@ fn containerDecl( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - container_decl: ast.full.ContainerDecl, + node: Ast.Node.Index, + container_decl: Ast.full.ContainerDecl, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; @@ -4084,7 +4084,7 @@ fn containerDecl( var values: usize = 0; var total_fields: usize = 0; var decls: usize = 0; - var nonexhaustive_node: ast.Node.Index = 0; + var nonexhaustive_node: Ast.Node.Index = 0; for (container_decl.ast.members) |member_node| { const member = switch (node_tags[member_node]) { .container_field_init => tree.containerFieldInit(member_node), @@ -4225,7 +4225,7 @@ fn containerDecl( const body = node_datas[member_node].rhs; switch (node_tags[fn_proto]) { .fn_proto_simple => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(¶ms, fn_proto)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -4240,7 +4240,7 @@ fn containerDecl( continue; }, .fn_proto_one => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(¶ms, fn_proto)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -4258,7 +4258,7 @@ fn containerDecl( } }, .fn_proto_simple => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(¶ms, member_node)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -4273,7 +4273,7 @@ fn containerDecl( continue; }, .fn_proto_one => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(¶ms, member_node)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -4441,7 +4441,7 @@ fn containerDecl( const body = node_datas[member_node].rhs; switch (node_tags[fn_proto]) { .fn_proto_simple => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoSimple(¶ms, fn_proto)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -4456,7 +4456,7 @@ fn containerDecl( continue; }, .fn_proto_one => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, body, tree.fnProtoOne(¶ms, fn_proto)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -4474,7 +4474,7 @@ fn containerDecl( } }, .fn_proto_simple => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoSimple(¶ms, member_node)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -4489,7 +4489,7 @@ fn containerDecl( continue; }, .fn_proto_one => { - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; astgen.fnDecl(gz, &namespace.base, &wip_decls, member_node, 0, tree.fnProtoOne(¶ms, member_node)) catch |err| switch (err) { error.OutOfMemory => return error.OutOfMemory, error.AnalysisFail => {}, @@ -4590,7 +4590,7 @@ fn containerDecl( } } -fn errorSetDecl(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn errorSetDecl(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; const tree = astgen.tree; @@ -4629,8 +4629,8 @@ fn tryExpr( parent_gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - operand_node: ast.Node.Index, + node: Ast.Node.Index, + operand_node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; @@ -4705,13 +4705,13 @@ fn orelseCatchExpr( parent_gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - lhs: ast.Node.Index, + node: Ast.Node.Index, + lhs: Ast.Node.Index, cond_op: Zir.Inst.Tag, unwrap_op: Zir.Inst.Tag, unwrap_code_op: Zir.Inst.Tag, - rhs: ast.Node.Index, - payload_token: ?ast.TokenIndex, + rhs: Ast.Node.Index, + payload_token: ?Ast.TokenIndex, ) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; const tree = astgen.tree; @@ -4796,7 +4796,7 @@ fn orelseCatchExpr( fn finishThenElseBlock( parent_gz: *GenZir, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, block_scope: *GenZir, then_scope: *GenZir, else_scope: *GenZir, @@ -4852,7 +4852,7 @@ fn finishThenElseBlock( /// tokens without allocating. /// OK in theory it could do it without allocating. This implementation /// allocates when the @"" form is used. -fn tokenIdentEql(astgen: *AstGen, token1: ast.TokenIndex, token2: ast.TokenIndex) !bool { +fn tokenIdentEql(astgen: *AstGen, token1: Ast.TokenIndex, token2: Ast.TokenIndex) !bool { const ident_name_1 = try astgen.identifierTokenString(token1); const ident_name_2 = try astgen.identifierTokenString(token2); return mem.eql(u8, ident_name_1, ident_name_2); @@ -4862,7 +4862,7 @@ fn fieldAccess( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; @@ -4889,7 +4889,7 @@ fn arrayAccess( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; @@ -4912,7 +4912,7 @@ fn simpleBinOp( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, op_inst_tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; @@ -4929,8 +4929,8 @@ fn simpleBinOp( fn simpleStrTok( gz: *GenZir, rl: ResultLoc, - ident_token: ast.TokenIndex, - node: ast.Node.Index, + ident_token: Ast.TokenIndex, + node: Ast.Node.Index, op_inst_tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; @@ -4943,7 +4943,7 @@ fn boolBinOp( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, zir_tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; @@ -4969,8 +4969,8 @@ fn ifExpr( parent_gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - if_full: ast.full.If, + node: Ast.Node.Index, + if_full: Ast.full.If, ) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; const tree = astgen.tree; @@ -5089,7 +5089,7 @@ fn ifExpr( const else_node = if_full.ast.else_expr; const else_info: struct { - src: ast.Node.Index, + src: Ast.Node.Index, result: Zir.Inst.Ref, } = if (else_node != 0) blk: { block_scope.break_count += 1; @@ -5215,8 +5215,8 @@ fn whileExpr( parent_gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - while_full: ast.full.While, + node: Ast.Node.Index, + while_full: Ast.full.While, ) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; const tree = astgen.tree; @@ -5368,7 +5368,7 @@ fn whileExpr( const else_node = while_full.ast.else_expr; const else_info: struct { - src: ast.Node.Index, + src: Ast.Node.Index, result: Zir.Inst.Ref, } = if (else_node != 0) blk: { loop_scope.break_count += 1; @@ -5435,8 +5435,8 @@ fn forExpr( parent_gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - for_full: ast.full.While, + node: Ast.Node.Index, + for_full: Ast.full.While, ) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; @@ -5577,7 +5577,7 @@ fn forExpr( const else_node = for_full.ast.else_expr; const else_info: struct { - src: ast.Node.Index, + src: Ast.Node.Index, result: Zir.Inst.Ref, } = if (else_node != 0) blk: { loop_scope.break_count += 1; @@ -5618,7 +5618,7 @@ fn switchExpr( parent_gz: *GenZir, scope: *Scope, rl: ResultLoc, - switch_node: ast.Node.Index, + switch_node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = parent_gz.astgen; const gpa = astgen.gpa; @@ -5628,7 +5628,7 @@ fn switchExpr( const main_tokens = tree.nodes.items(.main_token); const token_tags = tree.tokens.items(.tag); const operand_node = node_datas[switch_node].lhs; - const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange); + const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); const case_nodes = tree.extra_data[extra.start..extra.end]; // We perform two passes over the AST. This first pass is to collect information @@ -5638,9 +5638,9 @@ fn switchExpr( var scalar_cases_len: u32 = 0; var multi_cases_len: u32 = 0; var special_prong: Zir.SpecialProng = .none; - var special_node: ast.Node.Index = 0; - var else_src: ?ast.TokenIndex = null; - var underscore_src: ?ast.TokenIndex = null; + var special_node: Ast.Node.Index = 0; + var else_src: ?Ast.TokenIndex = null; + var underscore_src: ?Ast.TokenIndex = null; for (case_nodes) |case_node| { const case = switch (node_tags[case_node]) { .switch_case_one => tree.switchCaseOne(case_node), @@ -6212,7 +6212,7 @@ fn switchExpr( } } -fn ret(gz: *GenZir, scope: *Scope, node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; const node_datas = tree.nodes.items(.data); @@ -6311,7 +6311,7 @@ fn identifier( gz: *GenZir, scope: *Scope, rl: ResultLoc, - ident: ast.Node.Index, + ident: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const tracy = trace(@src()); defer tracy.end(); @@ -6363,8 +6363,8 @@ fn identifier( // Local variables, including function parameters. const name_str_index = try astgen.identAsString(ident_token); var s = scope; - var found_already: ?ast.Node.Index = null; // we have found a decl with the same name already - var hit_namespace: ast.Node.Index = 0; + var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already + var hit_namespace: Ast.Node.Index = 0; while (true) switch (s.tag) { .local_val => { const local_val = s.cast(Scope.LocalVal).?; @@ -6434,7 +6434,7 @@ fn identifier( fn stringLiteral( gz: *GenZir, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; @@ -6454,7 +6454,7 @@ fn stringLiteral( fn multilineStringLiteral( gz: *GenZir, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const str = try astgen.strLitNodeAsString(node); @@ -6468,7 +6468,7 @@ fn multilineStringLiteral( return rvalue(gz, rl, result, node); } -fn charLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { +fn charLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) !Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); @@ -6547,7 +6547,7 @@ fn charLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) !Zir.Inst.Ref { } } -fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); @@ -6593,7 +6593,7 @@ fn integerLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) InnerError!Z return rvalue(gz, rl, result, node); } -fn floatLiteral(gz: *GenZir, rl: ResultLoc, node: ast.Node.Index) InnerError!Zir.Inst.Ref { +fn floatLiteral(gz: *GenZir, rl: ResultLoc, node: Ast.Node.Index) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; const main_tokens = tree.nodes.items(.main_token); @@ -6633,8 +6633,8 @@ fn asmExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - full: ast.full.Asm, + node: Ast.Node.Index, + full: Ast.full.Asm, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; @@ -6791,9 +6791,9 @@ fn as( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - lhs: ast.Node.Index, - rhs: ast.Node.Index, + node: Ast.Node.Index, + lhs: Ast.Node.Index, + rhs: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const dest_type = try typeExpr(gz, scope, lhs); switch (rl) { @@ -6814,8 +6814,8 @@ fn unionInit( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - params: []const ast.Node.Index, + node: Ast.Node.Index, + params: []const Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const union_type = try typeExpr(gz, scope, params[0]); const field_name = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, params[1]); @@ -6840,9 +6840,9 @@ fn unionInit( fn unionInitRlPtr( parent_gz: *GenZir, scope: *Scope, - node: ast.Node.Index, + node: Ast.Node.Index, result_ptr: Zir.Inst.Ref, - expr_node: ast.Node.Index, + expr_node: Ast.Node.Index, union_type: Zir.Inst.Ref, field_name: Zir.Inst.Ref, ) InnerError!Zir.Inst.Ref { @@ -6859,9 +6859,9 @@ fn asRlPtr( parent_gz: *GenZir, scope: *Scope, rl: ResultLoc, - src_node: ast.Node.Index, + src_node: Ast.Node.Index, result_ptr: Zir.Inst.Ref, - operand_node: ast.Node.Index, + operand_node: Ast.Node.Index, dest_type: Zir.Inst.Ref, ) InnerError!Zir.Inst.Ref { // Detect whether this expr() call goes into rvalue() to store the result into the @@ -6899,9 +6899,9 @@ fn bitCast( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - lhs: ast.Node.Index, - rhs: ast.Node.Index, + node: Ast.Node.Index, + lhs: Ast.Node.Index, + rhs: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const dest_type = try typeExpr(gz, scope, lhs); @@ -6929,10 +6929,10 @@ fn bitCast( fn bitCastRlPtr( gz: *GenZir, scope: *Scope, - node: ast.Node.Index, + node: Ast.Node.Index, dest_type: Zir.Inst.Ref, result_ptr: Zir.Inst.Ref, - rhs: ast.Node.Index, + rhs: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const casted_result_ptr = try gz.addPlNode(.bitcast_result_ptr, node, Zir.Inst.Bin{ .lhs = dest_type, @@ -6945,8 +6945,8 @@ fn typeOf( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - params: []const ast.Node.Index, + node: Ast.Node.Index, + params: []const Ast.Node.Index, ) InnerError!Zir.Inst.Ref { if (params.len < 1) { return gz.astgen.failNode(node, "expected at least 1 argument, found 0", .{}); @@ -6970,8 +6970,8 @@ fn builtinCall( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - params: []const ast.Node.Index, + node: Ast.Node.Index, + params: []const Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const tree = astgen.tree; @@ -7463,7 +7463,7 @@ fn builtinCall( fn simpleNoOpVoid( gz: *GenZir, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { _ = try gz.addNode(tag, node); @@ -7474,9 +7474,9 @@ fn hasDeclOrField( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - lhs_node: ast.Node.Index, - rhs_node: ast.Node.Index, + node: Ast.Node.Index, + lhs_node: Ast.Node.Index, + rhs_node: Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const container_type = try typeExpr(gz, scope, lhs_node); @@ -7492,9 +7492,9 @@ fn typeCast( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - lhs_node: ast.Node.Index, - rhs_node: ast.Node.Index, + node: Ast.Node.Index, + lhs_node: Ast.Node.Index, + rhs_node: Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ @@ -7508,8 +7508,8 @@ fn simpleUnOpType( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - operand_node: ast.Node.Index, + node: Ast.Node.Index, + operand_node: Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const operand = try typeExpr(gz, scope, operand_node); @@ -7521,9 +7521,9 @@ fn simpleUnOp( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, + node: Ast.Node.Index, operand_rl: ResultLoc, - operand_node: ast.Node.Index, + operand_node: Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const operand = try expr(gz, scope, operand_rl, operand_node); @@ -7535,8 +7535,8 @@ fn cmpxchg( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - params: []const ast.Node.Index, + node: Ast.Node.Index, + params: []const Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const int_type = try typeExpr(gz, scope, params[0]); @@ -7565,9 +7565,9 @@ fn bitBuiltin( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - int_type_node: ast.Node.Index, - operand_node: ast.Node.Index, + node: Ast.Node.Index, + int_type_node: Ast.Node.Index, + operand_node: Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const int_type = try typeExpr(gz, scope, int_type_node); @@ -7580,9 +7580,9 @@ fn divBuiltin( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - lhs_node: ast.Node.Index, - rhs_node: ast.Node.Index, + node: Ast.Node.Index, + lhs_node: Ast.Node.Index, + rhs_node: Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const result = try gz.addPlNode(tag, node, Zir.Inst.Bin{ @@ -7596,8 +7596,8 @@ fn simpleCBuiltin( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - operand_node: ast.Node.Index, + node: Ast.Node.Index, + operand_node: Ast.Node.Index, tag: Zir.Inst.Extended, ) InnerError!Zir.Inst.Ref { const operand = try comptimeExpr(gz, scope, .{ .ty = .const_slice_u8_type }, operand_node); @@ -7612,9 +7612,9 @@ fn offsetOf( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - lhs_node: ast.Node.Index, - rhs_node: ast.Node.Index, + node: Ast.Node.Index, + lhs_node: Ast.Node.Index, + rhs_node: Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const type_inst = try typeExpr(gz, scope, lhs_node); @@ -7630,9 +7630,9 @@ fn shiftOp( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - lhs_node: ast.Node.Index, - rhs_node: ast.Node.Index, + node: Ast.Node.Index, + lhs_node: Ast.Node.Index, + rhs_node: Ast.Node.Index, tag: Zir.Inst.Tag, ) InnerError!Zir.Inst.Ref { const lhs = try expr(gz, scope, .none, lhs_node); @@ -7649,8 +7649,8 @@ fn cImport( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - body_node: ast.Node.Index, + node: Ast.Node.Index, + body_node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const gpa = astgen.gpa; @@ -7674,8 +7674,8 @@ fn overflowArithmetic( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - params: []const ast.Node.Index, + node: Ast.Node.Index, + params: []const Ast.Node.Index, tag: Zir.Inst.Extended, ) InnerError!Zir.Inst.Ref { const int_type = try typeExpr(gz, scope, params[0]); @@ -7722,8 +7722,8 @@ fn callExpr( gz: *GenZir, scope: *Scope, rl: ResultLoc, - node: ast.Node.Index, - call: ast.full.Call, + node: Ast.Node.Index, + call: Ast.full.Call, ) InnerError!Zir.Inst.Ref { const astgen = gz.astgen; const lhs = try expr(gz, scope, .none, call.ast.fn_expr); @@ -7812,7 +7812,7 @@ pub const simple_types = std.ComptimeStringMap(Zir.Inst.Ref, .{ .{ "void", .void_type }, }); -fn nodeMayNeedMemoryLocation(tree: *const ast.Tree, start_node: ast.Node.Index) bool { +fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index) bool { const node_tags = tree.nodes.items(.tag); const node_datas = tree.nodes.items(.data); const main_tokens = tree.nodes.items(.main_token); @@ -8021,7 +8021,7 @@ fn nodeMayNeedMemoryLocation(tree: *const ast.Tree, start_node: ast.Node.Index) } } -fn nodeMayEvalToError(tree: *const ast.Tree, start_node: ast.Node.Index) enum { never, always, maybe } { +fn nodeMayEvalToError(tree: *const Ast, start_node: Ast.Node.Index) enum { never, always, maybe } { const node_tags = tree.nodes.items(.tag); const node_datas = tree.nodes.items(.data); const main_tokens = tree.nodes.items(.main_token); @@ -8230,7 +8230,7 @@ fn nodeMayEvalToError(tree: *const ast.Tree, start_node: ast.Node.Index) enum { } } -fn nodeImpliesRuntimeBits(tree: *const ast.Tree, start_node: ast.Node.Index) bool { +fn nodeImpliesRuntimeBits(tree: *const Ast, start_node: Ast.Node.Index) bool { const node_tags = tree.nodes.items(.tag); const node_datas = tree.nodes.items(.data); @@ -8417,7 +8417,7 @@ fn rvalue( gz: *GenZir, rl: ResultLoc, result: Zir.Inst.Ref, - src_node: ast.Node.Index, + src_node: Ast.Node.Index, ) InnerError!Zir.Inst.Ref { if (gz.endsWithNoReturn()) return result; switch (rl) { @@ -8522,7 +8522,7 @@ fn rvalue( /// and allocates the result within `astgen.arena`. /// Otherwise, returns a reference to the source code bytes directly. /// See also `appendIdentStr` and `parseStrLit`. -fn identifierTokenString(astgen: *AstGen, token: ast.TokenIndex) InnerError![]const u8 { +fn identifierTokenString(astgen: *AstGen, token: Ast.TokenIndex) InnerError![]const u8 { const tree = astgen.tree; const token_tags = tree.tokens.items(.tag); assert(token_tags[token] == .identifier); @@ -8542,7 +8542,7 @@ fn identifierTokenString(astgen: *AstGen, token: ast.TokenIndex) InnerError![]co /// See also `identifierTokenString` and `parseStrLit`. fn appendIdentStr( astgen: *AstGen, - token: ast.TokenIndex, + token: Ast.TokenIndex, buf: *ArrayListUnmanaged(u8), ) InnerError!void { const tree = astgen.tree; @@ -8559,7 +8559,7 @@ fn appendIdentStr( /// Appends the result to `buf`. fn parseStrLit( astgen: *AstGen, - token: ast.TokenIndex, + token: Ast.TokenIndex, buf: *ArrayListUnmanaged(u8), bytes: []const u8, offset: u32, @@ -8623,7 +8623,7 @@ fn parseStrLit( fn failNode( astgen: *AstGen, - node: ast.Node.Index, + node: Ast.Node.Index, comptime format: []const u8, args: anytype, ) InnerError { @@ -8632,7 +8632,7 @@ fn failNode( fn failNodeNotes( astgen: *AstGen, - node: ast.Node.Index, + node: Ast.Node.Index, comptime format: []const u8, args: anytype, notes: []const u32, @@ -8664,7 +8664,7 @@ fn failNodeNotes( fn failTok( astgen: *AstGen, - token: ast.TokenIndex, + token: Ast.TokenIndex, comptime format: []const u8, args: anytype, ) InnerError { @@ -8673,7 +8673,7 @@ fn failTok( fn failTokNotes( astgen: *AstGen, - token: ast.TokenIndex, + token: Ast.TokenIndex, comptime format: []const u8, args: anytype, notes: []const u32, @@ -8706,7 +8706,7 @@ fn failTokNotes( /// Same as `fail`, except given an absolute byte offset. fn failOff( astgen: *AstGen, - token: ast.TokenIndex, + token: Ast.TokenIndex, byte_offset: u32, comptime format: []const u8, args: anytype, @@ -8731,7 +8731,7 @@ fn failOff( fn errNoteTok( astgen: *AstGen, - token: ast.TokenIndex, + token: Ast.TokenIndex, comptime format: []const u8, args: anytype, ) Allocator.Error!u32 { @@ -8754,7 +8754,7 @@ fn errNoteTok( fn errNoteNode( astgen: *AstGen, - node: ast.Node.Index, + node: Ast.Node.Index, comptime format: []const u8, args: anytype, ) Allocator.Error!u32 { @@ -8775,7 +8775,7 @@ fn errNoteNode( }); } -fn identAsString(astgen: *AstGen, ident_token: ast.TokenIndex) !u32 { +fn identAsString(astgen: *AstGen, ident_token: Ast.TokenIndex) !u32 { const gpa = astgen.gpa; const string_bytes = &astgen.string_bytes; const str_index = @intCast(u32, string_bytes.items.len); @@ -8798,7 +8798,7 @@ fn identAsString(astgen: *AstGen, ident_token: ast.TokenIndex) !u32 { const IndexSlice = struct { index: u32, len: u32 }; -fn strLitAsString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !IndexSlice { +fn strLitAsString(astgen: *AstGen, str_lit_token: Ast.TokenIndex) !IndexSlice { const gpa = astgen.gpa; const string_bytes = &astgen.string_bytes; const str_index = @intCast(u32, string_bytes.items.len); @@ -8829,7 +8829,7 @@ fn strLitAsString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !IndexSlice { } } -fn strLitNodeAsString(astgen: *AstGen, node: ast.Node.Index) !IndexSlice { +fn strLitNodeAsString(astgen: *AstGen, node: Ast.Node.Index) !IndexSlice { const tree = astgen.tree; const node_datas = tree.nodes.items(.data); @@ -8864,7 +8864,7 @@ fn strLitNodeAsString(astgen: *AstGen, node: ast.Node.Index) !IndexSlice { }; } -fn testNameString(astgen: *AstGen, str_lit_token: ast.TokenIndex) !u32 { +fn testNameString(astgen: *AstGen, str_lit_token: Ast.TokenIndex) !u32 { const gpa = astgen.gpa; const string_bytes = &astgen.string_bytes; const str_index = @intCast(u32, string_bytes.items.len); @@ -8921,7 +8921,7 @@ const Scope = struct { gen_zir: *GenZir, inst: Zir.Inst.Ref, /// Source location of the corresponding variable declaration. - token_src: ast.TokenIndex, + token_src: Ast.TokenIndex, /// String table index. name: u32, id_cat: IdCat, @@ -8940,7 +8940,7 @@ const Scope = struct { gen_zir: *GenZir, ptr: Zir.Inst.Ref, /// Source location of the corresponding variable declaration. - token_src: ast.TokenIndex, + token_src: Ast.TokenIndex, /// String table index. name: u32, id_cat: IdCat, @@ -8955,7 +8955,7 @@ const Scope = struct { base: Scope, /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`, `Defer`. parent: *Scope, - defer_node: ast.Node.Index, + defer_node: Ast.Node.Index, }; /// Represents a global scope that has any number of declarations in it. @@ -8967,8 +8967,8 @@ const Scope = struct { parent: *Scope, /// Maps string table index to the source location of declaration, /// for the purposes of reporting name shadowing compile errors. - decls: std.AutoHashMapUnmanaged(u32, ast.Node.Index) = .{}, - node: ast.Node.Index, + decls: std.AutoHashMapUnmanaged(u32, Ast.Node.Index) = .{}, + node: Ast.Node.Index, }; const Top = struct { @@ -8987,7 +8987,7 @@ const GenZir = struct { /// How decls created in this scope should be named. anon_name_strategy: Zir.Inst.NameStrategy = .anon, /// The containing decl AST node. - decl_node_index: ast.Node.Index, + decl_node_index: Ast.Node.Index, /// The containing decl line index, absolute. decl_line: u32, parent: *Scope, @@ -9022,8 +9022,8 @@ const GenZir = struct { /// a result location pointer. labeled_store_to_block_ptr_list: ArrayListUnmanaged(Zir.Inst.Index) = .{}, - suspend_node: ast.Node.Index = 0, - nosuspend_node: ast.Node.Index = 0, + suspend_node: Ast.Node.Index = 0, + nosuspend_node: Ast.Node.Index = 0, fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir { return .{ @@ -9039,7 +9039,7 @@ const GenZir = struct { } const Label = struct { - token: ast.TokenIndex, + token: Ast.TokenIndex, block_inst: Zir.Inst.Index, used: bool = false, }; @@ -9060,7 +9060,7 @@ const GenZir = struct { return false; } - fn calcLine(gz: GenZir, node: ast.Node.Index) u32 { + fn calcLine(gz: GenZir, node: Ast.Node.Index) u32 { const astgen = gz.astgen; const tree = astgen.tree; const source = tree.source; @@ -9072,15 +9072,15 @@ const GenZir = struct { return @intCast(u32, gz.decl_line + astgen.source_line); } - fn nodeIndexToRelative(gz: GenZir, node_index: ast.Node.Index) i32 { + fn nodeIndexToRelative(gz: GenZir, node_index: Ast.Node.Index) i32 { return @bitCast(i32, node_index) - @bitCast(i32, gz.decl_node_index); } - fn tokenIndexToRelative(gz: GenZir, token: ast.TokenIndex) u32 { + fn tokenIndexToRelative(gz: GenZir, token: Ast.TokenIndex) u32 { return token - gz.srcToken(); } - fn srcToken(gz: GenZir) ast.TokenIndex { + fn srcToken(gz: GenZir) Ast.TokenIndex { return gz.astgen.tree.firstToken(gz.decl_node_index); } @@ -9165,7 +9165,7 @@ const GenZir = struct { } fn addFunc(gz: *GenZir, args: struct { - src_node: ast.Node.Index, + src_node: Ast.Node.Index, body: []const Zir.Inst.Index, param_block: Zir.Inst.Index, ret_ty: []const Zir.Inst.Index, @@ -9358,7 +9358,7 @@ const GenZir = struct { callee: Zir.Inst.Ref, args: []const Zir.Inst.Ref, /// Absolute node index. This function does the conversion to offset from Decl. - src_node: ast.Node.Index, + src_node: Ast.Node.Index, ) !Zir.Inst.Ref { assert(callee != .none); assert(src_node != 0); @@ -9449,7 +9449,7 @@ const GenZir = struct { tag: Zir.Inst.Tag, operand: Zir.Inst.Ref, /// Absolute node index. This function does the conversion to offset from Decl. - src_node: ast.Node.Index, + src_node: Ast.Node.Index, ) !Zir.Inst.Ref { assert(operand != .none); return gz.add(.{ @@ -9465,7 +9465,7 @@ const GenZir = struct { gz: *GenZir, tag: Zir.Inst.Tag, /// Absolute node index. This function does the conversion to offset from Decl. - src_node: ast.Node.Index, + src_node: Ast.Node.Index, extra: anytype, ) !Zir.Inst.Ref { const gpa = gz.astgen.gpa; @@ -9489,7 +9489,7 @@ const GenZir = struct { gz: *GenZir, tag: Zir.Inst.Tag, /// Absolute token index. This function does the conversion to Decl offset. - abs_tok_index: ast.TokenIndex, + abs_tok_index: Ast.TokenIndex, name: u32, body: []const u32, ) !Zir.Inst.Index { @@ -9544,7 +9544,7 @@ const GenZir = struct { fn addExtendedMultiOp( gz: *GenZir, opcode: Zir.Inst.Extended, - node: ast.Node.Index, + node: Ast.Node.Index, operands: []const Zir.Inst.Ref, ) !Zir.Inst.Ref { const astgen = gz.astgen; @@ -9605,7 +9605,7 @@ const GenZir = struct { tag: Zir.Inst.Tag, operand: Zir.Inst.Ref, /// Absolute token index. This function does the conversion to Decl offset. - abs_tok_index: ast.TokenIndex, + abs_tok_index: Ast.TokenIndex, ) !Zir.Inst.Ref { assert(operand != .none); return gz.add(.{ @@ -9622,7 +9622,7 @@ const GenZir = struct { tag: Zir.Inst.Tag, str_index: u32, /// Absolute token index. This function does the conversion to Decl offset. - abs_tok_index: ast.TokenIndex, + abs_tok_index: Ast.TokenIndex, ) !Zir.Inst.Ref { return gz.add(.{ .tag = tag, @@ -9669,7 +9669,7 @@ const GenZir = struct { gz: *GenZir, tag: Zir.Inst.Tag, decl_index: u32, - src_node: ast.Node.Index, + src_node: Ast.Node.Index, ) !Zir.Inst.Ref { return gz.add(.{ .tag = tag, @@ -9684,7 +9684,7 @@ const GenZir = struct { gz: *GenZir, tag: Zir.Inst.Tag, /// Absolute node index. This function does the conversion to offset from Decl. - src_node: ast.Node.Index, + src_node: Ast.Node.Index, ) !Zir.Inst.Ref { return gz.add(.{ .tag = tag, @@ -9696,7 +9696,7 @@ const GenZir = struct { gz: *GenZir, opcode: Zir.Inst.Extended, /// Absolute node index. This function does the conversion to offset from Decl. - src_node: ast.Node.Index, + src_node: Ast.Node.Index, ) !Zir.Inst.Ref { return gz.add(.{ .tag = .extended, @@ -9712,7 +9712,7 @@ const GenZir = struct { gz: *GenZir, args: struct { /// Absolute node index. This function does the conversion to offset from Decl. - node: ast.Node.Index, + node: Ast.Node.Index, type_inst: Zir.Inst.Ref, align_inst: Zir.Inst.Ref, is_const: bool, @@ -9763,7 +9763,7 @@ const GenZir = struct { gz: *GenZir, args: struct { /// Absolute node index. This function does the conversion to offset from Decl. - node: ast.Node.Index, + node: Ast.Node.Index, asm_source: u32, output_type_bits: u32, is_volatile: bool, @@ -9820,7 +9820,7 @@ const GenZir = struct { /// Note that this returns a `Zir.Inst.Index` not a ref. /// Does *not* append the block instruction to the scope. /// Leaves the `payload_index` field undefined. - fn addBlock(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index { + fn addBlock(gz: *GenZir, tag: Zir.Inst.Tag, node: Ast.Node.Index) !Zir.Inst.Index { const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); const gpa = gz.astgen.gpa; try gz.astgen.instructions.append(gpa, .{ @@ -9835,7 +9835,7 @@ const GenZir = struct { /// Note that this returns a `Zir.Inst.Index` not a ref. /// Leaves the `payload_index` field undefined. - fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: ast.Node.Index) !Zir.Inst.Index { + fn addCondBr(gz: *GenZir, tag: Zir.Inst.Tag, node: Ast.Node.Index) !Zir.Inst.Index { const gpa = gz.astgen.gpa; try gz.instructions.ensureUnusedCapacity(gpa, 1); const new_index = @intCast(Zir.Inst.Index, gz.astgen.instructions.len); @@ -9851,7 +9851,7 @@ const GenZir = struct { } fn setStruct(gz: *GenZir, inst: Zir.Inst.Index, args: struct { - src_node: ast.Node.Index, + src_node: Ast.Node.Index, body_len: u32, fields_len: u32, decls_len: u32, @@ -9896,7 +9896,7 @@ const GenZir = struct { } fn setUnion(gz: *GenZir, inst: Zir.Inst.Index, args: struct { - src_node: ast.Node.Index, + src_node: Ast.Node.Index, tag_type: Zir.Inst.Ref, body_len: u32, fields_len: u32, @@ -9946,7 +9946,7 @@ const GenZir = struct { } fn setEnum(gz: *GenZir, inst: Zir.Inst.Index, args: struct { - src_node: ast.Node.Index, + src_node: Ast.Node.Index, tag_type: Zir.Inst.Ref, body_len: u32, fields_len: u32, @@ -10019,7 +10019,7 @@ const GenZir = struct { return new_index; } - fn addRet(gz: *GenZir, rl: ResultLoc, operand: Zir.Inst.Ref, node: ast.Node.Index) !void { + fn addRet(gz: *GenZir, rl: ResultLoc, operand: Zir.Inst.Ref, node: Ast.Node.Index) !void { switch (rl) { .ptr => |ret_ptr| _ = try gz.addUnNode(.ret_load, ret_ptr, node), .ty => _ = try gz.addUnNode(.ret_node, operand, node), @@ -10052,7 +10052,7 @@ fn detectLocalShadowing( astgen: *AstGen, scope: *Scope, ident_name: u32, - name_token: ast.TokenIndex, + name_token: Ast.TokenIndex, token_bytes: []const u8, ) !void { const gpa = astgen.gpa; @@ -10157,7 +10157,7 @@ fn refToIndex(inst: Zir.Inst.Ref) ?Zir.Inst.Index { } } -fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const ast.Node.Index) !void { +fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast.Node.Index) !void { const gpa = astgen.gpa; const tree = astgen.tree; const node_tags = tree.nodes.items(.tag); diff --git a/src/Compilation.zig b/src/Compilation.zig index 7dc726aeb2..7ac75130f2 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -2408,7 +2408,7 @@ const AstGenSrc = union(enum) { root, import: struct { importing_file: *Module.Scope.File, - import_tok: std.zig.ast.TokenIndex, + import_tok: std.zig.Ast.TokenIndex, }, }; diff --git a/src/Module.zig b/src/Module.zig index c17780cdc3..07b86c0d51 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -11,7 +11,7 @@ const log = std.log.scoped(.module); const BigIntConst = std.math.big.int.Const; const BigIntMutable = std.math.big.int.Mutable; const Target = std.Target; -const ast = std.zig.ast; +const Ast = std.zig.Ast; const Module = @This(); const Compilation = @import("Compilation.zig"); @@ -291,7 +291,7 @@ pub const Decl = struct { generation: u32, /// The AST node index of this declaration. /// Must be recomputed when the corresponding source file is modified. - src_node: ast.Node.Index, + src_node: Ast.Node.Index, /// Line number corresponding to `src_node`. Stored separately so that source files /// do not need to be loaded into memory in order to compute debug line numbers. src_line: u32, @@ -499,19 +499,19 @@ pub const Decl = struct { return decl.src_line + offset; } - pub fn relativeToNodeIndex(decl: Decl, offset: i32) ast.Node.Index { - return @bitCast(ast.Node.Index, offset + @bitCast(i32, decl.src_node)); + pub fn relativeToNodeIndex(decl: Decl, offset: i32) Ast.Node.Index { + return @bitCast(Ast.Node.Index, offset + @bitCast(i32, decl.src_node)); } - pub fn nodeIndexToRelative(decl: Decl, node_index: ast.Node.Index) i32 { + pub fn nodeIndexToRelative(decl: Decl, node_index: Ast.Node.Index) i32 { return @bitCast(i32, node_index) - @bitCast(i32, decl.src_node); } - pub fn tokSrcLoc(decl: Decl, token_index: ast.TokenIndex) LazySrcLoc { + pub fn tokSrcLoc(decl: Decl, token_index: Ast.TokenIndex) LazySrcLoc { return .{ .token_offset = token_index - decl.srcToken() }; } - pub fn nodeSrcLoc(decl: Decl, node_index: ast.Node.Index) LazySrcLoc { + pub fn nodeSrcLoc(decl: Decl, node_index: Ast.Node.Index) LazySrcLoc { return .{ .node_offset = decl.nodeIndexToRelative(node_index) }; } @@ -527,7 +527,7 @@ pub const Decl = struct { }; } - pub fn srcToken(decl: Decl) ast.TokenIndex { + pub fn srcToken(decl: Decl) Ast.TokenIndex { const tree = &decl.namespace.file_scope.tree; return tree.firstToken(decl.src_node); } @@ -1121,7 +1121,7 @@ pub const Scope = struct { /// Whether this is populated depends on `status`. stat_mtime: i128, /// Whether this is populated or not depends on `tree_loaded`. - tree: ast.Tree, + tree: Ast, /// Whether this is populated or not depends on `zir_loaded`. zir: Zir, /// Package that this file is a part of, managed externally. @@ -1220,7 +1220,7 @@ pub const Scope = struct { return source; } - pub fn getTree(file: *File, gpa: *Allocator) !*const ast.Tree { + pub fn getTree(file: *File, gpa: *Allocator) !*const Ast { if (file.tree_loaded) return &file.tree; const source = try file.getSource(gpa); @@ -1565,17 +1565,17 @@ pub const ErrorMsg = struct { pub const SrcLoc = struct { file_scope: *Scope.File, /// Might be 0 depending on tag of `lazy`. - parent_decl_node: ast.Node.Index, + parent_decl_node: Ast.Node.Index, /// Relative to `parent_decl_node`. lazy: LazySrcLoc, - pub fn declSrcToken(src_loc: SrcLoc) ast.TokenIndex { + pub fn declSrcToken(src_loc: SrcLoc) Ast.TokenIndex { const tree = src_loc.file_scope.tree; return tree.firstToken(src_loc.parent_decl_node); } - pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) ast.TokenIndex { - return @bitCast(ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node)); + pub fn declRelativeToNodeIndex(src_loc: SrcLoc, offset: i32) Ast.TokenIndex { + return @bitCast(Ast.Node.Index, offset + @bitCast(i32, src_loc.parent_decl_node)); } pub fn byteOffset(src_loc: SrcLoc, gpa: *Allocator) !u32 { @@ -1701,7 +1701,7 @@ pub const SrcLoc = struct { const tree = try src_loc.file_scope.getTree(gpa); const node_tags = tree.nodes.items(.tag); const node = src_loc.declRelativeToNodeIndex(node_off); - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; const full = switch (node_tags[node]) { .call_one, .call_one_comma, @@ -1831,7 +1831,7 @@ pub const SrcLoc = struct { const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); - const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange); + const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); const case_nodes = tree.extra_data[extra.start..extra.end]; for (case_nodes) |case_node| { const case = switch (node_tags[case_node]) { @@ -1857,7 +1857,7 @@ pub const SrcLoc = struct { const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); - const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange); + const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); const case_nodes = tree.extra_data[extra.start..extra.end]; for (case_nodes) |case_node| { const case = switch (node_tags[case_node]) { @@ -1886,7 +1886,7 @@ pub const SrcLoc = struct { const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); const node = src_loc.declRelativeToNodeIndex(node_off); - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; const full = switch (node_tags[node]) { .fn_proto_simple => tree.fnProtoSimple(¶ms, node), .fn_proto_multi => tree.fnProtoMulti(node), @@ -1911,7 +1911,7 @@ pub const SrcLoc = struct { const tree = try src_loc.file_scope.getTree(gpa); const node_tags = tree.nodes.items(.tag); const node = src_loc.declRelativeToNodeIndex(node_off); - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; const full = switch (node_tags[node]) { .fn_proto_simple => tree.fnProtoSimple(¶ms, node), .fn_proto_multi => tree.fnProtoMulti(node), @@ -1941,7 +1941,7 @@ pub const SrcLoc = struct { const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); const parent_node = src_loc.declRelativeToNodeIndex(node_off); - var params: [1]ast.Node.Index = undefined; + var params: [1]Ast.Node.Index = undefined; const full = switch (node_tags[parent_node]) { .fn_proto_simple => tree.fnProtoSimple(¶ms, parent_node), .fn_proto_multi => tree.fnProtoMulti(parent_node), @@ -3967,7 +3967,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void { decl.analysis = .outdated; } -pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: ast.Node.Index) !*Decl { +pub fn allocateNewDecl(mod: *Module, namespace: *Scope.Namespace, src_node: Ast.Node.Index) !*Decl { // If we have emit-h then we must allocate a bigger structure to store the emit-h state. const new_decl: *Decl = if (mod.emit_h != null) blk: { const parent_struct = try mod.gpa.create(DeclPlusEmitH); @@ -4237,7 +4237,7 @@ pub fn fail( pub fn failTok( mod: *Module, scope: *Scope, - token_index: ast.TokenIndex, + token_index: Ast.TokenIndex, comptime format: []const u8, args: anytype, ) CompileError { @@ -4250,7 +4250,7 @@ pub fn failTok( pub fn failNode( mod: *Module, scope: *Scope, - node_index: ast.Node.Index, + node_index: Ast.Node.Index, comptime format: []const u8, args: anytype, ) CompileError { @@ -4455,7 +4455,7 @@ pub const SwitchProngSrc = union(enum) { const main_tokens = tree.nodes.items(.main_token); const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const extra = tree.extraData(node_datas[switch_node].rhs, ast.Node.SubRange); + const extra = tree.extraData(node_datas[switch_node].rhs, Ast.Node.SubRange); const case_nodes = tree.extra_data[extra.start..extra.end]; var multi_i: u32 = 0; diff --git a/src/Sema.zig b/src/Sema.zig index b3eb3b1b85..46c1f1122e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -10177,7 +10177,7 @@ fn typeHasOnePossibleValue( }; } -fn getAstTree(sema: *Sema, block: *Scope.Block) CompileError!*const std.zig.ast.Tree { +fn getAstTree(sema: *Sema, block: *Scope.Block) CompileError!*const std.zig.Ast { return block.src_decl.namespace.file_scope.getTree(sema.gpa) catch |err| { log.err("unable to load AST to report compile error: {s}", .{@errorName(err)}); return error.AnalysisFail; @@ -10186,14 +10186,14 @@ fn getAstTree(sema: *Sema, block: *Scope.Block) CompileError!*const std.zig.ast. fn enumFieldSrcLoc( decl: *Decl, - tree: std.zig.ast.Tree, + tree: std.zig.Ast, node_offset: i32, field_index: usize, ) LazySrcLoc { @setCold(true); const enum_node = decl.relativeToNodeIndex(node_offset); const node_tags = tree.nodes.items(.tag); - var buffer: [2]std.zig.ast.Node.Index = undefined; + var buffer: [2]std.zig.Ast.Node.Index = undefined; const container_decl = switch (node_tags[enum_node]) { .container_decl, .container_decl_trailing, diff --git a/src/Zir.zig b/src/Zir.zig index e8e79fe1b5..329dbcef51 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -16,7 +16,7 @@ const Allocator = std.mem.Allocator; const assert = std.debug.assert; const BigIntConst = std.math.big.int.Const; const BigIntMutable = std.math.big.int.Mutable; -const ast = std.zig.ast; +const Ast = std.zig.Ast; const Zir = @This(); const Type = @import("type.zig").Type; @@ -2092,7 +2092,7 @@ pub const Inst = struct { /// Used for unary operators, with a token source location. un_tok: struct { /// Offset from Decl AST token index. - src_tok: ast.TokenIndex, + src_tok: Ast.TokenIndex, /// The meaning of this operand depends on the corresponding `Tag`. operand: Ref, @@ -2114,7 +2114,7 @@ pub const Inst = struct { }, pl_tok: struct { /// Offset from Decl AST token index. - src_tok: ast.TokenIndex, + src_tok: Ast.TokenIndex, /// index into extra. /// `Tag` determines what lives there. payload_index: u32, @@ -2150,7 +2150,7 @@ pub const Inst = struct { } }, /// Offset from Decl AST token index. - tok: ast.TokenIndex, + tok: Ast.TokenIndex, /// Offset from Decl AST node index. node: i32, int: u64, @@ -2878,9 +2878,9 @@ pub const Inst = struct { pub const Item = struct { /// null terminated string index msg: u32, - node: ast.Node.Index, + node: Ast.Node.Index, /// If node is 0 then this will be populated. - token: ast.TokenIndex, + token: Ast.TokenIndex, /// Can be used in combination with `token`. byte_offset: u32, /// 0 or a payload index of a `Block`, each is a payload @@ -2897,7 +2897,7 @@ pub const Inst = struct { /// null terminated string index name: u32, /// points to the import name - token: ast.TokenIndex, + token: Ast.TokenIndex, }; }; }; @@ -2912,8 +2912,8 @@ const Writer = struct { indent: u32, parent_decl_node: u32, - fn relativeToNodeIndex(self: *Writer, offset: i32) ast.Node.Index { - return @bitCast(ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node)); + fn relativeToNodeIndex(self: *Writer, offset: i32) Ast.Node.Index { + return @bitCast(Ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node)); } fn writeInstToStream( diff --git a/src/main.zig b/src/main.zig index f76128db74..0e075ff40f 100644 --- a/src/main.zig +++ b/src/main.zig @@ -6,7 +6,7 @@ const mem = std.mem; const process = std.process; const Allocator = mem.Allocator; const ArrayList = std.ArrayList; -const ast = std.zig.ast; +const Ast = std.zig.Ast; const warn = std.log.warn; const Compilation = @import("Compilation.zig"); @@ -3423,8 +3423,8 @@ fn fmtPathFile( fn printErrMsgToStdErr( gpa: *mem.Allocator, arena: *mem.Allocator, - parse_error: ast.Error, - tree: ast.Tree, + parse_error: Ast.Error, + tree: Ast, path: []const u8, color: Color, ) !void { @@ -4029,12 +4029,12 @@ pub fn cmdAstCheck( } { - const token_bytes = @sizeOf(std.zig.ast.TokenList) + - file.tree.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(std.zig.ast.ByteOffset)); - const tree_bytes = @sizeOf(std.zig.ast.Tree) + file.tree.nodes.len * - (@sizeOf(std.zig.ast.Node.Tag) + - @sizeOf(std.zig.ast.Node.Data) + - @sizeOf(std.zig.ast.TokenIndex)); + const token_bytes = @sizeOf(Ast.TokenList) + + file.tree.tokens.len * (@sizeOf(std.zig.Token.Tag) + @sizeOf(Ast.ByteOffset)); + const tree_bytes = @sizeOf(Ast) + file.tree.nodes.len * + (@sizeOf(Ast.Node.Tag) + + @sizeOf(Ast.Node.Data) + + @sizeOf(Ast.TokenIndex)); const instruction_bytes = file.zir.instructions.len * // Here we don't use @sizeOf(Zir.Inst.Data) because it would include // the debug safety tag but we want to measure release size. diff --git a/src/translate_c.zig b/src/translate_c.zig index 6b7165176b..c3325b569d 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -356,7 +356,7 @@ pub fn translate( args_end: [*]?[*]const u8, errors: *[]ClangErrMsg, resources_path: [*:0]const u8, -) !std.zig.ast.Tree { +) !std.zig.Ast { const ast_unit = clang.LoadFromCommandLine( args_begin, args_end, @@ -369,7 +369,7 @@ pub fn translate( }; defer ast_unit.delete(); - // For memory that has the same lifetime as the Tree that we return + // For memory that has the same lifetime as the Ast that we return // from this function. var arena = std.heap.ArenaAllocator.init(gpa); errdefer arena.deinit(); diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 01f7d24d04..a77334e7d1 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -714,9 +714,9 @@ pub const Payload = struct { }; }; -/// Converts the nodes into a Zig ast. +/// Converts the nodes into a Zig Ast. /// Caller must free the source slice. -pub fn render(gpa: *Allocator, nodes: []const Node) !std.zig.ast.Tree { +pub fn render(gpa: *Allocator, nodes: []const Node) !std.zig.Ast { var ctx = Context{ .gpa = gpa, .buf = std.ArrayList(u8).init(gpa), @@ -767,7 +767,7 @@ pub fn render(gpa: *Allocator, nodes: []const Node) !std.zig.ast.Tree { .start = @intCast(u32, ctx.buf.items.len), }); - return std.zig.ast.Tree{ + return std.zig.Ast{ .source = try ctx.buf.toOwnedSliceSentinel(0), .tokens = ctx.tokens.toOwnedSlice(), .nodes = ctx.nodes.toOwnedSlice(), @@ -776,17 +776,17 @@ pub fn render(gpa: *Allocator, nodes: []const Node) !std.zig.ast.Tree { }; } -const NodeIndex = std.zig.ast.Node.Index; -const NodeSubRange = std.zig.ast.Node.SubRange; -const TokenIndex = std.zig.ast.TokenIndex; +const NodeIndex = std.zig.Ast.Node.Index; +const NodeSubRange = std.zig.Ast.Node.SubRange; +const TokenIndex = std.zig.Ast.TokenIndex; const TokenTag = std.zig.Token.Tag; const Context = struct { gpa: *Allocator, buf: std.ArrayList(u8) = .{}, - nodes: std.zig.ast.NodeList = .{}, - extra_data: std.ArrayListUnmanaged(std.zig.ast.Node.Index) = .{}, - tokens: std.zig.ast.TokenList = .{}, + nodes: std.zig.Ast.NodeList = .{}, + extra_data: std.ArrayListUnmanaged(std.zig.Ast.Node.Index) = .{}, + tokens: std.zig.Ast.TokenList = .{}, fn addTokenFmt(c: *Context, tag: TokenTag, comptime format: []const u8, args: anytype) Allocator.Error!TokenIndex { const start_index = c.buf.items.len; @@ -831,7 +831,7 @@ const Context = struct { }; } - fn addNode(c: *Context, elem: std.zig.ast.NodeList.Elem) Allocator.Error!NodeIndex { + fn addNode(c: *Context, elem: std.zig.Ast.NodeList.Elem) Allocator.Error!NodeIndex { const result = @intCast(NodeIndex, c.nodes.len); try c.nodes.append(c.gpa, elem); return result; @@ -1166,7 +1166,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { .main_token = l_bracket, .data = .{ .lhs = string, - .rhs = try c.addExtra(std.zig.ast.Node.Slice{ + .rhs = try c.addExtra(std.zig.Ast.Node.Slice{ .start = start, .end = end, }), @@ -1601,7 +1601,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { .main_token = while_tok, .data = .{ .lhs = cond, - .rhs = try c.addExtra(std.zig.ast.Node.WhileCont{ + .rhs = try c.addExtra(std.zig.Ast.Node.WhileCont{ .cont_expr = cont_expr, .then_expr = body, }), @@ -1654,7 +1654,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { .main_token = if_tok, .data = .{ .lhs = cond, - .rhs = try c.addExtra(std.zig.ast.Node.If{ + .rhs = try c.addExtra(std.zig.Ast.Node.If{ .then_expr = then_expr, .else_expr = else_expr, }), @@ -2175,7 +2175,7 @@ fn renderNullSentinelArrayType(c: *Context, len: usize, elem_type: Node) !NodeIn .main_token = l_bracket, .data = .{ .lhs = len_expr, - .rhs = try c.addExtra(std.zig.ast.Node.ArrayTypeSentinel{ + .rhs = try c.addExtra(std.zig.Ast.Node.ArrayTypeSentinel{ .sentinel = sentinel_expr, .elem_type = elem_type_expr, }), @@ -2378,7 +2378,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { } } -fn renderPrefixOp(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex { +fn renderPrefixOp(c: *Context, node: Node, tag: std.zig.Ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex { const payload = @fieldParentPtr(Payload.UnOp, "base", node.ptr_otherwise).data; return c.addNode(.{ .tag = tag, @@ -2390,7 +2390,7 @@ fn renderPrefixOp(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: T }); } -fn renderBinOpGrouped(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex { +fn renderBinOpGrouped(c: *Context, node: Node, tag: std.zig.Ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex { const payload = @fieldParentPtr(Payload.BinOp, "base", node.ptr_otherwise).data; const lhs = try renderNodeGrouped(c, payload.lhs); return c.addNode(.{ @@ -2403,7 +2403,7 @@ fn renderBinOpGrouped(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_ta }); } -fn renderBinOp(c: *Context, node: Node, tag: std.zig.ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex { +fn renderBinOp(c: *Context, node: Node, tag: std.zig.Ast.Node.Tag, tok_tag: TokenTag, bytes: []const u8) !NodeIndex { const payload = @fieldParentPtr(Payload.BinOp, "base", node.ptr_otherwise).data; const lhs = try renderNode(c, payload.lhs); return c.addNode(.{ @@ -2604,7 +2604,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex { .tag = .local_var_decl, .main_token = mut_tok, .data = .{ - .lhs = try c.addExtra(std.zig.ast.Node.LocalVarDecl{ + .lhs = try c.addExtra(std.zig.Ast.Node.LocalVarDecl{ .type_node = type_node, .align_node = align_node, }), @@ -2617,7 +2617,7 @@ fn renderVar(c: *Context, node: Node) !NodeIndex { .tag = .global_var_decl, .main_token = mut_tok, .data = .{ - .lhs = try c.addExtra(std.zig.ast.Node.GlobalVarDecl{ + .lhs = try c.addExtra(std.zig.Ast.Node.GlobalVarDecl{ .type_node = type_node, .align_node = align_node, .section_node = section_node, @@ -2709,7 +2709,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex { .tag = .fn_proto_one, .main_token = fn_token, .data = .{ - .lhs = try c.addExtra(std.zig.ast.Node.FnProtoOne{ + .lhs = try c.addExtra(std.zig.Ast.Node.FnProtoOne{ .param = params.items[0], .align_expr = align_expr, .section_expr = section_expr, @@ -2723,7 +2723,7 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex { .tag = .fn_proto, .main_token = fn_token, .data = .{ - .lhs = try c.addExtra(std.zig.ast.Node.FnProto{ + .lhs = try c.addExtra(std.zig.Ast.Node.FnProto{ .params_start = span.start, .params_end = span.end, .align_expr = align_expr, @@ -2781,7 +2781,7 @@ fn renderMacroFunc(c: *Context, node: Node) !NodeIndex { .tag = .fn_proto_multi, .main_token = fn_token, .data = .{ - .lhs = try c.addExtra(std.zig.ast.Node.SubRange{ + .lhs = try c.addExtra(std.zig.Ast.Node.SubRange{ .start = span.start, .end = span.end, }), -- cgit v1.2.3