diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/AstGen.zig | 60 | ||||
| -rw-r--r-- | src/Compilation.zig | 69 | ||||
| -rw-r--r-- | src/Module.zig | 220 | ||||
| -rw-r--r-- | src/Sema.zig | 41 | ||||
| -rw-r--r-- | src/Zir.zig | 220 | ||||
| -rw-r--r-- | src/main.zig | 99 |
6 files changed, 446 insertions, 263 deletions
diff --git a/src/AstGen.zig b/src/AstGen.zig index 9e4b4cac0b..1091517494 100644 --- a/src/AstGen.zig +++ b/src/AstGen.zig @@ -96,14 +96,18 @@ pub fn generate(gpa: *Allocator, file: *Scope.File) InnerError!Zir { .arg = 0, }, }; - const struct_decl_ref = try AstGen.structDeclInner( + if (AstGen.structDeclInner( &gen_scope, &gen_scope.base, 0, container_decl, .struct_decl, - ); - astgen.extra.items[0] = @enumToInt(struct_decl_ref); + )) |struct_decl_ref| { + astgen.extra.items[0] = @enumToInt(struct_decl_ref); + } else |err| switch (err) { + error.OutOfMemory => return error.OutOfMemory, + error.AnalysisFail => {}, // Handled via compile_errors below. + } if (astgen.compile_errors.items.len == 0) { astgen.extra.items[1] = 0; @@ -1272,8 +1276,6 @@ fn blockExprStmts( .cmp_gt, .cmp_neq, .coerce_result_ptr, - .decl_ref, - .decl_val, .decl_ref_named, .decl_val_named, .load, @@ -1381,6 +1383,10 @@ fn blockExprStmts( .type_info, .size_of, .bit_size_of, + .this, + .fence, + .ret_addr, + .builtin_src, => break :b false, // ZIR instructions that are always either `noreturn` or `void`. @@ -2385,13 +2391,16 @@ fn structDeclInner( const decl_inst = try gz.addBlock(tag, node); try gz.instructions.append(gpa, decl_inst); - _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); + if (field_index != 0) { + _ = try block_scope.addBreak(.break_inline, decl_inst, .void_value); + } try astgen.extra.ensureCapacity(gpa, astgen.extra.items.len + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len + - bit_bag.items.len + 1 + fields_data.items.len + + bit_bag.items.len + @boolToInt(field_index != 0) + fields_data.items.len + block_scope.instructions.items.len + - wip_decls.bit_bag.items.len + 1 + wip_decls.name_and_value.items.len); + wip_decls.bit_bag.items.len + @boolToInt(wip_decls.decl_index != 0) + + wip_decls.name_and_value.items.len); const zir_datas = astgen.instructions.items(.data); zir_datas[decl_inst].pl_node.payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.StructDecl{ .body_len = @intCast(u32, block_scope.instructions.items.len), @@ -2401,11 +2410,15 @@ fn structDeclInner( astgen.extra.appendSliceAssumeCapacity(block_scope.instructions.items); astgen.extra.appendSliceAssumeCapacity(bit_bag.items); // Likely empty. - astgen.extra.appendAssumeCapacity(cur_bit_bag); + if (field_index != 0) { + astgen.extra.appendAssumeCapacity(cur_bit_bag); + } astgen.extra.appendSliceAssumeCapacity(fields_data.items); astgen.extra.appendSliceAssumeCapacity(wip_decls.bit_bag.items); // Likely empty. - astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); + if (wip_decls.decl_index != 0) { + astgen.extra.appendAssumeCapacity(wip_decls.cur_bit_bag); + } astgen.extra.appendSliceAssumeCapacity(wip_decls.name_and_value.items); return gz.indexToRef(decl_inst); @@ -4750,6 +4763,11 @@ fn builtinCall( return rvalue(gz, scope, rl, result, node); }, + .This => return rvalue(gz, scope, rl, try gz.addNode(.this, node), node), + .fence => return rvalue(gz, scope, rl, try gz.addNode(.fence, node), node), + .return_address => return rvalue(gz, scope, rl, try gz.addNode(.ret_addr, node), node), + .src => return rvalue(gz, scope, rl, try gz.addNode(.builtin_src, node), node), + .add_with_overflow, .align_cast, .align_of, @@ -4778,7 +4796,6 @@ fn builtinCall( .error_name, .error_return_trace, .err_set_cast, - .fence, .field_parent_ptr, .float_to_int, .has_field, @@ -4794,7 +4811,6 @@ fn builtinCall( .pop_count, .ptr_cast, .rem, - .return_address, .set_align_stack, .set_cold, .set_float_mode, @@ -4805,7 +4821,6 @@ fn builtinCall( .shuffle, .splat, .reduce, - .src, .sqrt, .sin, .cos, @@ -4821,21 +4836,18 @@ fn builtinCall( .round, .sub_with_overflow, .tag_name, - .This, .truncate, .Type, .type_name, .union_init, - => return astgen.failNode(node, "TODO: implement builtin function {s}", .{ - builtin_name, - }), - .async_call, .frame, .Frame, .frame_address, .frame_size, - => return astgen.failNode(node, "async and related features are not yet supported", .{}), + => return astgen.failNode(node, "TODO: implement builtin function {s}", .{ + builtin_name, + }), } } @@ -5376,7 +5388,7 @@ pub fn failNodeNotes( { var managed = string_bytes.toManaged(astgen.gpa); defer string_bytes.* = managed.toUnmanaged(); - try managed.writer().print(format, args); + try managed.writer().print(format ++ "\x00", args); } const notes_index: u32 = if (notes.len != 0) blk: { const notes_start = astgen.extra.items.len; @@ -5417,7 +5429,7 @@ pub fn failTokNotes( { var managed = string_bytes.toManaged(astgen.gpa); defer string_bytes.* = managed.toUnmanaged(); - try managed.writer().print(format, args); + try managed.writer().print(format ++ "\x00", args); } const notes_index: u32 = if (notes.len != 0) blk: { const notes_start = astgen.extra.items.len; @@ -5451,7 +5463,7 @@ pub fn failOff( { var managed = string_bytes.toManaged(astgen.gpa); defer string_bytes.* = managed.toUnmanaged(); - try managed.writer().print(format, args); + try managed.writer().print(format ++ "\x00", args); } try astgen.compile_errors.append(astgen.gpa, .{ .msg = msg, @@ -5475,7 +5487,7 @@ pub fn errNoteTok( { var managed = string_bytes.toManaged(astgen.gpa); defer string_bytes.* = managed.toUnmanaged(); - try managed.writer().print(format, args); + try managed.writer().print(format ++ "\x00", args); } return astgen.addExtra(Zir.Inst.CompileErrors.Item{ .msg = msg, @@ -5498,7 +5510,7 @@ pub fn errNoteNode( { var managed = string_bytes.toManaged(astgen.gpa); defer string_bytes.* = managed.toUnmanaged(); - try managed.writer().print(format, args); + try managed.writer().print(format ++ "\x00", args); } return astgen.addExtra(Zir.Inst.CompileErrors.Item{ .msg = msg, diff --git a/src/Compilation.zig b/src/Compilation.zig index 18349b71ec..b3fe13db1b 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -391,10 +391,10 @@ pub const AllErrors = struct { const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len); for (notes) |*note, i| { const module_note = module_err_msg.notes[i]; - const source = try module_note.src_loc.fileScope().getSource(module.gpa); + const source = try module_note.src_loc.file_scope.getSource(module.gpa); const byte_offset = try module_note.src_loc.byteOffset(); const loc = std.zig.findLineColumn(source, byte_offset); - const sub_file_path = module_note.src_loc.fileScope().sub_file_path; + const sub_file_path = module_note.src_loc.file_scope.sub_file_path; note.* = .{ .src = .{ .src_path = try arena.allocator.dupe(u8, sub_file_path), @@ -406,10 +406,10 @@ pub const AllErrors = struct { }, }; } - const source = try module_err_msg.src_loc.fileScope().getSource(module.gpa); + const source = try module_err_msg.src_loc.file_scope.getSource(module.gpa); const byte_offset = try module_err_msg.src_loc.byteOffset(); const loc = std.zig.findLineColumn(source, byte_offset); - const sub_file_path = module_err_msg.src_loc.fileScope().sub_file_path; + const sub_file_path = module_err_msg.src_loc.file_scope.sub_file_path; try errors.append(.{ .src = .{ .src_path = try arena.allocator.dupe(u8, sub_file_path), @@ -423,6 +423,56 @@ pub const AllErrors = struct { }); } + pub fn addZir( + arena: *Allocator, + errors: *std.ArrayList(Message), + file: *Module.Scope.File, + source: []const u8, + ) !void { + assert(file.zir_loaded); + assert(file.tree_loaded); + const Zir = @import("Zir.zig"); + const payload_index = file.zir.extra[Zir.compile_error_extra_index]; + assert(payload_index != 0); + + const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index); + const items_len = header.data.items_len; + var extra_index = header.end; + var item_i: usize = 0; + while (item_i < items_len) : (item_i += 1) { + const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index); + extra_index = item.end; + + if (item.data.notes != 0) { + @panic("TODO implement AllErrors for Zir notes"); + } + + const msg = file.zir.nullTerminatedString(item.data.msg); + const byte_offset = blk: { + const token_starts = file.tree.tokens.items(.start); + if (item.data.node != 0) { + const main_tokens = file.tree.nodes.items(.main_token); + const main_token = main_tokens[item.data.node]; + break :blk token_starts[main_token]; + } + break :blk token_starts[item.data.token] + item.data.byte_offset; + }; + const loc = std.zig.findLineColumn(source, byte_offset); + + try errors.append(.{ + .src = .{ + .src_path = try arena.dupe(u8, file.sub_file_path), + .msg = try arena.dupe(u8, msg), + .byte_offset = byte_offset, + .line = @intCast(u32, loc.line), + .column = @intCast(u32, loc.column), + .notes = &.{}, // TODO + .source_line = try arena.dupe(u8, loc.source_line), + }, + }); + } + } + fn addPlain( arena: *std.heap.ArenaAllocator, errors: *std.ArrayList(Message), @@ -1624,7 +1674,13 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors { } if (self.bin_file.options.module) |module| { for (module.failed_files.items()) |entry| { - try AllErrors.add(module, &arena, &errors, entry.value.*); + if (entry.value) |msg| { + try AllErrors.add(module, &arena, &errors, msg.*); + } else { + // Must be ZIR errors. + const source = try entry.key.getSource(module.gpa); + try AllErrors.addZir(&arena.allocator, &errors, entry.key, source); + } } for (module.failed_decls.items()) |entry| { if (entry.key.namespace.file_scope.status == .parse_failure) { @@ -2276,7 +2332,8 @@ fn reportRetryableAstGenError( file.status = .retryable_failure; const err_msg = try Module.ErrorMsg.create(gpa, .{ - .container = .{ .file_scope = file }, + .file_scope = file, + .parent_decl_node = 0, .lazy = .entire_file, }, "unable to load {s}: {s}", .{ file.sub_file_path, @errorName(err), diff --git a/src/Module.zig b/src/Module.zig index 2baa064255..15434fe159 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -70,7 +70,7 @@ emit_h_failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *ErrorMsg) = .{}, compile_log_decls: std.AutoArrayHashMapUnmanaged(*Decl, SrcLoc) = .{}, /// Using a map here for consistency with the other fields here. /// The ErrorMsg memory is owned by the `Scope.File`, using Module's general purpose allocator. -failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, *ErrorMsg) = .{}, +failed_files: std.AutoArrayHashMapUnmanaged(*Scope.File, ?*ErrorMsg) = .{}, /// Using a map here for consistency with the other fields here. /// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator. failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{}, @@ -267,9 +267,10 @@ pub const Decl = struct { return .{ .node_offset = decl.nodeIndexToRelative(node_index) }; } - pub fn srcLoc(decl: *Decl) SrcLoc { + pub fn srcLoc(decl: Decl) SrcLoc { return .{ - .container = .{ .decl = decl }, + .file_scope = decl.getFileScope(), + .parent_decl_node = decl.src_node, .lazy = .{ .node_offset = 0 }, }; } @@ -367,7 +368,8 @@ pub const ErrorSet = struct { pub fn srcLoc(self: ErrorSet) SrcLoc { return .{ - .container = .{ .decl = self.owner_decl }, + .file_scope = self.owner_decl.getFileScope(), + .parent_decl_node = self.owner_decl.src_node, .lazy = .{ .node_offset = self.node_offset }, }; } @@ -397,7 +399,8 @@ pub const Struct = struct { pub fn srcLoc(s: Struct) SrcLoc { return .{ - .container = .{ .decl = s.owner_decl }, + .file_scope = s.owner_decl.getFileScope(), + .parent_decl_node = s.owner_decl.src_node, .lazy = .{ .node_offset = s.node_offset }, }; } @@ -416,7 +419,8 @@ pub const EnumSimple = struct { pub fn srcLoc(self: EnumSimple) SrcLoc { return .{ - .container = .{ .decl = self.owner_decl }, + .file_scope = self.owner_decl.getFileScope(), + .parent_decl_node = self.owner_decl.src_node, .lazy = .{ .node_offset = self.node_offset }, }; } @@ -444,7 +448,8 @@ pub const EnumFull = struct { pub fn srcLoc(self: EnumFull) SrcLoc { return .{ - .container = .{ .decl = self.owner_decl }, + .file_scope = self.owner_decl.getFileScope(), + .parent_decl_node = self.owner_decl.src_node, .lazy = .{ .node_offset = self.node_offset }, }; } @@ -1710,51 +1715,19 @@ pub const ErrorMsg = struct { /// Canonical reference to a position within a source file. pub const SrcLoc = struct { - /// The active field is determined by tag of `lazy`. - container: union { - /// The containing `Decl` according to the source code. - decl: *Decl, - file_scope: *Scope.File, - }, - /// Relative to `decl`. + file_scope: *Scope.File, + /// Might be 0 depending on tag of `lazy`. + parent_decl_node: ast.Node.Index, + /// Relative to `parent_decl_node`. lazy: LazySrcLoc, - pub fn fileScope(src_loc: SrcLoc) *Scope.File { - return switch (src_loc.lazy) { - .unneeded => unreachable, - - .byte_abs, - .token_abs, - .node_abs, - .entire_file, - => src_loc.container.file_scope, + pub fn declSrcToken(src_loc: SrcLoc) ast.TokenIndex { + const tree = src_loc.file_scope.tree; + return tree.firstToken(src_loc.parent_decl_node); + } - .byte_offset, - .token_offset, - .node_offset, - .node_offset_back2tok, - .node_offset_var_decl_ty, - .node_offset_for_cond, - .node_offset_builtin_call_arg0, - .node_offset_builtin_call_arg1, - .node_offset_array_access_index, - .node_offset_slice_sentinel, - .node_offset_call_func, - .node_offset_field_name, - .node_offset_deref_ptr, - .node_offset_asm_source, - .node_offset_asm_ret_ty, - .node_offset_if_cond, - .node_offset_bin_op, - .node_offset_bin_lhs, - .node_offset_bin_rhs, - .node_offset_switch_operand, - .node_offset_switch_special_prong, - .node_offset_switch_range, - .node_offset_fn_type_cc, - .node_offset_fn_type_ret_ty, - => src_loc.container.decl.namespace.file_scope, - }; + 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) !u32 { @@ -1765,48 +1738,45 @@ pub const SrcLoc = struct { .byte_abs => |byte_index| return byte_index, .token_abs => |tok_index| { - const tree = src_loc.container.file_scope.tree; + const tree = src_loc.file_scope.tree; const token_starts = tree.tokens.items(.start); return token_starts[tok_index]; }, .node_abs => |node| { - const tree = src_loc.container.file_scope.tree; + const tree = src_loc.file_scope.tree; const token_starts = tree.tokens.items(.start); const tok_index = tree.firstToken(node); return token_starts[tok_index]; }, .byte_offset => |byte_off| { - const decl = src_loc.container.decl; - return decl.srcByteOffset() + byte_off; + const tree = src_loc.file_scope.tree; + const token_starts = tree.tokens.items(.start); + return token_starts[src_loc.declSrcToken()] + byte_off; }, .token_offset => |tok_off| { - const decl = src_loc.container.decl; - const tok_index = decl.srcToken() + tok_off; - const tree = decl.namespace.file_scope.tree; + const tok_index = src_loc.declSrcToken() + tok_off; + const tree = src_loc.file_scope.tree; const token_starts = tree.tokens.items(.start); return token_starts[tok_index]; }, .node_offset, .node_offset_bin_op => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const main_tokens = tree.nodes.items(.main_token); const tok_index = main_tokens[node]; const token_starts = tree.tokens.items(.start); return token_starts[tok_index]; }, .node_offset_back2tok => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const tok_index = tree.firstToken(node) - 2; const token_starts = tree.tokens.items(.start); return token_starts[tok_index]; }, .node_offset_var_decl_ty => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_tags = tree.nodes.items(.tag); const full = switch (node_tags[node]) { .global_var_decl => tree.globalVarDecl(node), @@ -1825,11 +1795,10 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_builtin_call_arg0 => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const param = switch (node_tags[node]) { .builtin_call_two, .builtin_call_two_comma => node_datas[node].lhs, .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs], @@ -1841,11 +1810,10 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_builtin_call_arg1 => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const param = switch (node_tags[node]) { .builtin_call_two, .builtin_call_two_comma => node_datas[node].rhs, .builtin_call, .builtin_call_comma => tree.extra_data[node_datas[node].lhs + 1], @@ -1857,22 +1825,20 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_array_access_index => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const main_tokens = tree.nodes.items(.main_token); const tok_index = main_tokens[node_datas[node].rhs]; const token_starts = tree.tokens.items(.start); return token_starts[tok_index]; }, .node_offset_slice_sentinel => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const full = switch (node_tags[node]) { .slice_open => tree.sliceOpen(node), .slice => tree.slice(node), @@ -1885,11 +1851,10 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_call_func => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); var params: [1]ast.Node.Index = undefined; const full = switch (node_tags[node]) { .call_one, @@ -1912,11 +1877,10 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_field_name => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const tok_index = switch (node_tags[node]) { .field_access => node_datas[node].rhs, else => tree.firstToken(node) - 2, @@ -1925,21 +1889,19 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_deref_ptr => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const tok_index = node_datas[node].lhs; const token_starts = tree.tokens.items(.start); return token_starts[tok_index]; }, .node_offset_asm_source => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const full = switch (node_tags[node]) { .asm_simple => tree.asmSimple(node), .@"asm" => tree.asmFull(node), @@ -1951,11 +1913,10 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_asm_ret_ty => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); const full = switch (node_tags[node]) { .asm_simple => tree.asmSimple(node), .@"asm" => tree.asmFull(node), @@ -1968,9 +1929,8 @@ pub const SrcLoc = struct { }, .node_offset_for_cond, .node_offset_if_cond => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_tags = tree.nodes.items(.tag); const src_node = switch (node_tags[node]) { .if_simple => tree.ifSimple(node).ast.cond_expr, @@ -1988,9 +1948,8 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_bin_lhs => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const src_node = node_datas[node].lhs; const main_tokens = tree.nodes.items(.main_token); @@ -1999,9 +1958,8 @@ pub const SrcLoc = struct { return token_starts[tok_index]; }, .node_offset_bin_rhs => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const src_node = node_datas[node].rhs; const main_tokens = tree.nodes.items(.main_token); @@ -2011,9 +1969,8 @@ pub const SrcLoc = struct { }, .node_offset_switch_operand => |node_off| { - const decl = src_loc.container.decl; - const node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const src_node = node_datas[node].lhs; const main_tokens = tree.nodes.items(.main_token); @@ -2023,9 +1980,8 @@ pub const SrcLoc = struct { }, .node_offset_switch_special_prong => |node_off| { - const decl = src_loc.container.decl; - const switch_node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const switch_node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); @@ -2050,9 +2006,8 @@ pub const SrcLoc = struct { }, .node_offset_switch_range => |node_off| { - const decl = src_loc.container.decl; - const switch_node = decl.relativeToNodeIndex(node_off); - const tree = decl.namespace.file_scope.tree; + const switch_node = src_loc.declRelativeToNodeIndex(node_off); + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); const main_tokens = tree.nodes.items(.main_token); @@ -2081,11 +2036,10 @@ pub const SrcLoc = struct { }, .node_offset_fn_type_cc => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); var params: [1]ast.Node.Index = undefined; const full = switch (node_tags[node]) { .fn_proto_simple => tree.fnProtoSimple(¶ms, node), @@ -2101,11 +2055,10 @@ pub const SrcLoc = struct { }, .node_offset_fn_type_ret_ty => |node_off| { - const decl = src_loc.container.decl; - const tree = decl.namespace.file_scope.tree; + const tree = src_loc.file_scope.tree; const node_datas = tree.nodes.items(.data); const node_tags = tree.nodes.items(.tag); - const node = decl.relativeToNodeIndex(node_off); + const node = src_loc.declRelativeToNodeIndex(node_off); var params: [1]ast.Node.Index = undefined; const full = switch (node_tags[node]) { .fn_proto_simple => tree.fnProtoSimple(¶ms, node), @@ -2288,7 +2241,8 @@ pub const LazySrcLoc = union(enum) { .token_abs, .node_abs, => .{ - .container = .{ .file_scope = scope.getFileScope() }, + .file_scope = scope.getFileScope(), + .parent_decl_node = 0, .lazy = lazy, }, @@ -2317,7 +2271,8 @@ pub const LazySrcLoc = union(enum) { .node_offset_fn_type_cc, .node_offset_fn_type_ret_ty, => .{ - .container = .{ .decl = scope.srcDecl().? }, + .file_scope = scope.getFileScope(), + .parent_decl_node = scope.srcDecl().?.src_node, .lazy = lazy, }, }; @@ -2332,7 +2287,8 @@ pub const LazySrcLoc = union(enum) { .token_abs, .node_abs, => .{ - .container = .{ .file_scope = decl.getFileScope() }, + .file_scope = decl.getFileScope(), + .parent_decl_node = 0, .lazy = lazy, }, @@ -2361,7 +2317,8 @@ pub const LazySrcLoc = union(enum) { .node_offset_fn_type_cc, .node_offset_fn_type_ret_ty, => .{ - .container = .{ .decl = decl }, + .file_scope = decl.getFileScope(), + .parent_decl_node = decl.src_node, .lazy = lazy, }, }; @@ -2409,7 +2366,7 @@ pub fn deinit(mod: *Module) void { mod.emit_h_failed_decls.deinit(gpa); for (mod.failed_files.items()) |entry| { - entry.value.destroy(gpa); + if (entry.value) |msg| msg.destroy(gpa); } mod.failed_files.deinit(gpa); @@ -2495,7 +2452,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node const lock = comp.mutex.acquire(); defer lock.release(); if (mod.failed_files.swapRemove(file)) |entry| { - entry.value.destroy(gpa); // Delete previous error message. + if (entry.value) |msg| msg.destroy(gpa); // Delete previous error message. } }, } @@ -2531,7 +2488,8 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node const err_msg = try gpa.create(ErrorMsg); err_msg.* = .{ .src_loc = .{ - .container = .{ .file_scope = file }, + .file_scope = file, + .parent_decl_node = 0, .lazy = .{ .byte_abs = token_starts[parse_err.token] }, }, .msg = msg.toOwnedSlice(), @@ -2550,11 +2508,11 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node file.zir = try AstGen.generate(gpa, file); file.zir_loaded = true; - if (file.zir.extra[1] != 0) { + if (file.zir.hasCompileErrors()) { { const lock = comp.mutex.acquire(); defer lock.release(); - try mod.failed_files.putNoClobber(gpa, file, undefined); + try mod.failed_files.putNoClobber(gpa, file, null); } file.status = .astgen_failure; return error.AnalysisFail; @@ -2972,12 +2930,14 @@ fn semaContainerFn( if (deleted_decls.swapRemove(decl) == null) { decl.analysis = .sema_failure; const msg = try ErrorMsg.create(mod.gpa, .{ - .container = .{ .file_scope = namespace.file_scope }, + .file_scope = namespace.file_scope, + .parent_decl_node = 0, .lazy = .{ .token_abs = name_token }, }, "redeclaration of '{s}'", .{decl.name}); errdefer msg.destroy(mod.gpa); const other_src_loc: SrcLoc = .{ - .container = .{ .file_scope = decl.namespace.file_scope }, + .file_scope = namespace.file_scope, + .parent_decl_node = 0, .lazy = .{ .node_abs = prev_src_node }, }; try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{}); @@ -3040,12 +3000,14 @@ fn semaContainerVar( if (deleted_decls.swapRemove(decl) == null) { decl.analysis = .sema_failure; const msg = try ErrorMsg.create(mod.gpa, .{ - .container = .{ .file_scope = namespace.file_scope }, + .file_scope = namespace.file_scope, + .parent_decl_node = 0, .lazy = .{ .token_abs = name_token }, }, "redeclaration of '{s}'", .{decl.name}); errdefer msg.destroy(mod.gpa); const other_src_loc: SrcLoc = .{ - .container = .{ .file_scope = decl.namespace.file_scope }, + .file_scope = decl.namespace.file_scope, + .parent_decl_node = 0, .lazy = .{ .node_abs = prev_src_node }, }; try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{}); diff --git a/src/Sema.zig b/src/Sema.zig index e0cc9fe750..eaea6961e8 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -170,9 +170,7 @@ pub fn analyzeBody( .cmp_lte => try sema.zirCmp(block, inst, .lte), .cmp_neq => try sema.zirCmp(block, inst, .neq), .coerce_result_ptr => try sema.zirCoerceResultPtr(block, inst), - .decl_ref => try sema.zirDeclRef(block, inst), .decl_ref_named => try sema.zirDeclRefNamed(block, inst), - .decl_val => try sema.zirDeclVal(block, inst), .decl_val_named => try sema.zirDeclValNamed(block, inst), .load => try sema.zirLoad(block, inst), .div => try sema.zirArithmetic(block, inst), @@ -266,6 +264,10 @@ pub fn analyzeBody( .type_info => try sema.zirTypeInfo(block, inst), .size_of => try sema.zirSizeOf(block, inst), .bit_size_of => try sema.zirBitSizeOf(block, inst), + .this => try sema.zirThis(block, inst), + .fence => try sema.zirFence(block, inst), + .ret_addr => try sema.zirRetAddr(block, inst), + .builtin_src => try sema.zirBuiltinSrc(block, inst), .typeof => try sema.zirTypeof(block, inst), .typeof_elem => try sema.zirTypeofElem(block, inst), .typeof_peer => try sema.zirTypeofPeer(block, inst), @@ -1656,20 +1658,6 @@ fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerE _ = try block.addDbgStmt(src, abs_byte_off); } -fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { - const inst_data = sema.code.instructions.items(.data)[inst].pl_node; - const src = inst_data.src(); - const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key; - return sema.analyzeDeclRef(block, src, decl); -} - -fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { - const inst_data = sema.code.instructions.items(.data)[inst].pl_node; - const src = inst_data.src(); - const decl = sema.owner_decl.dependencies.entries.items[inst_data.payload_index].key; - return sema.analyzeDeclVal(block, src, decl); -} - fn zirDeclRefNamed(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { const inst_data = sema.code.instructions.items(.data)[inst].str_tok; const src = inst_data.src(); @@ -4373,6 +4361,27 @@ fn zirBitSizeOf(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErr return sema.mod.constIntUnsigned(sema.arena, src, Type.initTag(.comptime_int), bit_size); } +fn zirThis(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const src_node = sema.code.instructions.items(.data)[inst].node; + const src: LazySrcLoc = .{ .node_offset = src_node }; + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirThis", .{}); +} +fn zirFence(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const src_node = sema.code.instructions.items(.data)[inst].node; + const src: LazySrcLoc = .{ .node_offset = src_node }; + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirFence", .{}); +} +fn zirRetAddr(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const src_node = sema.code.instructions.items(.data)[inst].node; + const src: LazySrcLoc = .{ .node_offset = src_node }; + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirRetAddr", .{}); +} +fn zirBuiltinSrc(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { + const src_node = sema.code.instructions.items(.data)[inst].node; + const src: LazySrcLoc = .{ .node_offset = src_node }; + return sema.mod.fail(&block.base, src, "TODO: implement Sema.zirBuiltinSrc", .{}); +} + fn zirTypeInfo(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst { const inst_data = sema.code.instructions.items(.data)[inst].un_node; const src = inst_data.src(); diff --git a/src/Zir.zig b/src/Zir.zig index c8c6893f82..f3be0e2c64 100644 --- a/src/Zir.zig +++ b/src/Zir.zig @@ -42,6 +42,9 @@ string_bytes: []u8, /// payload at this index. extra: []u32, +pub const main_struct_extra_index = 0; +pub const compile_error_extra_index = 1; + /// Returns the requested data, as well as the new index which is at the start of the /// trailers for the object. pub fn extraData(code: Zir, comptime T: type, index: usize) struct { data: T, end: usize } { @@ -76,6 +79,10 @@ pub fn refSlice(code: Zir, start: usize, len: usize) []Inst.Ref { return @bitCast([]Inst.Ref, raw_slice); } +pub fn hasCompileErrors(code: Zir) bool { + return code.extra[compile_error_extra_index] != 0; +} + pub fn deinit(code: *Zir, gpa: *Allocator) void { code.instructions.deinit(gpa); gpa.free(code.string_bytes); @@ -83,13 +90,11 @@ pub fn deinit(code: *Zir, gpa: *Allocator) void { code.* = undefined; } -/// For debugging purposes, like dumpFn but for unanalyzed zir blocks -pub fn dump( - code: Zir, +/// Write human-readable, debug formatted ZIR code to a file. +pub fn renderAsTextToFile( gpa: *Allocator, - kind: []const u8, - scope: *Module.Scope, - param_count: usize, + scope_file: *Module.Scope.File, + fs_file: std.fs.File, ) !void { var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); @@ -97,17 +102,17 @@ pub fn dump( var writer: Writer = .{ .gpa = gpa, .arena = &arena.allocator, - .scope = scope, - .code = code, + .file = scope_file, + .code = scope_file.zir, .indent = 0, - .param_count = param_count, + .parent_decl_node = 0, + .param_count = 0, }; - const decl_name = scope.srcDecl().?.name; - const stderr = std.io.getStdErr().writer(); - try stderr.print("ZIR {s} {s} %0 ", .{ kind, decl_name }); - try writer.writeInstToStream(stderr, 0); - try stderr.print(" // end ZIR {s} {s}\n\n", .{ kind, decl_name }); + const main_struct_inst = scope_file.zir.extra[0] - @intCast(u32, Inst.Ref.typed_value_map.len); + try fs_file.writer().print("%{d} ", .{main_struct_inst}); + try writer.writeInstToStream(fs_file.writer(), main_struct_inst); + try fs_file.writeAll("\n"); } /// These are untyped instructions generated from an Abstract Syntax Tree. @@ -291,12 +296,6 @@ pub const Inst = struct { /// Declares the beginning of a statement. Used for debug info. /// Uses the `node` union field. dbg_stmt_node, - /// Represents a pointer to a global decl. - /// Uses the `pl_node` union field. `payload_index` is into `decls`. - decl_ref, - /// Equivalent to a decl_ref followed by load. - /// Uses the `pl_node` union field. `payload_index` is into `decls`. - decl_val, /// Same as `decl_ref` except instead of indexing into decls, uses /// a name to identify the Decl. Uses the `str_tok` union field. decl_ref_named, @@ -705,6 +704,14 @@ pub const Inst = struct { size_of, /// Implements the `@bitSizeOf` builtin. Uses `un_node`. bit_size_of, + /// Implements the `@This` builtin. Uses `node`. + this, + /// Implements the `@fence` builtin. Uses `un_node`. + fence, + /// Implements the `@returnAddress` builtin. Uses `un_node`. + ret_addr, + /// Implements the `@src` builtin. Uses `un_node`. + builtin_src, /// Returns whether the instruction is one of the control flow "noreturn" types. /// Function calls do not count. @@ -758,8 +765,6 @@ pub const Inst = struct { .enum_decl_nonexhaustive, .opaque_decl, .dbg_stmt_node, - .decl_ref, - .decl_val, .decl_ref_named, .decl_val_named, .load, @@ -873,6 +878,10 @@ pub const Inst = struct { .type_info, .size_of, .bit_size_of, + .this, + .fence, + .ret_addr, + .builtin_src, => false, .@"break", @@ -1647,11 +1656,16 @@ pub const SpecialProng = enum { none, @"else", under }; const Writer = struct { gpa: *Allocator, arena: *Allocator, - scope: *Module.Scope, + file: *Module.Scope.File, code: Zir, - indent: usize, + indent: u32, + parent_decl_node: u32, param_count: usize, + fn relativeToNodeIndex(self: *Writer, offset: i32) ast.Node.Index { + return @bitCast(ast.Node.Index, offset + @bitCast(i32, self.parent_decl_node)); + } + fn writeInstToStream( self: *Writer, stream: anytype, @@ -1832,10 +1846,6 @@ const Writer = struct { .typeof_peer, => try self.writePlNodeMultiOp(stream, inst), - .decl_ref, - .decl_val, - => try self.writePlNodeDecl(stream, inst), - .field_ptr, .field_val, => try self.writePlNodeField(stream, inst), @@ -1851,6 +1861,10 @@ const Writer = struct { .repeat_inline, .alloc_inferred, .alloc_inferred_mut, + .this, + .fence, + .ret_addr, + .builtin_src, => try self.writeNode(stream, inst), .error_value, @@ -2067,68 +2081,114 @@ const Writer = struct { const extra = self.code.extraData(Inst.StructDecl, inst_data.payload_index); const body = self.code.extra[extra.end..][0..extra.data.body_len]; const fields_len = extra.data.fields_len; + const decls_len = extra.data.decls_len; + + const prev_parent_decl_node = self.parent_decl_node; + self.parent_decl_node = self.relativeToNodeIndex(inst_data.src_node); + + var extra_index: usize = undefined; if (fields_len == 0) { assert(body.len == 0); - try stream.writeAll("{}, {}) "); - try self.writeSrc(stream, inst_data.src()); - return; - } + try stream.writeAll("{}, {}, {"); + extra_index = extra.end; + } else { + try stream.writeAll("{\n"); + self.indent += 2; + try self.writeBody(stream, body); + + try stream.writeByteNTimes(' ', self.indent - 2); + try stream.writeAll("}, {\n"); + + const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable; + const body_end = extra.end + body.len; + extra_index = body_end + bit_bags_count; + var bit_bag_index: usize = body_end; + var cur_bit_bag: u32 = undefined; + var field_i: u32 = 0; + while (field_i < fields_len) : (field_i += 1) { + if (field_i % 16 == 0) { + cur_bit_bag = self.code.extra[bit_bag_index]; + bit_bag_index += 1; + } + const has_align = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; + const has_default = @truncate(u1, cur_bit_bag) != 0; + cur_bit_bag >>= 1; - try stream.writeAll("{\n"); - self.indent += 2; - try self.writeBody(stream, body); + const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); + extra_index += 1; + const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; - try stream.writeByteNTimes(' ', self.indent - 2); - try stream.writeAll("}, {\n"); + try stream.writeByteNTimes(' ', self.indent); + try stream.print("{}: ", .{std.zig.fmtId(field_name)}); + try self.writeInstRef(stream, field_type); - const bit_bags_count = std.math.divCeil(usize, fields_len, 16) catch unreachable; - const body_end = extra.end + body.len; - var extra_index: usize = body_end + bit_bags_count; - var bit_bag_index: usize = body_end; + if (has_align) { + const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + + try stream.writeAll(" align("); + try self.writeInstRef(stream, align_ref); + try stream.writeAll(")"); + } + if (has_default) { + const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); + extra_index += 1; + + try stream.writeAll(" = "); + try self.writeInstRef(stream, default_ref); + } + try stream.writeAll(",\n"); + } + + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}, {"); + } + if (decls_len == 0) { + try stream.writeAll("}) "); + } else { + try stream.writeAll("\n"); + self.indent += 2; + try self.writeDecls(stream, decls_len, extra_index); + self.indent -= 2; + try stream.writeByteNTimes(' ', self.indent); + try stream.writeAll("}) "); + } + self.parent_decl_node = prev_parent_decl_node; + try self.writeSrc(stream, inst_data.src()); + } + + fn writeDecls(self: *Writer, stream: anytype, decls_len: u32, extra_start: usize) !void { + const bit_bags_count = std.math.divCeil(usize, decls_len, 16) catch unreachable; + var extra_index = extra_start + bit_bags_count; + var bit_bag_index: usize = extra_start; var cur_bit_bag: u32 = undefined; - var field_i: u32 = 0; - while (field_i < fields_len) : (field_i += 1) { - if (field_i % 16 == 0) { + var decl_i: u32 = 0; + while (decl_i < decls_len) : (decl_i += 1) { + if (decl_i % 16 == 0) { cur_bit_bag = self.code.extra[bit_bag_index]; bit_bag_index += 1; } - const has_align = @truncate(u1, cur_bit_bag) != 0; + const is_pub = @truncate(u1, cur_bit_bag) != 0; cur_bit_bag >>= 1; - const has_default = @truncate(u1, cur_bit_bag) != 0; + const is_exported = @truncate(u1, cur_bit_bag) != 0; cur_bit_bag >>= 1; - const field_name = self.code.nullTerminatedString(self.code.extra[extra_index]); + const decl_name = self.code.nullTerminatedString(self.code.extra[extra_index]); extra_index += 1; - const field_type = @intToEnum(Inst.Ref, self.code.extra[extra_index]); + const decl_value = @intToEnum(Inst.Ref, self.code.extra[extra_index]); extra_index += 1; + const pub_str = if (is_pub) "pub " else ""; + const export_str = if (is_exported) "export " else ""; try stream.writeByteNTimes(' ', self.indent); - try stream.print("{}: ", .{std.zig.fmtId(field_name)}); - try self.writeInstRef(stream, field_type); - - if (has_align) { - const align_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - - try stream.writeAll(" align("); - try self.writeInstRef(stream, align_ref); - try stream.writeAll(")"); - } - if (has_default) { - const default_ref = @intToEnum(Inst.Ref, self.code.extra[extra_index]); - extra_index += 1; - - try stream.writeAll(" = "); - try self.writeInstRef(stream, default_ref); - } - try stream.writeAll(",\n"); + try stream.print("{s}{s}{} = ", .{ pub_str, export_str, std.zig.fmtId(decl_name) }); + try self.writeInstRef(stream, decl_value); + try stream.writeAll("\n"); } - - self.indent -= 2; - try stream.writeByteNTimes(' ', self.indent); - try stream.writeAll("}) "); - try self.writeSrc(stream, inst_data.src()); } fn writeEnumDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void { @@ -2374,14 +2434,6 @@ const Writer = struct { try self.writeSrc(stream, inst_data.src()); } - fn writePlNodeDecl(self: *Writer, stream: anytype, inst: Inst.Index) !void { - const inst_data = self.code.instructions.items(.data)[inst].pl_node; - const owner_decl = self.scope.ownerDecl().?; - const decl = owner_decl.dependencies.entries.items[inst_data.payload_index].key; - try stream.print("{s}) ", .{decl.name}); - try self.writeSrc(stream, inst_data.src()); - } - fn writePlNodeField(self: *Writer, stream: anytype, inst: Inst.Index) !void { const inst_data = self.code.instructions.items(.data)[inst].pl_node; const extra = self.code.extraData(Inst.Field, inst_data.payload_index).data; @@ -2593,8 +2645,12 @@ const Writer = struct { } fn writeSrc(self: *Writer, stream: anytype, src: LazySrcLoc) !void { - const tree = self.scope.tree(); - const src_loc = src.toSrcLoc(self.scope); + const tree = self.file.tree; + const src_loc: Module.SrcLoc = .{ + .file_scope = self.file, + .parent_decl_node = self.parent_decl_node, + .lazy = src, + }; const abs_byte_off = try src_loc.byteOffset(); const delta_line = std.zig.findLineColumn(tree.source, abs_byte_off); try stream.print("{s}:{d}:{d}", .{ diff --git a/src/main.zig b/src/main.zig index 044c6f0fec..40dd9f89af 100644 --- a/src/main.zig +++ b/src/main.zig @@ -25,7 +25,11 @@ pub fn fatal(comptime format: []const u8, args: anytype) noreturn { process.exit(1); } -pub const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB +/// There are many assumptions in the entire codebase that Zig source files can +/// be byte-indexed with a u32 integer. +pub const max_src_size = std.math.maxInt(u32); + +pub const debug_extensions_enabled = std.builtin.mode == .Debug; pub const Color = enum { auto, @@ -33,7 +37,7 @@ pub const Color = enum { on, }; -const usage = +const normal_usage = \\Usage: zig [command] [options] \\ \\Commands: @@ -63,6 +67,16 @@ const usage = \\ ; +const debug_usage = normal_usage ++ + \\ + \\Debug Commands: + \\ + \\ astgen Print ZIR code for a .zig source file + \\ +; + +const usage = if (debug_extensions_enabled) debug_usage else normal_usage; + pub const log_level: std.log.Level = switch (std.builtin.mode) { .Debug => .debug, .ReleaseSafe, .ReleaseFast => .info, @@ -206,13 +220,15 @@ pub fn mainArgs(gpa: *Allocator, arena: *Allocator, args: []const []const u8) !v const stdout = io.getStdOut().writer(); return @import("print_targets.zig").cmdTargets(arena, cmd_args, stdout, info.target); } else if (mem.eql(u8, cmd, "version")) { - try std.io.getStdOut().writeAll(build_options.version ++ "\n"); + return std.io.getStdOut().writeAll(build_options.version ++ "\n"); } else if (mem.eql(u8, cmd, "env")) { - try @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer()); + return @import("print_env.zig").cmdEnv(arena, cmd_args, io.getStdOut().writer()); } else if (mem.eql(u8, cmd, "zen")) { - try io.getStdOut().writeAll(info_zen); + return io.getStdOut().writeAll(info_zen); } else if (mem.eql(u8, cmd, "help") or mem.eql(u8, cmd, "-h") or mem.eql(u8, cmd, "--help")) { - try io.getStdOut().writeAll(usage); + return io.getStdOut().writeAll(usage); + } else if (debug_extensions_enabled and mem.eql(u8, cmd, "astgen")) { + return cmdAstgen(gpa, arena, cmd_args); } else { std.log.info("{s}", .{usage}); fatal("unknown command: {s}", .{args[1]}); @@ -3485,3 +3501,74 @@ pub fn cleanExit() void { process.exit(0); } } + +/// This is only enabled for debug builds. +pub fn cmdAstgen( + gpa: *Allocator, + arena: *Allocator, + args: []const []const u8, +) !void { + const Module = @import("Module.zig"); + const AstGen = @import("AstGen.zig"); + const Zir = @import("Zir.zig"); + + const zig_source_file = args[0]; + + var f = try fs.cwd().openFile(zig_source_file, .{}); + defer f.close(); + + const stat = try f.stat(); + + if (stat.size > max_src_size) + return error.FileTooBig; + + var file: Module.Scope.File = .{ + .status = .never_loaded, + .source_loaded = false, + .tree_loaded = false, + .zir_loaded = false, + .sub_file_path = zig_source_file, + .source = undefined, + .stat_size = stat.size, + .stat_inode = stat.inode, + .stat_mtime = stat.mtime, + .tree = undefined, + .zir = undefined, + .pkg = undefined, + .namespace = undefined, + }; + + const source = try arena.allocSentinel(u8, stat.size, 0); + const amt = try f.readAll(source); + if (amt != stat.size) + return error.UnexpectedEndOfFile; + file.source = source; + file.source_loaded = true; + + file.tree = try std.zig.parse(gpa, file.source); + file.tree_loaded = true; + defer file.tree.deinit(gpa); + + for (file.tree.errors) |parse_error| { + try printErrMsgToFile(gpa, parse_error, file.tree, zig_source_file, io.getStdErr(), .auto); + } + if (file.tree.errors.len != 0) { + process.exit(1); + } + + file.zir = try AstGen.generate(gpa, &file); + file.zir_loaded = true; + defer file.zir.deinit(gpa); + + if (file.zir.hasCompileErrors()) { + var errors = std.ArrayList(Compilation.AllErrors.Message).init(arena); + try Compilation.AllErrors.addZir(arena, &errors, &file, source); + const ttyconf = std.debug.detectTTYConfig(); + for (errors.items) |full_err_msg| { + full_err_msg.renderToStdErr(ttyconf); + } + process.exit(1); + } + + return Zir.renderAsTextToFile(gpa, &file, io.getStdOut()); +} |
