| author | |
| committer | |
| log | cb715212f7aa62ec33933138c3cd47efdf95c075 |
| tree | b49c3fddb003abb8026f027057ca8d912a297788 |
| parent | c57dfa2f06e088b67ace125f84e2d97de5396c41 |
4 files changed, 116 insertions(+), 45 deletions(-)
lib/std/zig/Ast.zig+4-2| ... | ... | @@ -139,7 +139,10 @@ pub fn deinit(tree: *Ast, gpa: Allocator) void { |
| 139 | 139 | } |
| 140 | 140 | |
| 141 | 141 | pub const Mode = enum { zig, zon }; |
| 142 | pub const ParseOptions = struct { recover: bool = true, mode: Mode = .zig, use_old_precedence: bool = false }; | |
| 142 | pub const ParseOptions = struct { | |
| 143 | recover: bool = true, | |
| 144 | mode: Mode = .zig, | |
| 145 | }; | |
| 143 | 146 | |
| 144 | 147 | /// Result should be freed with tree.deinit() when there are |
| 145 | 148 | /// no more references to any of the tokens or nodes. |
| ... | ... | @@ -182,7 +185,6 @@ pub fn parseTokens( |
| 182 | 185 | .scratch = .empty, |
| 183 | 186 | .tok_i = 0, |
| 184 | 187 | .recover = options.recover, |
| 185 | .use_old_precedence = options.use_old_precedence, | |
| 186 | 188 | }; |
| 187 | 189 | defer parser.errors.deinit(gpa); |
| 188 | 190 | defer parser.nodes.deinit(gpa); |
lib/std/zig/Ast/Render.zig+27-35| ... | ... | @@ -4,7 +4,6 @@ const mem = std.mem; |
| 4 | 4 | const Allocator = std.mem.Allocator; |
| 5 | 5 | const meta = std.meta; |
| 6 | 6 | const Ast = std.zig.Ast; |
| 7 | const Parse = @import("../../zig/Parse.zig"); | |
| 8 | 7 | const Token = std.zig.Token; |
| 9 | 8 | const primitives = std.zig.primitives; |
| 10 | 9 | const Writer = std.Io.Writer; |
| ... | ... | @@ -46,6 +45,8 @@ pub const Fixups = struct { |
| 46 | 45 | replace_nodes_with_node: std.AutoHashMapUnmanaged(Ast.Node.Index, Ast.Node.Index) = .empty, |
| 47 | 46 | /// Change all identifier names matching the key to be value instead. |
| 48 | 47 | rename_identifiers: std.array_hash_map.String([]const u8) = .empty, |
| 48 | /// Add parentheses surrounding the node. | |
| 49 | insert_parentheses: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .empty, | |
| 49 | 50 | |
| 50 | 51 | /// All `@import` builtin calls which refer to a file path will be prefixed |
| 51 | 52 | /// with this path. |
| ... | ... | @@ -59,6 +60,7 @@ pub const Fixups = struct { |
| 59 | 60 | f.append_string_after_node.count() + |
| 60 | 61 | f.replace_nodes_with_node.count() + |
| 61 | 62 | f.rename_identifiers.count() + |
| 63 | f.insert_parentheses.count() + | |
| 62 | 64 | @intFromBool(f.rebase_imported_paths != null); |
| 63 | 65 | } |
| 64 | 66 | |
| ... | ... | @@ -70,6 +72,7 @@ pub const Fixups = struct { |
| 70 | 72 | f.append_string_after_node.clearRetainingCapacity(); |
| 71 | 73 | f.replace_nodes_with_node.clearRetainingCapacity(); |
| 72 | 74 | f.rename_identifiers.clearRetainingCapacity(); |
| 75 | f.insert_parentheses.clearRetainingCapacity(); | |
| 73 | 76 | |
| 74 | 77 | f.rebase_imported_paths = null; |
| 75 | 78 | } |
| ... | ... | @@ -82,6 +85,7 @@ pub const Fixups = struct { |
| 82 | 85 | f.append_string_after_node.deinit(gpa); |
| 83 | 86 | f.replace_nodes_with_node.deinit(gpa); |
| 84 | 87 | f.rename_identifiers.deinit(gpa); |
| 88 | f.insert_parentheses.deinit(gpa); | |
| 85 | 89 | f.* = undefined; |
| 86 | 90 | } |
| 87 | 91 | }; |
| ... | ... | @@ -421,6 +425,9 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 421 | 425 | tree.tokenTag(fallback_first) == .multiline_string_literal_line; |
| 422 | 426 | const after_op_space: Space = if (seperate_line) .newline else .space; |
| 423 | 427 | |
| 428 | if (r.fixups.insert_parentheses.contains(node)) { | |
| 429 | try ais.writeByte('('); | |
| 430 | } | |
| 424 | 431 | try renderExpression(r, lhs, .space); // target |
| 425 | 432 | |
| 426 | 433 | try ais.pushIndent(.normal); |
| ... | ... | @@ -433,7 +440,13 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 433 | 440 | assert(tree.tokenTag(fallback_first - 1) == .keyword_catch); |
| 434 | 441 | try renderToken(r, main_token, after_op_space); // catch keyword |
| 435 | 442 | } |
| 436 | try renderExpression(r, rhs, space); // fallback | |
| 443 | if (r.fixups.insert_parentheses.contains(node)) { | |
| 444 | try renderExpression(r, rhs, .none); | |
| 445 | try ais.writeByte(')'); | |
| 446 | try renderOnlySpace(r, space); | |
| 447 | } else { | |
| 448 | try renderExpression(r, rhs, space); // fallback | |
| 449 | } | |
| 437 | 450 | ais.popIndent(); |
| 438 | 451 | }, |
| 439 | 452 | |
| ... | ... | @@ -540,43 +553,22 @@ fn renderExpression(r: *Render, node: Ast.Node.Index, space: Space) Error!void { |
| 540 | 553 | .@"orelse", |
| 541 | 554 | => { |
| 542 | 555 | const lhs, const rhs = tree.nodeData(node).node_and_node; |
| 543 | ||
| 544 | const lhs_tag = tree.nodeTag(lhs); | |
| 545 | const center_tag = tree.nodeTag(node); | |
| 546 | const rhs_tag = tree.nodeTag(rhs); | |
| 547 | ||
| 548 | const lhs_prec = Parse.precedenceFromNodeTag(lhs_tag); | |
| 549 | const center_prec = Parse.precedenceFromNodeTag(center_tag); | |
| 550 | const rhs_prec = Parse.precedenceFromNodeTag(rhs_tag); | |
| 551 | ||
| 552 | const left_rel = lhs_prec.cmp(center_prec); | |
| 553 | const right_rel = rhs_prec.cmp(center_prec); | |
| 554 | ||
| 555 | const paren_left = left_rel == null or left_rel == .lt or (left_rel == .eq and lhs_prec.group == center_prec.group and lhs_prec.assoc == .none); | |
| 556 | const paren_right = right_rel == null or right_rel == .lt; | |
| 557 | ||
| 558 | ||
| 559 | if (paren_left) try ais.writeByte('('); | |
| 560 | try renderExpression(r, lhs, .none); | |
| 561 | if (paren_left) try ais.writeByte(')'); | |
| 562 | // Multiline string literals will eat the space so we need to skip if we thats next. | |
| 563 | if (tree.tokenTag(tree.lastToken(lhs)) != .multiline_string_literal_line) try renderOnlySpace(r, .space); | |
| 564 | ||
| 565 | try ais.pushIndent(.binop); | |
| 556 | if (r.fixups.insert_parentheses.contains(node)) { | |
| 557 | try ais.writeByte('('); | |
| 558 | } | |
| 559 | try renderExpression(r, lhs, .space); | |
| 566 | 560 | const op_token = tree.nodeMainToken(node); |
| 561 | try ais.pushIndent(.binop); | |
| 567 | 562 | const rhs_seperate_line = !tree.tokensOnSameLine(op_token, op_token + 1) or |
| 568 | 563 | tree.tokenTag(op_token + 1) == .multiline_string_literal_line; |
| 569 | 564 | try renderToken(r, op_token, if (rhs_seperate_line) .newline else .space); |
| 570 | ||
| 571 | if (paren_right) try ais.writeByte('('); | |
| 572 | try renderExpression(r, rhs, .none); | |
| 573 | if (paren_right) try ais.writeByte(')'); | |
| 574 | ||
| 575 | const most_recent = tree.lastToken(rhs); | |
| 576 | const lexeme = tokenSliceForRender(tree, most_recent); | |
| 577 | // If our space is .none, then the above code functions as normal and putting this here will duplicate comments and such | |
| 578 | if (space != .none) try renderSpace(r, most_recent, lexeme.len, space); | |
| 579 | ||
| 565 | if (r.fixups.insert_parentheses.contains(node)) { | |
| 566 | try renderExpression(r, rhs, .none); | |
| 567 | try ais.writeByte(')'); | |
| 568 | try renderOnlySpace(r, space); | |
| 569 | } else { | |
| 570 | try renderExpression(r, rhs, space); | |
| 571 | } | |
| 580 | 572 | ais.popIndent(); |
| 581 | 573 | }, |
| 582 | 574 |
lib/std/zig/Parse.zig+4-6| ... | ... | @@ -24,7 +24,6 @@ nodes: Ast.NodeList, |
| 24 | 24 | extra_data: std.ArrayList(u32), |
| 25 | 25 | scratch: std.ArrayList(Node.Index), |
| 26 | 26 | recover: bool, |
| 27 | use_old_precedence: bool = false, | |
| 28 | 27 | |
| 29 | 28 | fn tokenTag(p: *const Parse, token_index: TokenIndex) Token.Tag { |
| 30 | 29 | return p.tokens.items(.tag)[token_index]; |
| ... | ... | @@ -1793,8 +1792,7 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 |
| 1793 | 1792 | const tok_tag = p.tokenTag(p.tok_i); |
| 1794 | 1793 | const info = operTable[@backingInt(tok_tag)]; |
| 1795 | 1794 | |
| 1796 | const prec_relation = if (!p.use_old_precedence) info.prec.cmp(min_exc_prec) else info.prec.v16_cmp(min_exc_prec); | |
| 1797 | const rel = prec_relation orelse b: { | |
| 1795 | const rel = info.prec.cmp(min_exc_prec) orelse b: { | |
| 1798 | 1796 | // This issues warnings if the relation is null, which it never is in 0.16.0 |
| 1799 | 1797 | const prev_op_tok_tag = p.tokenTag(prev_operator_token); |
| 1800 | 1798 | const prev_op_info = operTable[@backingInt(prev_op_tok_tag)]; |
| ... | ... | @@ -1831,7 +1829,8 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 |
| 1831 | 1829 | }, |
| 1832 | 1830 | }); |
| 1833 | 1831 | } |
| 1834 | break :b .gt; | |
| 1832 | // Use the old precedence rules to construct the tree to ease automatic fixups | |
| 1833 | break :b info.prec.v16_cmp(min_exc_prec); | |
| 1835 | 1834 | }; |
| 1836 | 1835 | |
| 1837 | 1836 | if (rel == .lt) { |
| ... | ... | @@ -1842,8 +1841,7 @@ fn parseExprPrecedence(p: *Parse, min_exc_prec: PrecClass, prev_token_const: u32 |
| 1842 | 1841 | //Special cased check to maintain the old more helpful error for chained comparisons. |
| 1843 | 1842 | if (info.prec.group == .comparison) { |
| 1844 | 1843 | try p.warn(.chained_comparison_operators); |
| 1845 | // In 0.16.0 the only reptition prohibited was comparisons which we checked above | |
| 1846 | } else if (!p.use_old_precedence) { | |
| 1844 | } else { | |
| 1847 | 1845 | try p.warnMsg(.{ |
| 1848 | 1846 | .tag = .illegal_chained_operators, |
| 1849 | 1847 | .is_note = false, |
src/fmt.zig+81-2| ... | ... | @@ -387,9 +387,88 @@ fn fmtPathFile( |
| 387 | 387 | break :mode .zig; |
| 388 | 388 | }; |
| 389 | 389 | |
| 390 | var tree = try std.zig.Ast.parse(gpa, source_code, .{ .mode = mode, .use_old_precedence = fmt.fix_precedence }); | |
| 390 | var tree = try std.zig.Ast.parse(gpa, source_code, .{ .mode = mode }); | |
| 391 | 391 | defer tree.deinit(gpa); |
| 392 | 392 | |
| 393 | var fixups: std.zig.Ast.Render.Fixups = .{}; | |
| 394 | defer fixups.deinit(gpa); | |
| 395 | ||
| 396 | fix: { | |
| 397 | if (!fmt.fix_precedence) break :fix; | |
| 398 | ||
| 399 | var operators_to_fix: std.AutoHashMapUnmanaged(std.zig.Ast.TokenIndex, void) = .empty; | |
| 400 | defer operators_to_fix.deinit(gpa); | |
| 401 | ||
| 402 | // Gather ambiguous operator precedence error tokens for quick lookup later | |
| 403 | for (tree.errors) |err| { | |
| 404 | switch (err.tag) { | |
| 405 | .hint_operator_precedence_left => { | |
| 406 | try operators_to_fix.putNoClobber(gpa, err.token - @as(u32, @intCast(err.extra.offset)), {}); | |
| 407 | }, | |
| 408 | .hint_operator_precedence_right => { | |
| 409 | try operators_to_fix.putNoClobber(gpa, err.token, {}); | |
| 410 | }, | |
| 411 | else => continue, | |
| 412 | } | |
| 413 | } | |
| 414 | ||
| 415 | if (operators_to_fix.count() == 0) break :fix; | |
| 416 | ||
| 417 | // Build a new error list without the ambiguous operator precedence errors/notes | |
| 418 | var fixed_errors: std.ArrayList(std.zig.Ast.Error) = try .initCapacity(gpa, tree.errors.len - (operators_to_fix.count() * 3)); | |
| 419 | for (tree.errors) |err| { | |
| 420 | switch (err.tag) { | |
| 421 | .ambiguous_operator_precedence, | |
| 422 | .illegal_chained_operators, | |
| 423 | .previous_ambiguous_operator, | |
| 424 | .hint_operator_precedence_left, | |
| 425 | .hint_operator_precedence_right, | |
| 426 | => continue, | |
| 427 | else => { | |
| 428 | fixed_errors.appendAssumeCapacity(err); | |
| 429 | }, | |
| 430 | } | |
| 431 | } | |
| 432 | gpa.free(tree.errors); | |
| 433 | tree.errors = fixed_errors.toOwnedSliceAssert(); | |
| 434 | ||
| 435 | // Find the nodes we need to add parens to and add them to the list | |
| 436 | for (tree.nodes.items(.tag), 0..) |tag, i| { | |
| 437 | switch (tag) { | |
| 438 | .merge_error_sets, | |
| 439 | .mul, | |
| 440 | .div, | |
| 441 | .mod, | |
| 442 | .mul_wrap, | |
| 443 | .mul_sat, | |
| 444 | .add, | |
| 445 | .sub, | |
| 446 | .array_cat, | |
| 447 | .add_wrap, | |
| 448 | .sub_wrap, | |
| 449 | .add_sat, | |
| 450 | .sub_sat, | |
| 451 | .shl, | |
| 452 | .shl_sat, | |
| 453 | .shr, | |
| 454 | .bit_and, | |
| 455 | .bit_xor, | |
| 456 | .bit_or, | |
| 457 | .@"orelse", | |
| 458 | .@"catch", | |
| 459 | .bool_and, | |
| 460 | .bool_or, | |
| 461 | => { | |
| 462 | const main_tok = tree.nodes.get(i).main_token; | |
| 463 | if (operators_to_fix.contains(main_tok)) { | |
| 464 | try fixups.insert_parentheses.put(gpa, @fromBackingInt(@intCast(i)), {}); | |
| 465 | } | |
| 466 | }, | |
| 467 | else => {}, | |
| 468 | } | |
| 469 | } | |
| 470 | } | |
| 471 | ||
| 393 | 472 | if (tree.errors.len != 0) { |
| 394 | 473 | try std.zig.printAstErrorsToStderr(gpa, io, tree, file_path, fmt.color); |
| 395 | 474 | fmt.any_error = true; |
| ... | ... | @@ -497,7 +576,7 @@ fn fmtPathFile( |
| 497 | 576 | fmt.out_buffer.clearRetainingCapacity(); |
| 498 | 577 | try fmt.out_buffer.ensureTotalCapacity(source_code.len); |
| 499 | 578 | |
| 500 | tree.render(gpa, &fmt.out_buffer.writer, .{}) catch |err| switch (err) { | |
| 579 | tree.render(gpa, &fmt.out_buffer.writer, fixups) catch |err| switch (err) { | |
| 501 | 580 | error.WriteFailed, error.OutOfMemory => return error.OutOfMemory, |
| 502 | 581 | }; |
| 503 | 582 | if (!mem.eql(u8, fmt.out_buffer.written(), source_code)) { |