| author | |
| committer | |
| log | 10d2f08d376a302bd79e87d17c06922d3145a939 |
| tree | 1251086911401d33cda814ad87d0fce50da70184 |
| parent | d767fae47e89aef53505191cf11ce7e592a784b2 |
6 files changed, 255 insertions(+), 112 deletions(-)
src-self-hosted/compilation.zig+30-29| ... | @@ -24,6 +24,7 @@ const Visib = @import("visib.zig").Visib; | ... | @@ -24,6 +24,7 @@ const Visib = @import("visib.zig").Visib; |
| 24 | const Value = @import("value.zig").Value; | 24 | const Value = @import("value.zig").Value; |
| 25 | const Type = Value.Type; | 25 | const Type = Value.Type; |
| 26 | const Span = errmsg.Span; | 26 | const Span = errmsg.Span; |
| 27 | const Msg = errmsg.Msg; | ||
| 27 | const codegen = @import("codegen.zig"); | 28 | const codegen = @import("codegen.zig"); |
| 28 | const Package = @import("package.zig").Package; | 29 | const Package = @import("package.zig").Package; |
| 29 | const link = @import("link.zig").link; | 30 | const link = @import("link.zig").link; |
| ... | @@ -40,8 +41,6 @@ pub const EventLoopLocal = struct { | ... | @@ -40,8 +41,6 @@ pub const EventLoopLocal = struct { |
| 40 | 41 | ||
| 41 | native_libc: event.Future(LibCInstallation), | 42 | native_libc: event.Future(LibCInstallation), |
| 42 | 43 | ||
| 43 | cwd: []const u8, | ||
| 44 | |||
| 45 | var lazy_init_targets = std.lazyInit(void); | 44 | var lazy_init_targets = std.lazyInit(void); |
| 46 | 45 | ||
| 47 | fn init(loop: *event.Loop) !EventLoopLocal { | 46 | fn init(loop: *event.Loop) !EventLoopLocal { |
| ... | @@ -54,21 +53,16 @@ pub const EventLoopLocal = struct { | ... | @@ -54,21 +53,16 @@ pub const EventLoopLocal = struct { |
| 54 | try std.os.getRandomBytes(seed_bytes[0..]); | 53 | try std.os.getRandomBytes(seed_bytes[0..]); |
| 55 | const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big); | 54 | const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big); |
| 56 | 55 | ||
| 57 | const cwd = try os.getCwd(loop.allocator); | ||
| 58 | errdefer loop.allocator.free(cwd); | ||
| 59 | |||
| 60 | return EventLoopLocal{ | 56 | return EventLoopLocal{ |
| 61 | .loop = loop, | 57 | .loop = loop, |
| 62 | .llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(), | 58 | .llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(), |
| 63 | .prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)), | 59 | .prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)), |
| 64 | .native_libc = event.Future(LibCInstallation).init(loop), | 60 | .native_libc = event.Future(LibCInstallation).init(loop), |
| 65 | .cwd = cwd, | ||
| 66 | }; | 61 | }; |
| 67 | } | 62 | } |
| 68 | 63 | ||
| 69 | /// Must be called only after EventLoop.run completes. | 64 | /// Must be called only after EventLoop.run completes. |
| 70 | fn deinit(self: *EventLoopLocal) void { | 65 | fn deinit(self: *EventLoopLocal) void { |
| 71 | self.loop.allocator.free(self.cwd); | ||
| 72 | while (self.llvm_handle_pool.pop()) |node| { | 66 | while (self.llvm_handle_pool.pop()) |node| { |
| 73 | c.LLVMContextDispose(node.data); | 67 | c.LLVMContextDispose(node.data); |
| 74 | self.loop.allocator.destroy(node); | 68 | self.loop.allocator.destroy(node); |
| ... | @@ -234,7 +228,7 @@ pub const Compilation = struct { | ... | @@ -234,7 +228,7 @@ pub const Compilation = struct { |
| 234 | const PtrTypeTable = std.HashMap(*const Type.Pointer.Key, *Type.Pointer, Type.Pointer.Key.hash, Type.Pointer.Key.eql); | 228 | const PtrTypeTable = std.HashMap(*const Type.Pointer.Key, *Type.Pointer, Type.Pointer.Key.hash, Type.Pointer.Key.eql); |
| 235 | const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8); | 229 | const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8); |
| 236 | 230 | ||
| 237 | const CompileErrList = std.ArrayList(*errmsg.Msg); | 231 | const CompileErrList = std.ArrayList(*Msg); |
| 238 | 232 | ||
| 239 | // TODO handle some of these earlier and report them in a way other than error codes | 233 | // TODO handle some of these earlier and report them in a way other than error codes |
| 240 | pub const BuildError = error{ | 234 | pub const BuildError = error{ |
| ... | @@ -286,7 +280,7 @@ pub const Compilation = struct { | ... | @@ -286,7 +280,7 @@ pub const Compilation = struct { |
| 286 | pub const Event = union(enum) { | 280 | pub const Event = union(enum) { |
| 287 | Ok, | 281 | Ok, |
| 288 | Error: BuildError, | 282 | Error: BuildError, |
| 289 | Fail: []*errmsg.Msg, | 283 | Fail: []*Msg, |
| 290 | }; | 284 | }; |
| 291 | 285 | ||
| 292 | pub const DarwinVersionMin = union(enum) { | 286 | pub const DarwinVersionMin = union(enum) { |
| ... | @@ -761,21 +755,35 @@ pub const Compilation = struct { | ... | @@ -761,21 +755,35 @@ pub const Compilation = struct { |
| 761 | }; | 755 | }; |
| 762 | errdefer self.gpa().free(source_code); | 756 | errdefer self.gpa().free(source_code); |
| 763 | 757 | ||
| 764 | var tree = try std.zig.parse(self.gpa(), source_code); | 758 | const tree = try self.gpa().createOne(ast.Tree); |
| 765 | errdefer tree.deinit(); | 759 | tree.* = try std.zig.parse(self.gpa(), source_code); |
| 760 | errdefer { | ||
| 761 | tree.deinit(); | ||
| 762 | self.gpa().destroy(tree); | ||
| 763 | } | ||
| 766 | 764 | ||
| 767 | break :blk try Scope.Root.create(self, tree, root_src_real_path); | 765 | break :blk try Scope.Root.create(self, tree, root_src_real_path); |
| 768 | }; | 766 | }; |
| 769 | defer root_scope.base.deref(self); | 767 | defer root_scope.base.deref(self); |
| 768 | const tree = root_scope.tree; | ||
| 769 | |||
| 770 | var error_it = tree.errors.iterator(0); | ||
| 771 | while (error_it.next()) |parse_error| { | ||
| 772 | const msg = try Msg.createFromParseErrorAndScope(self, root_scope, parse_error); | ||
| 773 | errdefer msg.destroy(); | ||
| 770 | 774 | ||
| 771 | const tree = &root_scope.tree; | 775 | try await (async self.addCompileErrorAsync(msg) catch unreachable); |
| 776 | } | ||
| 777 | if (tree.errors.len != 0) { | ||
| 778 | return; | ||
| 779 | } | ||
| 772 | 780 | ||
| 773 | const decls = try Scope.Decls.create(self, &root_scope.base); | 781 | const decls = try Scope.Decls.create(self, &root_scope.base); |
| 774 | defer decls.base.deref(self); | 782 | defer decls.base.deref(self); |
| 775 | 783 | ||
| 776 | var decl_group = event.Group(BuildError!void).init(self.loop); | 784 | var decl_group = event.Group(BuildError!void).init(self.loop); |
| 777 | // TODO https://github.com/ziglang/zig/issues/1261 | 785 | var decl_group_consumed = false; |
| 778 | //errdefer decl_group.cancelAll(); | 786 | errdefer if (!decl_group_consumed) decl_group.cancelAll(); |
| 779 | 787 | ||
| 780 | var it = tree.root_node.decls.iterator(0); | 788 | var it = tree.root_node.decls.iterator(0); |
| 781 | while (it.next()) |decl_ptr| { | 789 | while (it.next()) |decl_ptr| { |
| ... | @@ -817,6 +825,7 @@ pub const Compilation = struct { | ... | @@ -817,6 +825,7 @@ pub const Compilation = struct { |
| 817 | else => unreachable, | 825 | else => unreachable, |
| 818 | } | 826 | } |
| 819 | } | 827 | } |
| 828 | decl_group_consumed = true; | ||
| 820 | try await (async decl_group.wait() catch unreachable); | 829 | try await (async decl_group.wait() catch unreachable); |
| 821 | 830 | ||
| 822 | // Now other code can rely on the decls scope having a complete list of names. | 831 | // Now other code can rely on the decls scope having a complete list of names. |
| ... | @@ -897,7 +906,7 @@ pub const Compilation = struct { | ... | @@ -897,7 +906,7 @@ pub const Compilation = struct { |
| 897 | } | 906 | } |
| 898 | 907 | ||
| 899 | async fn addTopLevelDecl(self: *Compilation, decls: *Scope.Decls, decl: *Decl) !void { | 908 | async fn addTopLevelDecl(self: *Compilation, decls: *Scope.Decls, decl: *Decl) !void { |
| 900 | const tree = &decl.findRootScope().tree; | 909 | const tree = decl.findRootScope().tree; |
| 901 | const is_export = decl.isExported(tree); | 910 | const is_export = decl.isExported(tree); |
| 902 | 911 | ||
| 903 | var add_to_table_resolved = false; | 912 | var add_to_table_resolved = false; |
| ... | @@ -927,25 +936,17 @@ pub const Compilation = struct { | ... | @@ -927,25 +936,17 @@ pub const Compilation = struct { |
| 927 | const text = try std.fmt.allocPrint(self.gpa(), fmt, args); | 936 | const text = try std.fmt.allocPrint(self.gpa(), fmt, args); |
| 928 | errdefer self.gpa().free(text); | 937 | errdefer self.gpa().free(text); |
| 929 | 938 | ||
| 930 | try self.prelink_group.call(addCompileErrorAsync, self, root, span, text); | 939 | const msg = try Msg.createFromScope(self, root, span, text); |
| 940 | errdefer msg.destroy(); | ||
| 941 | |||
| 942 | try self.prelink_group.call(addCompileErrorAsync, self, msg); | ||
| 931 | } | 943 | } |
| 932 | 944 | ||
| 933 | async fn addCompileErrorAsync( | 945 | async fn addCompileErrorAsync( |
| 934 | self: *Compilation, | 946 | self: *Compilation, |
| 935 | root: *Scope.Root, | 947 | msg: *Msg, |
| 936 | span: Span, | ||
| 937 | text: []u8, | ||
| 938 | ) !void { | 948 | ) !void { |
| 939 | const relpath = try os.path.relative(self.gpa(), self.event_loop_local.cwd, root.realpath); | 949 | errdefer msg.destroy(); |
| 940 | errdefer self.gpa().free(relpath); | ||
| 941 | |||
| 942 | const msg = try self.gpa().create(errmsg.Msg{ | ||
| 943 | .path = if (relpath.len < root.realpath.len) relpath else root.realpath, | ||
| 944 | .text = text, | ||
| 945 | .span = span, | ||
| 946 | .tree = &root.tree, | ||
| 947 | }); | ||
| 948 | errdefer self.gpa().destroy(msg); | ||
| 949 | 950 | ||
| 950 | const compile_errors = await (async self.compile_errors.acquire() catch unreachable); | 951 | const compile_errors = await (async self.compile_errors.acquire() catch unreachable); |
| 951 | defer compile_errors.release(); | 952 | defer compile_errors.release(); |
src-self-hosted/errmsg.zig+195-65| ... | @@ -4,6 +4,8 @@ const os = std.os; | ... | @@ -4,6 +4,8 @@ const os = std.os; |
| 4 | const Token = std.zig.Token; | 4 | const Token = std.zig.Token; |
| 5 | const ast = std.zig.ast; | 5 | const ast = std.zig.ast; |
| 6 | const TokenIndex = std.zig.ast.TokenIndex; | 6 | const TokenIndex = std.zig.ast.TokenIndex; |
| 7 | const Compilation = @import("compilation.zig").Compilation; | ||
| 8 | const Scope = @import("scope.zig").Scope; | ||
| 7 | 9 | ||
| 8 | pub const Color = enum { | 10 | pub const Color = enum { |
| 9 | Auto, | 11 | Auto, |
| ... | @@ -31,77 +33,205 @@ pub const Span = struct { | ... | @@ -31,77 +33,205 @@ pub const Span = struct { |
| 31 | }; | 33 | }; |
| 32 | 34 | ||
| 33 | pub const Msg = struct { | 35 | pub const Msg = struct { |
| 34 | path: []const u8, | ||
| 35 | text: []u8, | ||
| 36 | span: Span, | 36 | span: Span, |
| 37 | tree: *ast.Tree, | 37 | text: []u8, |
| 38 | }; | 38 | data: Data, |
| 39 | |||
| 40 | const Data = union(enum) { | ||
| 41 | PathAndTree: PathAndTree, | ||
| 42 | ScopeAndComp: ScopeAndComp, | ||
| 43 | }; | ||
| 44 | |||
| 45 | const PathAndTree = struct { | ||
| 46 | realpath: []const u8, | ||
| 47 | tree: *ast.Tree, | ||
| 48 | allocator: *mem.Allocator, | ||
| 49 | }; | ||
| 50 | |||
| 51 | const ScopeAndComp = struct { | ||
| 52 | root_scope: *Scope.Root, | ||
| 53 | compilation: *Compilation, | ||
| 54 | }; | ||
| 55 | |||
| 56 | pub fn destroy(self: *Msg) void { | ||
| 57 | switch (self.data) { | ||
| 58 | Data.PathAndTree => |path_and_tree| { | ||
| 59 | path_and_tree.allocator.free(self.text); | ||
| 60 | path_and_tree.allocator.destroy(self); | ||
| 61 | }, | ||
| 62 | Data.ScopeAndComp => |scope_and_comp| { | ||
| 63 | scope_and_comp.root_scope.base.deref(scope_and_comp.compilation); | ||
| 64 | scope_and_comp.compilation.gpa().free(self.text); | ||
| 65 | scope_and_comp.compilation.gpa().destroy(self); | ||
| 66 | }, | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | fn getAllocator(self: *const Msg) *mem.Allocator { | ||
| 71 | switch (self.data) { | ||
| 72 | Data.PathAndTree => |path_and_tree| { | ||
| 73 | return path_and_tree.allocator; | ||
| 74 | }, | ||
| 75 | Data.ScopeAndComp => |scope_and_comp| { | ||
| 76 | return scope_and_comp.compilation.gpa(); | ||
| 77 | }, | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | pub fn getRealPath(self: *const Msg) []const u8 { | ||
| 82 | switch (self.data) { | ||
| 83 | Data.PathAndTree => |path_and_tree| { | ||
| 84 | return path_and_tree.realpath; | ||
| 85 | }, | ||
| 86 | Data.ScopeAndComp => |scope_and_comp| { | ||
| 87 | return scope_and_comp.root_scope.realpath; | ||
| 88 | }, | ||
| 89 | } | ||
| 90 | } | ||
| 91 | |||
| 92 | pub fn getTree(self: *const Msg) *ast.Tree { | ||
| 93 | switch (self.data) { | ||
| 94 | Data.PathAndTree => |path_and_tree| { | ||
| 95 | return path_and_tree.tree; | ||
| 96 | }, | ||
| 97 | Data.ScopeAndComp => |scope_and_comp| { | ||
| 98 | return scope_and_comp.root_scope.tree; | ||
| 99 | }, | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | /// Takes ownership of text | ||
| 104 | /// References root_scope, and derefs when the msg is freed | ||
| 105 | pub fn createFromScope(comp: *Compilation, root_scope: *Scope.Root, span: Span, text: []u8) !*Msg { | ||
| 106 | const msg = try comp.gpa().create(Msg{ | ||
| 107 | .text = text, | ||
| 108 | .span = span, | ||
| 109 | .data = Data{ | ||
| 110 | .ScopeAndComp = ScopeAndComp{ | ||
| 111 | .root_scope = root_scope, | ||
| 112 | .compilation = comp, | ||
| 113 | }, | ||
| 114 | }, | ||
| 115 | }); | ||
| 116 | root_scope.base.ref(); | ||
| 117 | return msg; | ||
| 118 | } | ||
| 119 | |||
| 120 | pub fn createFromParseErrorAndScope( | ||
| 121 | comp: *Compilation, | ||
| 122 | root_scope: *Scope.Root, | ||
| 123 | parse_error: *const ast.Error, | ||
| 124 | ) !*Msg { | ||
| 125 | const loc_token = parse_error.loc(); | ||
| 126 | var text_buf = try std.Buffer.initSize(comp.gpa(), 0); | ||
| 127 | defer text_buf.deinit(); | ||
| 128 | |||
| 129 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; | ||
| 130 | try parse_error.render(&root_scope.tree.tokens, out_stream); | ||
| 131 | |||
| 132 | const msg = try comp.gpa().create(Msg{ | ||
| 133 | .text = undefined, | ||
| 134 | .span = Span{ | ||
| 135 | .first = loc_token, | ||
| 136 | .last = loc_token, | ||
| 137 | }, | ||
| 138 | .data = Data{ | ||
| 139 | .ScopeAndComp = ScopeAndComp{ | ||
| 140 | .root_scope = root_scope, | ||
| 141 | .compilation = comp, | ||
| 142 | }, | ||
| 143 | }, | ||
| 144 | }); | ||
| 145 | root_scope.base.ref(); | ||
| 146 | msg.text = text_buf.toOwnedSlice(); | ||
| 147 | return msg; | ||
| 148 | } | ||
| 149 | |||
| 150 | /// `realpath` must outlive the returned Msg | ||
| 151 | /// `tree` must outlive the returned Msg | ||
| 152 | /// Caller owns returned Msg and must free with `allocator` | ||
| 153 | /// allocator will additionally be used for printing messages later. | ||
| 154 | pub fn createFromParseError( | ||
| 155 | allocator: *mem.Allocator, | ||
| 156 | parse_error: *const ast.Error, | ||
| 157 | tree: *ast.Tree, | ||
| 158 | realpath: []const u8, | ||
| 159 | ) !*Msg { | ||
| 160 | const loc_token = parse_error.loc(); | ||
| 161 | var text_buf = try std.Buffer.initSize(allocator, 0); | ||
| 162 | defer text_buf.deinit(); | ||
| 163 | |||
| 164 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; | ||
| 165 | try parse_error.render(&tree.tokens, out_stream); | ||
| 166 | |||
| 167 | const msg = try allocator.create(Msg{ | ||
| 168 | .text = undefined, | ||
| 169 | .data = Data{ | ||
| 170 | .PathAndTree = PathAndTree{ | ||
| 171 | .allocator = allocator, | ||
| 172 | .realpath = realpath, | ||
| 173 | .tree = tree, | ||
| 174 | }, | ||
| 175 | }, | ||
| 176 | .span = Span{ | ||
| 177 | .first = loc_token, | ||
| 178 | .last = loc_token, | ||
| 179 | }, | ||
| 180 | }); | ||
| 181 | msg.text = text_buf.toOwnedSlice(); | ||
| 182 | errdefer allocator.destroy(msg); | ||
| 183 | |||
| 184 | return msg; | ||
| 185 | } | ||
| 186 | |||
| 187 | pub fn printToStream(msg: *const Msg, stream: var, color_on: bool) !void { | ||
| 188 | const allocator = msg.getAllocator(); | ||
| 189 | const realpath = msg.getRealPath(); | ||
| 190 | const tree = msg.getTree(); | ||
| 191 | |||
| 192 | const cwd = try os.getCwd(allocator); | ||
| 193 | defer allocator.free(cwd); | ||
| 194 | |||
| 195 | const relpath = try os.path.relative(allocator, cwd, realpath); | ||
| 196 | defer allocator.free(relpath); | ||
| 197 | |||
| 198 | const path = if (relpath.len < realpath.len) relpath else realpath; | ||
| 199 | |||
| 200 | const first_token = tree.tokens.at(msg.span.first); | ||
| 201 | const last_token = tree.tokens.at(msg.span.last); | ||
| 202 | const start_loc = tree.tokenLocationPtr(0, first_token); | ||
| 203 | const end_loc = tree.tokenLocationPtr(first_token.end, last_token); | ||
| 204 | if (!color_on) { | ||
| 205 | try stream.print( | ||
| 206 | "{}:{}:{}: error: {}\n", | ||
| 207 | path, | ||
| 208 | start_loc.line + 1, | ||
| 209 | start_loc.column + 1, | ||
| 210 | msg.text, | ||
| 211 | ); | ||
| 212 | return; | ||
| 213 | } | ||
| 39 | 214 | ||
| 40 | /// `path` must outlive the returned Msg | ||
| 41 | /// `tree` must outlive the returned Msg | ||
| 42 | /// Caller owns returned Msg and must free with `allocator` | ||
| 43 | pub fn createFromParseError( | ||
| 44 | allocator: *mem.Allocator, | ||
| 45 | parse_error: *const ast.Error, | ||
| 46 | tree: *ast.Tree, | ||
| 47 | path: []const u8, | ||
| 48 | ) !*Msg { | ||
| 49 | const loc_token = parse_error.loc(); | ||
| 50 | var text_buf = try std.Buffer.initSize(allocator, 0); | ||
| 51 | defer text_buf.deinit(); | ||
| 52 | |||
| 53 | var out_stream = &std.io.BufferOutStream.init(&text_buf).stream; | ||
| 54 | try parse_error.render(&tree.tokens, out_stream); | ||
| 55 | |||
| 56 | const msg = try allocator.create(Msg{ | ||
| 57 | .tree = tree, | ||
| 58 | .path = path, | ||
| 59 | .text = text_buf.toOwnedSlice(), | ||
| 60 | .span = Span{ | ||
| 61 | .first = loc_token, | ||
| 62 | .last = loc_token, | ||
| 63 | }, | ||
| 64 | }); | ||
| 65 | errdefer allocator.destroy(msg); | ||
| 66 | |||
| 67 | return msg; | ||
| 68 | } | ||
| 69 | |||
| 70 | pub fn printToStream(stream: var, msg: *const Msg, color_on: bool) !void { | ||
| 71 | const first_token = msg.tree.tokens.at(msg.span.first); | ||
| 72 | const last_token = msg.tree.tokens.at(msg.span.last); | ||
| 73 | const start_loc = msg.tree.tokenLocationPtr(0, first_token); | ||
| 74 | const end_loc = msg.tree.tokenLocationPtr(first_token.end, last_token); | ||
| 75 | if (!color_on) { | ||
| 76 | try stream.print( | 215 | try stream.print( |
| 77 | "{}:{}:{}: error: {}\n", | 216 | "{}:{}:{}: error: {}\n{}\n", |
| 78 | msg.path, | 217 | path, |
| 79 | start_loc.line + 1, | 218 | start_loc.line + 1, |
| 80 | start_loc.column + 1, | 219 | start_loc.column + 1, |
| 81 | msg.text, | 220 | msg.text, |
| 221 | tree.source[start_loc.line_start..start_loc.line_end], | ||
| 82 | ); | 222 | ); |
| 83 | return; | 223 | try stream.writeByteNTimes(' ', start_loc.column); |
| 224 | try stream.writeByteNTimes('~', last_token.end - first_token.start); | ||
| 225 | try stream.write("\n"); | ||
| 84 | } | 226 | } |
| 85 | 227 | ||
| 86 | try stream.print( | 228 | pub fn printToFile(msg: *const Msg, file: *os.File, color: Color) !void { |
| 87 | "{}:{}:{}: error: {}\n{}\n", | 229 | const color_on = switch (color) { |
| 88 | msg.path, | 230 | Color.Auto => file.isTty(), |
| 89 | start_loc.line + 1, | 231 | Color.On => true, |
| 90 | start_loc.column + 1, | 232 | Color.Off => false, |
| 91 | msg.text, | 233 | }; |
| 92 | msg.tree.source[start_loc.line_start..start_loc.line_end], | 234 | var stream = &std.io.FileOutStream.init(file).stream; |
| 93 | ); | 235 | return msg.printToStream(stream, color_on); |
| 94 | try stream.writeByteNTimes(' ', start_loc.column); | 236 | } |
| 95 | try stream.writeByteNTimes('~', last_token.end - first_token.start); | 237 | }; |
| 96 | try stream.write("\n"); | ||
| 97 | } | ||
| 98 | |||
| 99 | pub fn printToFile(file: *os.File, msg: *const Msg, color: Color) !void { | ||
| 100 | const color_on = switch (color) { | ||
| 101 | Color.Auto => file.isTty(), | ||
| 102 | Color.On => true, | ||
| 103 | Color.Off => false, | ||
| 104 | }; | ||
| 105 | var stream = &std.io.FileOutStream.init(file).stream; | ||
| 106 | return printToStream(stream, msg, color_on); | ||
| 107 | } |
src-self-hosted/main.zig+8-7| ... | @@ -485,7 +485,8 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { | ... | @@ -485,7 +485,8 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { |
| 485 | }, | 485 | }, |
| 486 | Compilation.Event.Fail => |msgs| { | 486 | Compilation.Event.Fail => |msgs| { |
| 487 | for (msgs) |msg| { | 487 | for (msgs) |msg| { |
| 488 | errmsg.printToFile(&stderr_file, msg, color) catch os.exit(1); | 488 | defer msg.destroy(); |
| 489 | msg.printToFile(&stderr_file, color) catch os.exit(1); | ||
| 489 | } | 490 | } |
| 490 | }, | 491 | }, |
| 491 | } | 492 | } |
| ... | @@ -646,10 +647,10 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -646,10 +647,10 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 646 | 647 | ||
| 647 | var error_it = tree.errors.iterator(0); | 648 | var error_it = tree.errors.iterator(0); |
| 648 | while (error_it.next()) |parse_error| { | 649 | while (error_it.next()) |parse_error| { |
| 649 | const msg = try errmsg.createFromParseError(allocator, parse_error, &tree, "<stdin>"); | 650 | const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>"); |
| 650 | defer allocator.destroy(msg); | 651 | defer msg.destroy(); |
| 651 | 652 | ||
| 652 | try errmsg.printToFile(&stderr_file, msg, color); | 653 | try msg.printToFile(&stderr_file, color); |
| 653 | } | 654 | } |
| 654 | if (tree.errors.len != 0) { | 655 | if (tree.errors.len != 0) { |
| 655 | os.exit(1); | 656 | os.exit(1); |
| ... | @@ -702,10 +703,10 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { | ... | @@ -702,10 +703,10 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 702 | 703 | ||
| 703 | var error_it = tree.errors.iterator(0); | 704 | var error_it = tree.errors.iterator(0); |
| 704 | while (error_it.next()) |parse_error| { | 705 | while (error_it.next()) |parse_error| { |
| 705 | const msg = try errmsg.createFromParseError(allocator, parse_error, &tree, file_path); | 706 | const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, file_path); |
| 706 | defer allocator.destroy(msg); | 707 | defer msg.destroy(); |
| 707 | 708 | ||
| 708 | try errmsg.printToFile(&stderr_file, msg, color); | 709 | try msg.printToFile(&stderr_file, color); |
| 709 | } | 710 | } |
| 710 | if (tree.errors.len != 0) { | 711 | if (tree.errors.len != 0) { |
| 711 | fmt.any_error = true; | 712 | fmt.any_error = true; |
src-self-hosted/scope.zig+4-3| ... | @@ -93,13 +93,13 @@ pub const Scope = struct { | ... | @@ -93,13 +93,13 @@ pub const Scope = struct { |
| 93 | 93 | ||
| 94 | pub const Root = struct { | 94 | pub const Root = struct { |
| 95 | base: Scope, | 95 | base: Scope, |
| 96 | tree: ast.Tree, | 96 | tree: *ast.Tree, |
| 97 | realpath: []const u8, | 97 | realpath: []const u8, |
| 98 | 98 | ||
| 99 | /// Creates a Root scope with 1 reference | 99 | /// Creates a Root scope with 1 reference |
| 100 | /// Takes ownership of realpath | 100 | /// Takes ownership of realpath |
| 101 | /// Caller must set tree | 101 | /// Takes ownership of tree, will deinit and destroy when done. |
| 102 | pub fn create(comp: *Compilation, tree: ast.Tree, realpath: []u8) !*Root { | 102 | pub fn create(comp: *Compilation, tree: *ast.Tree, realpath: []u8) !*Root { |
| 103 | const self = try comp.gpa().create(Root{ | 103 | const self = try comp.gpa().create(Root{ |
| 104 | .base = Scope{ | 104 | .base = Scope{ |
| 105 | .id = Id.Root, | 105 | .id = Id.Root, |
| ... | @@ -117,6 +117,7 @@ pub const Scope = struct { | ... | @@ -117,6 +117,7 @@ pub const Scope = struct { |
| 117 | pub fn destroy(self: *Root, comp: *Compilation) void { | 117 | pub fn destroy(self: *Root, comp: *Compilation) void { |
| 118 | comp.gpa().free(self.tree.source); | 118 | comp.gpa().free(self.tree.source); |
| 119 | self.tree.deinit(); | 119 | self.tree.deinit(); |
| 120 | comp.gpa().destroy(self.tree); | ||
| 120 | comp.gpa().free(self.realpath); | 121 | comp.gpa().free(self.realpath); |
| 121 | comp.gpa().destroy(self); | 122 | comp.gpa().destroy(self); |
| 122 | } | 123 | } |
src-self-hosted/test.zig+8-6| ... | @@ -184,7 +184,8 @@ pub const TestContext = struct { | ... | @@ -184,7 +184,8 @@ pub const TestContext = struct { |
| 184 | var stderr = try std.io.getStdErr(); | 184 | var stderr = try std.io.getStdErr(); |
| 185 | try stderr.write("build incorrectly failed:\n"); | 185 | try stderr.write("build incorrectly failed:\n"); |
| 186 | for (msgs) |msg| { | 186 | for (msgs) |msg| { |
| 187 | try errmsg.printToFile(&stderr, msg, errmsg.Color.Auto); | 187 | defer msg.destroy(); |
| 188 | try msg.printToFile(&stderr, errmsg.Color.Auto); | ||
| 188 | } | 189 | } |
| 189 | }, | 190 | }, |
| 190 | } | 191 | } |
| ... | @@ -211,10 +212,10 @@ pub const TestContext = struct { | ... | @@ -211,10 +212,10 @@ pub const TestContext = struct { |
| 211 | Compilation.Event.Fail => |msgs| { | 212 | Compilation.Event.Fail => |msgs| { |
| 212 | assertOrPanic(msgs.len != 0); | 213 | assertOrPanic(msgs.len != 0); |
| 213 | for (msgs) |msg| { | 214 | for (msgs) |msg| { |
| 214 | if (mem.endsWith(u8, msg.path, path) and mem.eql(u8, msg.text, text)) { | 215 | if (mem.endsWith(u8, msg.getRealPath(), path) and mem.eql(u8, msg.text, text)) { |
| 215 | const first_token = msg.tree.tokens.at(msg.span.first); | 216 | const first_token = msg.getTree().tokens.at(msg.span.first); |
| 216 | const last_token = msg.tree.tokens.at(msg.span.first); | 217 | const last_token = msg.getTree().tokens.at(msg.span.first); |
| 217 | const start_loc = msg.tree.tokenLocationPtr(0, first_token); | 218 | const start_loc = msg.getTree().tokenLocationPtr(0, first_token); |
| 218 | if (start_loc.line + 1 == line and start_loc.column + 1 == column) { | 219 | if (start_loc.line + 1 == line and start_loc.column + 1 == column) { |
| 219 | return; | 220 | return; |
| 220 | } | 221 | } |
| ... | @@ -231,7 +232,8 @@ pub const TestContext = struct { | ... | @@ -231,7 +232,8 @@ pub const TestContext = struct { |
| 231 | std.debug.warn("\n====found:========\n"); | 232 | std.debug.warn("\n====found:========\n"); |
| 232 | var stderr = try std.io.getStdErr(); | 233 | var stderr = try std.io.getStdErr(); |
| 233 | for (msgs) |msg| { | 234 | for (msgs) |msg| { |
| 234 | try errmsg.printToFile(&stderr, msg, errmsg.Color.Auto); | 235 | defer msg.destroy(); |
| 236 | try msg.printToFile(&stderr, errmsg.Color.Auto); | ||
| 235 | } | 237 | } |
| 236 | std.debug.warn("============\n"); | 238 | std.debug.warn("============\n"); |
| 237 | return error.TestFailed; | 239 | return error.TestFailed; |
std/mem.zig+10-2| ... | @@ -35,6 +35,7 @@ pub const Allocator = struct { | ... | @@ -35,6 +35,7 @@ pub const Allocator = struct { |
| 35 | freeFn: fn (self: *Allocator, old_mem: []u8) void, | 35 | freeFn: fn (self: *Allocator, old_mem: []u8) void, |
| 36 | 36 | ||
| 37 | /// Call `destroy` with the result | 37 | /// Call `destroy` with the result |
| 38 | /// TODO this is deprecated. use createOne instead | ||
| 38 | pub fn create(self: *Allocator, init: var) Error!*@typeOf(init) { | 39 | pub fn create(self: *Allocator, init: var) Error!*@typeOf(init) { |
| 39 | const T = @typeOf(init); | 40 | const T = @typeOf(init); |
| 40 | if (@sizeOf(T) == 0) return &(T{}); | 41 | if (@sizeOf(T) == 0) return &(T{}); |
| ... | @@ -44,6 +45,14 @@ pub const Allocator = struct { | ... | @@ -44,6 +45,14 @@ pub const Allocator = struct { |
| 44 | return ptr; | 45 | return ptr; |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 48 | /// Call `destroy` with the result. | ||
| 49 | /// Returns undefined memory. | ||
| 50 | pub fn createOne(self: *Allocator, comptime T: type) Error!*T { | ||
| 51 | if (@sizeOf(T) == 0) return &(T{}); | ||
| 52 | const slice = try self.alloc(T, 1); | ||
| 53 | return &slice[0]; | ||
| 54 | } | ||
| 55 | |||
| 47 | /// `ptr` should be the return value of `create` | 56 | /// `ptr` should be the return value of `create` |
| 48 | pub fn destroy(self: *Allocator, ptr: var) void { | 57 | pub fn destroy(self: *Allocator, ptr: var) void { |
| 49 | const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr)); | 58 | const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr)); |
| ... | @@ -149,13 +158,12 @@ pub fn copyBackwards(comptime T: type, dest: []T, source: []const T) void { | ... | @@ -149,13 +158,12 @@ pub fn copyBackwards(comptime T: type, dest: []T, source: []const T) void { |
| 149 | @setRuntimeSafety(false); | 158 | @setRuntimeSafety(false); |
| 150 | assert(dest.len >= source.len); | 159 | assert(dest.len >= source.len); |
| 151 | var i = source.len; | 160 | var i = source.len; |
| 152 | while(i > 0){ | 161 | while (i > 0) { |
| 153 | i -= 1; | 162 | i -= 1; |
| 154 | dest[i] = source[i]; | 163 | dest[i] = source[i]; |
| 155 | } | 164 | } |
| 156 | } | 165 | } |
| 157 | 166 | ||
| 158 | |||
| 159 | pub fn set(comptime T: type, dest: []T, value: T) void { | 167 | pub fn set(comptime T: type, dest: []T, value: T) void { |
| 160 | for (dest) |*d| | 168 | for (dest) |*d| |
| 161 | d.* = value; | 169 | d.* = value; |