| author | |
| committer | |
| log | 8bd01d2d9bbda1a2e044223db4b2272e7c5020a0 |
| tree | 9f7a7726478b6a1fc0a9b26385a08cf95b5d6e4c |
| parent | 98dc28bbe223cb7183aabe7ed7a847c67c1a4df9 |
One thing is missing for it to be useful, however, which is dealing with
ambiguous reference errors introduced by the inlining process.3 files changed, 108 insertions(+), 20 deletions(-)
lib/std/zig/render.zig+28-4| ... | @@ -24,8 +24,11 @@ pub const Fixups = struct { | ... | @@ -24,8 +24,11 @@ pub const Fixups = struct { |
| 24 | gut_functions: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{}, | 24 | gut_functions: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{}, |
| 25 | /// These global declarations will be omitted. | 25 | /// These global declarations will be omitted. |
| 26 | omit_nodes: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{}, | 26 | omit_nodes: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{}, |
| 27 | /// These expressions will be replaced with `undefined`. | 27 | /// These expressions will be replaced with the string value. |
| 28 | replace_nodes: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{}, | 28 | replace_nodes: std.AutoHashMapUnmanaged(Ast.Node.Index, []const u8) = .{}, |
| 29 | /// All `@import` builtin calls which refer to a file path will be prefixed | ||
| 30 | /// with this path. | ||
| 31 | rebase_imported_paths: ?[]const u8 = null, | ||
| 29 | 32 | ||
| 30 | pub fn count(f: Fixups) usize { | 33 | pub fn count(f: Fixups) usize { |
| 31 | return f.unused_var_decls.count() + | 34 | return f.unused_var_decls.count() + |
| ... | @@ -277,8 +280,8 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { | ... | @@ -277,8 +280,8 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 277 | const main_tokens = tree.nodes.items(.main_token); | 280 | const main_tokens = tree.nodes.items(.main_token); |
| 278 | const node_tags = tree.nodes.items(.tag); | 281 | const node_tags = tree.nodes.items(.tag); |
| 279 | const datas = tree.nodes.items(.data); | 282 | const datas = tree.nodes.items(.data); |
| 280 | if (r.fixups.replace_nodes.contains(node)) { | 283 | if (r.fixups.replace_nodes.get(node)) |replacement| { |
| 281 | try ais.writer().writeAll("undefined"); | 284 | try ais.writer().writeAll(replacement); |
| 282 | try renderOnlySpace(r, space); | 285 | try renderOnlySpace(r, space); |
| 283 | return; | 286 | return; |
| 284 | } | 287 | } |
| ... | @@ -1515,6 +1518,7 @@ fn renderBuiltinCall( | ... | @@ -1515,6 +1518,7 @@ fn renderBuiltinCall( |
| 1515 | const tree = r.tree; | 1518 | const tree = r.tree; |
| 1516 | const ais = r.ais; | 1519 | const ais = r.ais; |
| 1517 | const token_tags = tree.tokens.items(.tag); | 1520 | const token_tags = tree.tokens.items(.tag); |
| 1521 | const main_tokens = tree.nodes.items(.main_token); | ||
| 1518 | 1522 | ||
| 1519 | // TODO remove before release of 0.12.0 | 1523 | // TODO remove before release of 0.12.0 |
| 1520 | const slice = tree.tokenSlice(builtin_token); | 1524 | const slice = tree.tokenSlice(builtin_token); |
| ... | @@ -1609,6 +1613,26 @@ fn renderBuiltinCall( | ... | @@ -1609,6 +1613,26 @@ fn renderBuiltinCall( |
| 1609 | return renderToken(r, builtin_token + 2, space); // ) | 1613 | return renderToken(r, builtin_token + 2, space); // ) |
| 1610 | } | 1614 | } |
| 1611 | 1615 | ||
| 1616 | if (r.fixups.rebase_imported_paths) |prefix| { | ||
| 1617 | if (mem.eql(u8, slice, "@import")) f: { | ||
| 1618 | const param = params[0]; | ||
| 1619 | const str_lit_token = main_tokens[param]; | ||
| 1620 | assert(token_tags[str_lit_token] == .string_literal); | ||
| 1621 | const token_bytes = tree.tokenSlice(str_lit_token); | ||
| 1622 | const imported_string = std.zig.string_literal.parseAlloc(r.gpa, token_bytes) catch |err| switch (err) { | ||
| 1623 | error.OutOfMemory => return error.OutOfMemory, | ||
| 1624 | error.InvalidLiteral => break :f, | ||
| 1625 | }; | ||
| 1626 | defer r.gpa.free(imported_string); | ||
| 1627 | const new_string = try std.fs.path.resolvePosix(r.gpa, &.{ prefix, imported_string }); | ||
| 1628 | defer r.gpa.free(new_string); | ||
| 1629 | |||
| 1630 | try renderToken(r, builtin_token + 1, .none); // ( | ||
| 1631 | try ais.writer().print("\"{}\"", .{std.zig.fmtEscapes(new_string)}); | ||
| 1632 | return renderToken(r, str_lit_token + 1, space); // ) | ||
| 1633 | } | ||
| 1634 | } | ||
| 1635 | |||
| 1612 | const last_param = params[params.len - 1]; | 1636 | const last_param = params[params.len - 1]; |
| 1613 | const after_last_param_token = tree.lastToken(last_param) + 1; | 1637 | const after_last_param_token = tree.lastToken(last_param) + 1; |
| 1614 | 1638 |
src/reduce.zig+47-10| ... | @@ -109,8 +109,11 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -109,8 +109,11 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 109 | var rendered = std.ArrayList(u8).init(gpa); | 109 | var rendered = std.ArrayList(u8).init(gpa); |
| 110 | defer rendered.deinit(); | 110 | defer rendered.deinit(); |
| 111 | 111 | ||
| 112 | var tree = try parse(gpa, arena, root_source_file_path); | 112 | var tree = try parse(gpa, root_source_file_path); |
| 113 | defer tree.deinit(gpa); | 113 | defer { |
| 114 | gpa.free(tree.source); | ||
| 115 | tree.deinit(gpa); | ||
| 116 | } | ||
| 114 | 117 | ||
| 115 | if (!skip_smoke_test) { | 118 | if (!skip_smoke_test) { |
| 116 | std.debug.print("smoke testing the interestingness check...\n", .{}); | 119 | std.debug.print("smoke testing the interestingness check...\n", .{}); |
| ... | @@ -159,7 +162,7 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -159,7 +162,7 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 159 | subset_size = @max(1, subset_size / 2); | 162 | subset_size = @max(1, subset_size / 2); |
| 160 | 163 | ||
| 161 | const this_set = transformations.items[start_index..][0..subset_size]; | 164 | const this_set = transformations.items[start_index..][0..subset_size]; |
| 162 | try transformationsToFixups(gpa, this_set, &fixups); | 165 | try transformationsToFixups(gpa, arena, root_source_file_path, this_set, &fixups); |
| 163 | 166 | ||
| 164 | rendered.clearRetainingCapacity(); | 167 | rendered.clearRetainingCapacity(); |
| 165 | try tree.renderToArrayList(&rendered, fixups); | 168 | try tree.renderToArrayList(&rendered, fixups); |
| ... | @@ -171,7 +174,8 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { | ... | @@ -171,7 +174,8 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 171 | }); | 174 | }); |
| 172 | switch (interestingness) { | 175 | switch (interestingness) { |
| 173 | .interesting => { | 176 | .interesting => { |
| 174 | const new_tree = try parse(gpa, arena, root_source_file_path); | 177 | const new_tree = try parse(gpa, root_source_file_path); |
| 178 | gpa.free(tree.source); | ||
| 175 | tree.deinit(gpa); | 179 | tree.deinit(gpa); |
| 176 | tree = new_tree; | 180 | tree = new_tree; |
| 177 | 181 | ||
| ... | @@ -241,6 +245,8 @@ fn runCheck(arena: std.mem.Allocator, argv: []const []const u8) !Interestingness | ... | @@ -241,6 +245,8 @@ fn runCheck(arena: std.mem.Allocator, argv: []const []const u8) !Interestingness |
| 241 | 245 | ||
| 242 | fn transformationsToFixups( | 246 | fn transformationsToFixups( |
| 243 | gpa: Allocator, | 247 | gpa: Allocator, |
| 248 | arena: Allocator, | ||
| 249 | root_source_file_path: []const u8, | ||
| 244 | transforms: []const Walk.Transformation, | 250 | transforms: []const Walk.Transformation, |
| 245 | fixups: *Ast.Fixups, | 251 | fixups: *Ast.Fixups, |
| 246 | ) !void { | 252 | ) !void { |
| ... | @@ -254,20 +260,51 @@ fn transformationsToFixups( | ... | @@ -254,20 +260,51 @@ fn transformationsToFixups( |
| 254 | try fixups.omit_nodes.put(gpa, decl_node, {}); | 260 | try fixups.omit_nodes.put(gpa, decl_node, {}); |
| 255 | }, | 261 | }, |
| 256 | .replace_with_undef => |node| { | 262 | .replace_with_undef => |node| { |
| 257 | try fixups.replace_nodes.put(gpa, node, {}); | 263 | try fixups.replace_nodes.put(gpa, node, "undefined"); |
| 264 | }, | ||
| 265 | .inline_imported_file => |inline_imported_file| { | ||
| 266 | defer gpa.free(inline_imported_file.imported_string); | ||
| 267 | const full_imported_path = try std.fs.path.join(gpa, &.{ | ||
| 268 | std.fs.path.dirname(root_source_file_path) orelse ".", | ||
| 269 | inline_imported_file.imported_string, | ||
| 270 | }); | ||
| 271 | defer gpa.free(full_imported_path); | ||
| 272 | var other_file_ast = try parse(gpa, full_imported_path); | ||
| 273 | defer { | ||
| 274 | gpa.free(other_file_ast.source); | ||
| 275 | other_file_ast.deinit(gpa); | ||
| 276 | } | ||
| 277 | var other_source = std.ArrayList(u8).init(gpa); | ||
| 278 | defer other_source.deinit(); | ||
| 279 | var inlined_fixups: Ast.Fixups = .{}; | ||
| 280 | defer inlined_fixups.deinit(gpa); | ||
| 281 | try other_source.appendSlice("struct {\n"); | ||
| 282 | try other_file_ast.renderToArrayList(&other_source, .{ | ||
| 283 | .rebase_imported_paths = std.fs.path.dirname(inline_imported_file.imported_string), | ||
| 284 | }); | ||
| 285 | try other_source.appendSlice("}"); | ||
| 286 | |||
| 287 | try fixups.replace_nodes.put( | ||
| 288 | gpa, | ||
| 289 | inline_imported_file.builtin_call_node, | ||
| 290 | try arena.dupe(u8, other_source.items), | ||
| 291 | ); | ||
| 258 | }, | 292 | }, |
| 259 | }; | 293 | }; |
| 260 | } | 294 | } |
| 261 | 295 | ||
| 262 | fn parse(gpa: Allocator, arena: Allocator, root_source_file_path: []const u8) !Ast { | 296 | fn parse(gpa: Allocator, file_path: []const u8) !Ast { |
| 263 | const source_code = try std.fs.cwd().readFileAllocOptions( | 297 | const source_code = std.fs.cwd().readFileAllocOptions( |
| 264 | arena, | 298 | gpa, |
| 265 | root_source_file_path, | 299 | file_path, |
| 266 | std.math.maxInt(u32), | 300 | std.math.maxInt(u32), |
| 267 | null, | 301 | null, |
| 268 | 1, | 302 | 1, |
| 269 | 0, | 303 | 0, |
| 270 | ); | 304 | ) catch |err| { |
| 305 | fatal("unable to open '{s}': {s}", .{ file_path, @errorName(err) }); | ||
| 306 | }; | ||
| 307 | errdefer gpa.free(source_code); | ||
| 271 | 308 | ||
| 272 | var tree = try Ast.parse(gpa, source_code, .zig); | 309 | var tree = try Ast.parse(gpa, source_code, .zig); |
| 273 | errdefer tree.deinit(gpa); | 310 | errdefer tree.deinit(gpa); |
src/reduce/Walk.zig+33-6| ... | @@ -2,6 +2,7 @@ const std = @import("std"); | ... | @@ -2,6 +2,7 @@ const std = @import("std"); |
| 2 | const Ast = std.zig.Ast; | 2 | const Ast = std.zig.Ast; |
| 3 | const Walk = @This(); | 3 | const Walk = @This(); |
| 4 | const assert = std.debug.assert; | 4 | const assert = std.debug.assert; |
| 5 | const BuiltinFn = @import("../BuiltinFn.zig"); | ||
| 5 | 6 | ||
| 6 | ast: *const Ast, | 7 | ast: *const Ast, |
| 7 | transformations: *std.ArrayList(Transformation), | 8 | transformations: *std.ArrayList(Transformation), |
| ... | @@ -16,6 +17,11 @@ pub const Transformation = union(enum) { | ... | @@ -16,6 +17,11 @@ pub const Transformation = union(enum) { |
| 16 | delete_node: Ast.Node.Index, | 17 | delete_node: Ast.Node.Index, |
| 17 | /// Replace an expression with `undefined`. | 18 | /// Replace an expression with `undefined`. |
| 18 | replace_with_undef: Ast.Node.Index, | 19 | replace_with_undef: Ast.Node.Index, |
| 20 | /// Replace an `@import` with the imported file contents wrapped in a struct. | ||
| 21 | inline_imported_file: struct { | ||
| 22 | builtin_call_node: Ast.Node.Index, | ||
| 23 | imported_string: []const u8, | ||
| 24 | }, | ||
| 19 | }; | 25 | }; |
| 20 | 26 | ||
| 21 | pub const Error = error{OutOfMemory}; | 27 | pub const Error = error{OutOfMemory}; |
| ... | @@ -437,16 +443,16 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void { | ... | @@ -437,16 +443,16 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void { |
| 437 | 443 | ||
| 438 | .builtin_call_two, .builtin_call_two_comma => { | 444 | .builtin_call_two, .builtin_call_two_comma => { |
| 439 | if (datas[node].lhs == 0) { | 445 | if (datas[node].lhs == 0) { |
| 440 | return walkBuiltinCall(w, main_tokens[node], &.{}); | 446 | return walkBuiltinCall(w, node, &.{}); |
| 441 | } else if (datas[node].rhs == 0) { | 447 | } else if (datas[node].rhs == 0) { |
| 442 | return walkBuiltinCall(w, main_tokens[node], &.{datas[node].lhs}); | 448 | return walkBuiltinCall(w, node, &.{datas[node].lhs}); |
| 443 | } else { | 449 | } else { |
| 444 | return walkBuiltinCall(w, main_tokens[node], &.{ datas[node].lhs, datas[node].rhs }); | 450 | return walkBuiltinCall(w, node, &.{ datas[node].lhs, datas[node].rhs }); |
| 445 | } | 451 | } |
| 446 | }, | 452 | }, |
| 447 | .builtin_call, .builtin_call_comma => { | 453 | .builtin_call, .builtin_call_comma => { |
| 448 | const params = ast.extra_data[datas[node].lhs..datas[node].rhs]; | 454 | const params = ast.extra_data[datas[node].lhs..datas[node].rhs]; |
| 449 | return walkBuiltinCall(w, main_tokens[node], params); | 455 | return walkBuiltinCall(w, node, params); |
| 450 | }, | 456 | }, |
| 451 | 457 | ||
| 452 | .fn_proto_simple, | 458 | .fn_proto_simple, |
| ... | @@ -680,10 +686,31 @@ fn walkContainerDecl( | ... | @@ -680,10 +686,31 @@ fn walkContainerDecl( |
| 680 | 686 | ||
| 681 | fn walkBuiltinCall( | 687 | fn walkBuiltinCall( |
| 682 | w: *Walk, | 688 | w: *Walk, |
| 683 | builtin_token: Ast.TokenIndex, | 689 | call_node: Ast.Node.Index, |
| 684 | params: []const Ast.Node.Index, | 690 | params: []const Ast.Node.Index, |
| 685 | ) Error!void { | 691 | ) Error!void { |
| 686 | _ = builtin_token; | 692 | const ast = w.ast; |
| 693 | const gpa = w.gpa; | ||
| 694 | const main_tokens = ast.nodes.items(.main_token); | ||
| 695 | const builtin_token = main_tokens[call_node]; | ||
| 696 | const builtin_name = ast.tokenSlice(builtin_token); | ||
| 697 | const info = BuiltinFn.list.get(builtin_name).?; | ||
| 698 | switch (info.tag) { | ||
| 699 | .import => { | ||
| 700 | const operand_node = params[0]; | ||
| 701 | const str_lit_token = main_tokens[operand_node]; | ||
| 702 | const token_bytes = ast.tokenSlice(str_lit_token); | ||
| 703 | const imported_string = std.zig.string_literal.parseAlloc(gpa, token_bytes) catch | ||
| 704 | unreachable; | ||
| 705 | if (std.mem.endsWith(u8, imported_string, ".zig")) { | ||
| 706 | try w.transformations.append(.{ .inline_imported_file = .{ | ||
| 707 | .builtin_call_node = call_node, | ||
| 708 | .imported_string = imported_string, | ||
| 709 | } }); | ||
| 710 | } | ||
| 711 | }, | ||
| 712 | else => {}, | ||
| 713 | } | ||
| 687 | for (params) |param_node| { | 714 | for (params) |param_node| { |
| 688 | try walkExpression(w, param_node); | 715 | try walkExpression(w, param_node); |
| 689 | } | 716 | } |