| 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 | 24 | const Value = @import("value.zig").Value; |
| 25 | 25 | const Type = Value.Type; |
| 26 | 26 | const Span = errmsg.Span; |
| 27 | const Msg = errmsg.Msg; | |
| 27 | 28 | const codegen = @import("codegen.zig"); |
| 28 | 29 | const Package = @import("package.zig").Package; |
| 29 | 30 | const link = @import("link.zig").link; |
| ... | ... | @@ -40,8 +41,6 @@ pub const EventLoopLocal = struct { |
| 40 | 41 | |
| 41 | 42 | native_libc: event.Future(LibCInstallation), |
| 42 | 43 | |
| 43 | cwd: []const u8, | |
| 44 | ||
| 45 | 44 | var lazy_init_targets = std.lazyInit(void); |
| 46 | 45 | |
| 47 | 46 | fn init(loop: *event.Loop) !EventLoopLocal { |
| ... | ... | @@ -54,21 +53,16 @@ pub const EventLoopLocal = struct { |
| 54 | 53 | try std.os.getRandomBytes(seed_bytes[0..]); |
| 55 | 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 | 56 | return EventLoopLocal{ |
| 61 | 57 | .loop = loop, |
| 62 | 58 | .llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(), |
| 63 | 59 | .prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)), |
| 64 | 60 | .native_libc = event.Future(LibCInstallation).init(loop), |
| 65 | .cwd = cwd, | |
| 66 | 61 | }; |
| 67 | 62 | } |
| 68 | 63 | |
| 69 | 64 | /// Must be called only after EventLoop.run completes. |
| 70 | 65 | fn deinit(self: *EventLoopLocal) void { |
| 71 | self.loop.allocator.free(self.cwd); | |
| 72 | 66 | while (self.llvm_handle_pool.pop()) |node| { |
| 73 | 67 | c.LLVMContextDispose(node.data); |
| 74 | 68 | self.loop.allocator.destroy(node); |
| ... | ... | @@ -234,7 +228,7 @@ pub const Compilation = struct { |
| 234 | 228 | const PtrTypeTable = std.HashMap(*const Type.Pointer.Key, *Type.Pointer, Type.Pointer.Key.hash, Type.Pointer.Key.eql); |
| 235 | 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 | 233 | // TODO handle some of these earlier and report them in a way other than error codes |
| 240 | 234 | pub const BuildError = error{ |
| ... | ... | @@ -286,7 +280,7 @@ pub const Compilation = struct { |
| 286 | 280 | pub const Event = union(enum) { |
| 287 | 281 | Ok, |
| 288 | 282 | Error: BuildError, |
| 289 | Fail: []*errmsg.Msg, | |
| 283 | Fail: []*Msg, | |
| 290 | 284 | }; |
| 291 | 285 | |
| 292 | 286 | pub const DarwinVersionMin = union(enum) { |
| ... | ... | @@ -761,21 +755,35 @@ pub const Compilation = struct { |
| 761 | 755 | }; |
| 762 | 756 | errdefer self.gpa().free(source_code); |
| 763 | 757 | |
| 764 | var tree = try std.zig.parse(self.gpa(), source_code); | |
| 765 | errdefer tree.deinit(); | |
| 758 | const tree = try self.gpa().createOne(ast.Tree); | |
| 759 | tree.* = try std.zig.parse(self.gpa(), source_code); | |
| 760 | errdefer { | |
| 761 | tree.deinit(); | |
| 762 | self.gpa().destroy(tree); | |
| 763 | } | |
| 766 | 764 | |
| 767 | 765 | break :blk try Scope.Root.create(self, tree, root_src_real_path); |
| 768 | 766 | }; |
| 769 | 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 | 781 | const decls = try Scope.Decls.create(self, &root_scope.base); |
| 774 | 782 | defer decls.base.deref(self); |
| 775 | 783 | |
| 776 | 784 | var decl_group = event.Group(BuildError!void).init(self.loop); |
| 777 | // TODO https://github.com/ziglang/zig/issues/1261 | |
| 778 | //errdefer decl_group.cancelAll(); | |
| 785 | var decl_group_consumed = false; | |
| 786 | errdefer if (!decl_group_consumed) decl_group.cancelAll(); | |
| 779 | 787 | |
| 780 | 788 | var it = tree.root_node.decls.iterator(0); |
| 781 | 789 | while (it.next()) |decl_ptr| { |
| ... | ... | @@ -817,6 +825,7 @@ pub const Compilation = struct { |
| 817 | 825 | else => unreachable, |
| 818 | 826 | } |
| 819 | 827 | } |
| 828 | decl_group_consumed = true; | |
| 820 | 829 | try await (async decl_group.wait() catch unreachable); |
| 821 | 830 | |
| 822 | 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 | 906 | } |
| 898 | 907 | |
| 899 | 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 | 910 | const is_export = decl.isExported(tree); |
| 902 | 911 | |
| 903 | 912 | var add_to_table_resolved = false; |
| ... | ... | @@ -927,25 +936,17 @@ pub const Compilation = struct { |
| 927 | 936 | const text = try std.fmt.allocPrint(self.gpa(), fmt, args); |
| 928 | 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 | 945 | async fn addCompileErrorAsync( |
| 934 | 946 | self: *Compilation, |
| 935 | root: *Scope.Root, | |
| 936 | span: Span, | |
| 937 | text: []u8, | |
| 947 | msg: *Msg, | |
| 938 | 948 | ) !void { |
| 939 | const relpath = try os.path.relative(self.gpa(), self.event_loop_local.cwd, root.realpath); | |
| 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 | errdefer msg.destroy(); | |
| 949 | 950 | |
| 950 | 951 | const compile_errors = await (async self.compile_errors.acquire() catch unreachable); |
| 951 | 952 | defer compile_errors.release(); |
src-self-hosted/errmsg.zig+195-65| ... | ... | @@ -4,6 +4,8 @@ const os = std.os; |
| 4 | 4 | const Token = std.zig.Token; |
| 5 | 5 | const ast = std.zig.ast; |
| 6 | 6 | const TokenIndex = std.zig.ast.TokenIndex; |
| 7 | const Compilation = @import("compilation.zig").Compilation; | |
| 8 | const Scope = @import("scope.zig").Scope; | |
| 7 | 9 | |
| 8 | 10 | pub const Color = enum { |
| 9 | 11 | Auto, |
| ... | ... | @@ -31,77 +33,205 @@ pub const Span = struct { |
| 31 | 33 | }; |
| 32 | 34 | |
| 33 | 35 | pub const Msg = struct { |
| 34 | path: []const u8, | |
| 35 | text: []u8, | |
| 36 | 36 | span: Span, |
| 37 | tree: *ast.Tree, | |
| 38 | }; | |
| 37 | text: []u8, | |
| 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 | 215 | try stream.print( |
| 77 | "{}:{}:{}: error: {}\n", | |
| 78 | msg.path, | |
| 216 | "{}:{}:{}: error: {}\n{}\n", | |
| 217 | path, | |
| 79 | 218 | start_loc.line + 1, |
| 80 | 219 | start_loc.column + 1, |
| 81 | 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( | |
| 87 | "{}:{}:{}: error: {}\n{}\n", | |
| 88 | msg.path, | |
| 89 | start_loc.line + 1, | |
| 90 | start_loc.column + 1, | |
| 91 | msg.text, | |
| 92 | msg.tree.source[start_loc.line_start..start_loc.line_end], | |
| 93 | ); | |
| 94 | try stream.writeByteNTimes(' ', start_loc.column); | |
| 95 | try stream.writeByteNTimes('~', last_token.end - first_token.start); | |
| 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 | } | |
| 228 | pub fn printToFile(msg: *const Msg, file: *os.File, color: Color) !void { | |
| 229 | const color_on = switch (color) { | |
| 230 | Color.Auto => file.isTty(), | |
| 231 | Color.On => true, | |
| 232 | Color.Off => false, | |
| 233 | }; | |
| 234 | var stream = &std.io.FileOutStream.init(file).stream; | |
| 235 | return msg.printToStream(stream, color_on); | |
| 236 | } | |
| 237 | }; |
src-self-hosted/main.zig+8-7| ... | ... | @@ -485,7 +485,8 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void { |
| 485 | 485 | }, |
| 486 | 486 | Compilation.Event.Fail => |msgs| { |
| 487 | 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 | 647 | |
| 647 | 648 | var error_it = tree.errors.iterator(0); |
| 648 | 649 | while (error_it.next()) |parse_error| { |
| 649 | const msg = try errmsg.createFromParseError(allocator, parse_error, &tree, "<stdin>"); | |
| 650 | defer allocator.destroy(msg); | |
| 650 | const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>"); | |
| 651 | defer msg.destroy(); | |
| 651 | 652 | |
| 652 | try errmsg.printToFile(&stderr_file, msg, color); | |
| 653 | try msg.printToFile(&stderr_file, color); | |
| 653 | 654 | } |
| 654 | 655 | if (tree.errors.len != 0) { |
| 655 | 656 | os.exit(1); |
| ... | ... | @@ -702,10 +703,10 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void { |
| 702 | 703 | |
| 703 | 704 | var error_it = tree.errors.iterator(0); |
| 704 | 705 | while (error_it.next()) |parse_error| { |
| 705 | const msg = try errmsg.createFromParseError(allocator, parse_error, &tree, file_path); | |
| 706 | defer allocator.destroy(msg); | |
| 706 | const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, file_path); | |
| 707 | defer msg.destroy(); | |
| 707 | 708 | |
| 708 | try errmsg.printToFile(&stderr_file, msg, color); | |
| 709 | try msg.printToFile(&stderr_file, color); | |
| 709 | 710 | } |
| 710 | 711 | if (tree.errors.len != 0) { |
| 711 | 712 | fmt.any_error = true; |
src-self-hosted/scope.zig+4-3| ... | ... | @@ -93,13 +93,13 @@ pub const Scope = struct { |
| 93 | 93 | |
| 94 | 94 | pub const Root = struct { |
| 95 | 95 | base: Scope, |
| 96 | tree: ast.Tree, | |
| 96 | tree: *ast.Tree, | |
| 97 | 97 | realpath: []const u8, |
| 98 | 98 | |
| 99 | 99 | /// Creates a Root scope with 1 reference |
| 100 | 100 | /// Takes ownership of realpath |
| 101 | /// Caller must set tree | |
| 102 | pub fn create(comp: *Compilation, tree: ast.Tree, realpath: []u8) !*Root { | |
| 101 | /// Takes ownership of tree, will deinit and destroy when done. | |
| 102 | pub fn create(comp: *Compilation, tree: *ast.Tree, realpath: []u8) !*Root { | |
| 103 | 103 | const self = try comp.gpa().create(Root{ |
| 104 | 104 | .base = Scope{ |
| 105 | 105 | .id = Id.Root, |
| ... | ... | @@ -117,6 +117,7 @@ pub const Scope = struct { |
| 117 | 117 | pub fn destroy(self: *Root, comp: *Compilation) void { |
| 118 | 118 | comp.gpa().free(self.tree.source); |
| 119 | 119 | self.tree.deinit(); |
| 120 | comp.gpa().destroy(self.tree); | |
| 120 | 121 | comp.gpa().free(self.realpath); |
| 121 | 122 | comp.gpa().destroy(self); |
| 122 | 123 | } |
src-self-hosted/test.zig+8-6| ... | ... | @@ -184,7 +184,8 @@ pub const TestContext = struct { |
| 184 | 184 | var stderr = try std.io.getStdErr(); |
| 185 | 185 | try stderr.write("build incorrectly failed:\n"); |
| 186 | 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 | 212 | Compilation.Event.Fail => |msgs| { |
| 212 | 213 | assertOrPanic(msgs.len != 0); |
| 213 | 214 | for (msgs) |msg| { |
| 214 | if (mem.endsWith(u8, msg.path, path) and mem.eql(u8, msg.text, text)) { | |
| 215 | const first_token = msg.tree.tokens.at(msg.span.first); | |
| 216 | const last_token = msg.tree.tokens.at(msg.span.first); | |
| 217 | const start_loc = msg.tree.tokenLocationPtr(0, first_token); | |
| 215 | if (mem.endsWith(u8, msg.getRealPath(), path) and mem.eql(u8, msg.text, text)) { | |
| 216 | const first_token = msg.getTree().tokens.at(msg.span.first); | |
| 217 | const last_token = msg.getTree().tokens.at(msg.span.first); | |
| 218 | const start_loc = msg.getTree().tokenLocationPtr(0, first_token); | |
| 218 | 219 | if (start_loc.line + 1 == line and start_loc.column + 1 == column) { |
| 219 | 220 | return; |
| 220 | 221 | } |
| ... | ... | @@ -231,7 +232,8 @@ pub const TestContext = struct { |
| 231 | 232 | std.debug.warn("\n====found:========\n"); |
| 232 | 233 | var stderr = try std.io.getStdErr(); |
| 233 | 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 | 238 | std.debug.warn("============\n"); |
| 237 | 239 | return error.TestFailed; |
std/mem.zig+10-2| ... | ... | @@ -35,6 +35,7 @@ pub const Allocator = struct { |
| 35 | 35 | freeFn: fn (self: *Allocator, old_mem: []u8) void, |
| 36 | 36 | |
| 37 | 37 | /// Call `destroy` with the result |
| 38 | /// TODO this is deprecated. use createOne instead | |
| 38 | 39 | pub fn create(self: *Allocator, init: var) Error!*@typeOf(init) { |
| 39 | 40 | const T = @typeOf(init); |
| 40 | 41 | if (@sizeOf(T) == 0) return &(T{}); |
| ... | ... | @@ -44,6 +45,14 @@ pub const Allocator = struct { |
| 44 | 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 | 56 | /// `ptr` should be the return value of `create` |
| 48 | 57 | pub fn destroy(self: *Allocator, ptr: var) void { |
| 49 | 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 | 158 | @setRuntimeSafety(false); |
| 150 | 159 | assert(dest.len >= source.len); |
| 151 | 160 | var i = source.len; |
| 152 | while(i > 0){ | |
| 161 | while (i > 0) { | |
| 153 | 162 | i -= 1; |
| 154 | 163 | dest[i] = source[i]; |
| 155 | 164 | } |
| 156 | 165 | } |
| 157 | 166 | |
| 158 | ||
| 159 | 167 | pub fn set(comptime T: type, dest: []T, value: T) void { |
| 160 | 168 | for (dest) |*d| |
| 161 | 169 | d.* = value; |