aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/AstGen.zig60
-rw-r--r--src/Compilation.zig69
-rw-r--r--src/Module.zig220
-rw-r--r--src/Sema.zig41
-rw-r--r--src/Zir.zig220
-rw-r--r--src/main.zig99
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(&params, 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(&params, 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());
+}