| 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 | 24 | gut_functions: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{}, |
| 25 | 25 | /// These global declarations will be omitted. |
| 26 | 26 | omit_nodes: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{}, |
| 27 | /// These expressions will be replaced with `undefined`. | |
| 28 | replace_nodes: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{}, | |
| 27 | /// These expressions will be replaced with the string value. | |
| 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 | 33 | pub fn count(f: Fixups) usize { |
| 31 | 34 | return f.unused_var_decls.count() + |
| ... | ... | @@ -277,8 +280,8 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 277 | 280 | const main_tokens = tree.nodes.items(.main_token); |
| 278 | 281 | const node_tags = tree.nodes.items(.tag); |
| 279 | 282 | const datas = tree.nodes.items(.data); |
| 280 | if (r.fixups.replace_nodes.contains(node)) { | |
| 281 | try ais.writer().writeAll("undefined"); | |
| 283 | if (r.fixups.replace_nodes.get(node)) |replacement| { | |
| 284 | try ais.writer().writeAll(replacement); | |
| 282 | 285 | try renderOnlySpace(r, space); |
| 283 | 286 | return; |
| 284 | 287 | } |
| ... | ... | @@ -1515,6 +1518,7 @@ fn renderBuiltinCall( |
| 1515 | 1518 | const tree = r.tree; |
| 1516 | 1519 | const ais = r.ais; |
| 1517 | 1520 | const token_tags = tree.tokens.items(.tag); |
| 1521 | const main_tokens = tree.nodes.items(.main_token); | |
| 1518 | 1522 | |
| 1519 | 1523 | // TODO remove before release of 0.12.0 |
| 1520 | 1524 | const slice = tree.tokenSlice(builtin_token); |
| ... | ... | @@ -1609,6 +1613,26 @@ fn renderBuiltinCall( |
| 1609 | 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 | 1636 | const last_param = params[params.len - 1]; |
| 1613 | 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 | 109 | var rendered = std.ArrayList(u8).init(gpa); |
| 110 | 110 | defer rendered.deinit(); |
| 111 | 111 | |
| 112 | var tree = try parse(gpa, arena, root_source_file_path); | |
| 113 | defer tree.deinit(gpa); | |
| 112 | var tree = try parse(gpa, root_source_file_path); | |
| 113 | defer { | |
| 114 | gpa.free(tree.source); | |
| 115 | tree.deinit(gpa); | |
| 116 | } | |
| 114 | 117 | |
| 115 | 118 | if (!skip_smoke_test) { |
| 116 | 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 | 162 | subset_size = @max(1, subset_size / 2); |
| 160 | 163 | |
| 161 | 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 | 167 | rendered.clearRetainingCapacity(); |
| 165 | 168 | try tree.renderToArrayList(&rendered, fixups); |
| ... | ... | @@ -171,7 +174,8 @@ pub fn main(gpa: Allocator, arena: Allocator, args: []const []const u8) !void { |
| 171 | 174 | }); |
| 172 | 175 | switch (interestingness) { |
| 173 | 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 | 179 | tree.deinit(gpa); |
| 176 | 180 | tree = new_tree; |
| 177 | 181 | |
| ... | ... | @@ -241,6 +245,8 @@ fn runCheck(arena: std.mem.Allocator, argv: []const []const u8) !Interestingness |
| 241 | 245 | |
| 242 | 246 | fn transformationsToFixups( |
| 243 | 247 | gpa: Allocator, |
| 248 | arena: Allocator, | |
| 249 | root_source_file_path: []const u8, | |
| 244 | 250 | transforms: []const Walk.Transformation, |
| 245 | 251 | fixups: *Ast.Fixups, |
| 246 | 252 | ) !void { |
| ... | ... | @@ -254,20 +260,51 @@ fn transformationsToFixups( |
| 254 | 260 | try fixups.omit_nodes.put(gpa, decl_node, {}); |
| 255 | 261 | }, |
| 256 | 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 { | |
| 263 | const source_code = try std.fs.cwd().readFileAllocOptions( | |
| 264 | arena, | |
| 265 | root_source_file_path, | |
| 296 | fn parse(gpa: Allocator, file_path: []const u8) !Ast { | |
| 297 | const source_code = std.fs.cwd().readFileAllocOptions( | |
| 298 | gpa, | |
| 299 | file_path, | |
| 266 | 300 | std.math.maxInt(u32), |
| 267 | 301 | null, |
| 268 | 302 | 1, |
| 269 | 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 | 309 | var tree = try Ast.parse(gpa, source_code, .zig); |
| 273 | 310 | errdefer tree.deinit(gpa); |
src/reduce/Walk.zig+33-6| ... | ... | @@ -2,6 +2,7 @@ const std = @import("std"); |
| 2 | 2 | const Ast = std.zig.Ast; |
| 3 | 3 | const Walk = @This(); |
| 4 | 4 | const assert = std.debug.assert; |
| 5 | const BuiltinFn = @import("../BuiltinFn.zig"); | |
| 5 | 6 | |
| 6 | 7 | ast: *const Ast, |
| 7 | 8 | transformations: *std.ArrayList(Transformation), |
| ... | ... | @@ -16,6 +17,11 @@ pub const Transformation = union(enum) { |
| 16 | 17 | delete_node: Ast.Node.Index, |
| 17 | 18 | /// Replace an expression with `undefined`. |
| 18 | 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 | 27 | pub const Error = error{OutOfMemory}; |
| ... | ... | @@ -437,16 +443,16 @@ fn walkExpression(w: *Walk, node: Ast.Node.Index) Error!void { |
| 437 | 443 | |
| 438 | 444 | .builtin_call_two, .builtin_call_two_comma => { |
| 439 | 445 | if (datas[node].lhs == 0) { |
| 440 | return walkBuiltinCall(w, main_tokens[node], &.{}); | |
| 446 | return walkBuiltinCall(w, node, &.{}); | |
| 441 | 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 | 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 | 453 | .builtin_call, .builtin_call_comma => { |
| 448 | 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 | 458 | .fn_proto_simple, |
| ... | ... | @@ -680,10 +686,31 @@ fn walkContainerDecl( |
| 680 | 686 | |
| 681 | 687 | fn walkBuiltinCall( |
| 682 | 688 | w: *Walk, |
| 683 | builtin_token: Ast.TokenIndex, | |
| 689 | call_node: Ast.Node.Index, | |
| 684 | 690 | params: []const Ast.Node.Index, |
| 685 | 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 | 714 | for (params) |param_node| { |
| 688 | 715 | try walkExpression(w, param_node); |
| 689 | 716 | } |