| ... | @@ -611,6 +611,298 @@ fn renderExpression( | ... | @@ -611,6 +611,298 @@ fn renderExpression( |
| 611 | return renderExpression(allocator, stream, tree, indent, start_col, prefix_op_node.rhs, space); | 611 | return renderExpression(allocator, stream, tree, indent, start_col, prefix_op_node.rhs, space); |
| 612 | }, | 612 | }, |
| 613 | | 613 | |
| | 614 | .ArrayInitializer, .ArrayInitializerDot => { |
| | 615 | var rtoken: ast.TokenIndex = undefined; |
| | 616 | var exprs: []*ast.Node = undefined; |
| | 617 | const lhs: union(enum) {dot: ast.TokenIndex, node: *ast.Node } = switch (base.id){ |
| | 618 | .ArrayInitializerDot => blk: { |
| | 619 | const casted = @fieldParentPtr(ast.Node.ArrayInitializerDot, "base", base); |
| | 620 | rtoken = casted.rtoken; |
| | 621 | exprs = casted.list; |
| | 622 | break :blk .{ .dot = casted.dot }; |
| | 623 | }, |
| | 624 | .ArrayInitializer => blk: { |
| | 625 | const casted = @fieldParentPtr(ast.Node.ArrayInitializer, "base", base); |
| | 626 | rtoken = casted.rtoken; |
| | 627 | exprs = casted.list; |
| | 628 | break :blk .{ .node = casted.lhs }; |
| | 629 | }, |
| | 630 | else => unreachable, |
| | 631 | }; |
| | 632 | |
| | 633 | const lbrace = switch (lhs) { |
| | 634 | .dot => |dot| tree.nextToken(dot), |
| | 635 | .node => |node| tree.nextToken(node.lastToken()), |
| | 636 | }; |
| | 637 | |
| | 638 | if (exprs.len == 0) { |
| | 639 | switch (lhs) { |
| | 640 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), |
| | 641 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), |
| | 642 | } |
| | 643 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); |
| | 644 | return renderToken(tree, stream, rtoken, indent, start_col, space); |
| | 645 | } |
| | 646 | |
| | 647 | if (exprs.len == 1 and tree.tokens[exprs[0].lastToken() + 1].id == .RBrace) { |
| | 648 | const expr = exprs[0]; |
| | 649 | switch (lhs) { |
| | 650 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), |
| | 651 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), |
| | 652 | } |
| | 653 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); |
| | 654 | try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None); |
| | 655 | return renderToken(tree, stream, rtoken, indent, start_col, space); |
| | 656 | } |
| | 657 | |
| | 658 | switch (lhs) { |
| | 659 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), |
| | 660 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), |
| | 661 | } |
| | 662 | |
| | 663 | // scan to find row size |
| | 664 | const maybe_row_size: ?usize = blk: { |
| | 665 | var count: usize = 1; |
| | 666 | for (exprs) |expr, i| { |
| | 667 | if (i + 1 < exprs.len) { |
| | 668 | const expr_last_token = expr.lastToken() + 1; |
| | 669 | const loc = tree.tokenLocation(tree.tokens[expr_last_token].end, exprs[i+1].firstToken()); |
| | 670 | if (loc.line != 0) break :blk count; |
| | 671 | count += 1; |
| | 672 | } else { |
| | 673 | const expr_last_token = expr.lastToken(); |
| | 674 | const loc = tree.tokenLocation(tree.tokens[expr_last_token].end, rtoken); |
| | 675 | if (loc.line == 0) { |
| | 676 | // all on one line |
| | 677 | const src_has_trailing_comma = trailblk: { |
| | 678 | const maybe_comma = tree.prevToken(rtoken); |
| | 679 | break :trailblk tree.tokens[maybe_comma].id == .Comma; |
| | 680 | }; |
| | 681 | if (src_has_trailing_comma) { |
| | 682 | break :blk 1; // force row size 1 |
| | 683 | } else { |
| | 684 | break :blk null; // no newlines |
| | 685 | } |
| | 686 | } |
| | 687 | break :blk count; |
| | 688 | } |
| | 689 | } |
| | 690 | unreachable; |
| | 691 | }; |
| | 692 | |
| | 693 | if (maybe_row_size) |row_size| { |
| | 694 | // A place to store the width of each expression and its column's maximum |
| | 695 | var widths = try allocator.alloc(usize, exprs.len + row_size); |
| | 696 | defer allocator.free(widths); |
| | 697 | mem.set(usize, widths, 0); |
| | 698 | |
| | 699 | var expr_widths = widths[0 .. widths.len - row_size]; |
| | 700 | var column_widths = widths[widths.len - row_size ..]; |
| | 701 | |
| | 702 | // Null stream for counting the printed length of each expression |
| | 703 | var counting_stream = std.io.countingOutStream(std.io.null_out_stream); |
| | 704 | |
| | 705 | for (exprs) |expr, i| { |
| | 706 | counting_stream.bytes_written = 0; |
| | 707 | var dummy_col: usize = 0; |
| | 708 | try renderExpression(allocator, counting_stream.outStream(), tree, indent, &dummy_col, expr, Space.None); |
| | 709 | const width = @intCast(usize, counting_stream.bytes_written); |
| | 710 | const col = i % row_size; |
| | 711 | column_widths[col] = std.math.max(column_widths[col], width); |
| | 712 | expr_widths[i] = width; |
| | 713 | } |
| | 714 | |
| | 715 | var new_indent = indent + indent_delta; |
| | 716 | |
| | 717 | if (tree.tokens[tree.nextToken(lbrace)].id != .MultilineStringLiteralLine) { |
| | 718 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); |
| | 719 | try stream.writeByteNTimes(' ', new_indent); |
| | 720 | } else { |
| | 721 | new_indent -= indent_delta; |
| | 722 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.None); |
| | 723 | } |
| | 724 | |
| | 725 | var col: usize = 1; |
| | 726 | for (exprs) |expr, i| { |
| | 727 | if (i + 1 < exprs.len) { |
| | 728 | const next_expr = exprs[i + 1]; |
| | 729 | try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.None); |
| | 730 | |
| | 731 | const comma = tree.nextToken(expr.lastToken()); |
| | 732 | |
| | 733 | if (col != row_size) { |
| | 734 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Space); // , |
| | 735 | |
| | 736 | const padding = column_widths[i % row_size] - expr_widths[i]; |
| | 737 | try stream.writeByteNTimes(' ', padding); |
| | 738 | |
| | 739 | col += 1; |
| | 740 | continue; |
| | 741 | } |
| | 742 | col = 1; |
| | 743 | |
| | 744 | if (tree.tokens[tree.nextToken(comma)].id != .MultilineStringLiteralLine) { |
| | 745 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // , |
| | 746 | } else { |
| | 747 | try renderToken(tree, stream, comma, new_indent, start_col, Space.None); // , |
| | 748 | } |
| | 749 | |
| | 750 | try renderExtraNewline(tree, stream, start_col, next_expr); |
| | 751 | if (next_expr.id != .MultilineStringLiteral) { |
| | 752 | try stream.writeByteNTimes(' ', new_indent); |
| | 753 | } |
| | 754 | } else { |
| | 755 | try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.Comma); // , |
| | 756 | } |
| | 757 | } |
| | 758 | if (exprs[exprs.len - 1].id != .MultilineStringLiteral) { |
| | 759 | try stream.writeByteNTimes(' ', indent); |
| | 760 | } |
| | 761 | return renderToken(tree, stream, rtoken, indent, start_col, space); |
| | 762 | } else { |
| | 763 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); |
| | 764 | for (exprs) |expr, i| { |
| | 765 | if (i + 1 < exprs.len) { |
| | 766 | try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None); |
| | 767 | const comma = tree.nextToken(expr.lastToken()); |
| | 768 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); // , |
| | 769 | } else { |
| | 770 | try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.Space); |
| | 771 | } |
| | 772 | } |
| | 773 | |
| | 774 | return renderToken(tree, stream, rtoken, indent, start_col, space); |
| | 775 | } |
| | 776 | }, |
| | 777 | |
| | 778 | .StructInitializer, .StructInitializerDot => { |
| | 779 | var rtoken: ast.TokenIndex = undefined; |
| | 780 | var field_inits: []*ast.Node = undefined; |
| | 781 | const lhs: union(enum) {dot: ast.TokenIndex, node: *ast.Node } = switch (base.id){ |
| | 782 | .StructInitializerDot => blk: { |
| | 783 | const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base); |
| | 784 | rtoken = casted.rtoken; |
| | 785 | field_inits = casted.list; |
| | 786 | break :blk .{ .dot = casted.dot }; |
| | 787 | }, |
| | 788 | .StructInitializer => blk: { |
| | 789 | const casted = @fieldParentPtr(ast.Node.StructInitializer, "base", base); |
| | 790 | rtoken = casted.rtoken; |
| | 791 | field_inits = casted.list; |
| | 792 | break :blk .{ .node = casted.lhs }; |
| | 793 | }, |
| | 794 | else => unreachable, |
| | 795 | }; |
| | 796 | |
| | 797 | const lbrace = switch (lhs) { |
| | 798 | .dot => |dot| tree.nextToken(dot), |
| | 799 | .node => |node| tree.nextToken(node.lastToken()), |
| | 800 | }; |
| | 801 | |
| | 802 | if (field_inits.len == 0) { |
| | 803 | switch (lhs) { |
| | 804 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), |
| | 805 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), |
| | 806 | } |
| | 807 | try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None); |
| | 808 | return renderToken(tree, stream, rtoken, indent, start_col, space); |
| | 809 | } |
| | 810 | |
| | 811 | const src_has_trailing_comma = blk: { |
| | 812 | const maybe_comma = tree.prevToken(rtoken); |
| | 813 | break :blk tree.tokens[maybe_comma].id == .Comma; |
| | 814 | }; |
| | 815 | |
| | 816 | const src_same_line = blk: { |
| | 817 | const loc = tree.tokenLocation(tree.tokens[lbrace].end, rtoken); |
| | 818 | break :blk loc.line == 0; |
| | 819 | }; |
| | 820 | |
| | 821 | const expr_outputs_one_line = blk: { |
| | 822 | // render field expressions until a LF is found |
| | 823 | for (field_inits) |field_init| { |
| | 824 | var find_stream = FindByteOutStream.init('\n'); |
| | 825 | var dummy_col: usize = 0; |
| | 826 | try renderExpression(allocator, find_stream.outStream(), tree, 0, &dummy_col, field_init, Space.None); |
| | 827 | if (find_stream.byte_found) break :blk false; |
| | 828 | } |
| | 829 | break :blk true; |
| | 830 | }; |
| | 831 | |
| | 832 | if (field_inits.len == 1) blk: { |
| | 833 | const field_init = field_inits[0].cast(ast.Node.FieldInitializer).?; |
| | 834 | |
| | 835 | switch (field_init.expr.id) { |
| | 836 | .StructInitializer, |
| | 837 | .StructInitializerDot, |
| | 838 | => break :blk, |
| | 839 | |
| | 840 | else => {}, |
| | 841 | } |
| | 842 | |
| | 843 | // if the expression outputs to multiline, make this struct multiline |
| | 844 | if (!expr_outputs_one_line or src_has_trailing_comma) { |
| | 845 | break :blk; |
| | 846 | } |
| | 847 | |
| | 848 | switch (lhs) { |
| | 849 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), |
| | 850 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), |
| | 851 | } |
| | 852 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); |
| | 853 | try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space); |
| | 854 | return renderToken(tree, stream, rtoken, indent, start_col, space); |
| | 855 | } |
| | 856 | |
| | 857 | if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) { |
| | 858 | // render all on one line, no trailing comma |
| | 859 | switch (lhs) { |
| | 860 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), |
| | 861 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), |
| | 862 | } |
| | 863 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); |
| | 864 | |
| | 865 | for (field_inits) |field_init, i| { |
| | 866 | if (i + 1 < field_inits.len) { |
| | 867 | try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.None); |
| | 868 | |
| | 869 | const comma = tree.nextToken(field_init.lastToken()); |
| | 870 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); |
| | 871 | } else { |
| | 872 | try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.Space); |
| | 873 | } |
| | 874 | } |
| | 875 | |
| | 876 | return renderToken(tree, stream, rtoken, indent, start_col, space); |
| | 877 | } |
| | 878 | |
| | 879 | const new_indent = indent + indent_delta; |
| | 880 | |
| | 881 | switch (lhs) { |
| | 882 | .dot => |dot| try renderToken(tree, stream, dot, new_indent, start_col, Space.None), |
| | 883 | .node => |node| try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None), |
| | 884 | } |
| | 885 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); |
| | 886 | |
| | 887 | for (field_inits) |field_init, i| { |
| | 888 | try stream.writeByteNTimes(' ', new_indent); |
| | 889 | |
| | 890 | if (i + 1 < field_inits.len) { |
| | 891 | try renderExpression(allocator, stream, tree, new_indent, start_col, field_init, Space.None); |
| | 892 | |
| | 893 | const comma = tree.nextToken(field_init.lastToken()); |
| | 894 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); |
| | 895 | |
| | 896 | try renderExtraNewline(tree, stream, start_col, field_inits[i + 1]); |
| | 897 | } else { |
| | 898 | try renderExpression(allocator, stream, tree, new_indent, start_col, field_init, Space.Comma); |
| | 899 | } |
| | 900 | } |
| | 901 | |
| | 902 | try stream.writeByteNTimes(' ', indent); |
| | 903 | return renderToken(tree, stream, rtoken, indent, start_col, space); |
| | 904 | }, |
| | 905 | |
| 614 | .SuffixOp => { | 906 | .SuffixOp => { |
| 615 | const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base); | 907 | const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base); |
| 616 | | 908 | |
| ... | @@ -620,9 +912,9 @@ fn renderExpression( | ... | @@ -620,9 +912,9 @@ fn renderExpression( |
| 620 | try renderToken(tree, stream, async_token, indent, start_col, Space.Space); | 912 | try renderToken(tree, stream, async_token, indent, start_col, Space.Space); |
| 621 | } | 913 | } |
| 622 | | 914 | |
| 623 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | 915 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 624 | | 916 | |
| 625 | const lparen = tree.nextToken(suffix_op.lhs.node.lastToken()); | 917 | const lparen = tree.nextToken(suffix_op.lhs.lastToken()); |
| 626 | | 918 | |
| 627 | if (call_info.params.first == null) { | 919 | if (call_info.params.first == null) { |
| 628 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); | 920 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); |
| ... | @@ -680,10 +972,10 @@ fn renderExpression( | ... | @@ -680,10 +972,10 @@ fn renderExpression( |
| 680 | }, | 972 | }, |
| 681 | | 973 | |
| 682 | .ArrayAccess => |index_expr| { | 974 | .ArrayAccess => |index_expr| { |
| 683 | const lbracket = tree.nextToken(suffix_op.lhs.node.lastToken()); | 975 | const lbracket = tree.nextToken(suffix_op.lhs.lastToken()); |
| 684 | const rbracket = tree.nextToken(index_expr.lastToken()); | 976 | const rbracket = tree.nextToken(index_expr.lastToken()); |
| 685 | | 977 | |
| 686 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | 978 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 687 | try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ | 979 | try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ |
| 688 | | 980 | |
| 689 | const starts_with_comment = tree.tokens[lbracket + 1].id == .LineComment; | 981 | const starts_with_comment = tree.tokens[lbracket + 1].id == .LineComment; |
| ... | @@ -701,18 +993,18 @@ fn renderExpression( | ... | @@ -701,18 +993,18 @@ fn renderExpression( |
| 701 | }, | 993 | }, |
| 702 | | 994 | |
| 703 | .Deref => { | 995 | .Deref => { |
| 704 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | 996 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 705 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .* | 997 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .* |
| 706 | }, | 998 | }, |
| 707 | | 999 | |
| 708 | .UnwrapOptional => { | 1000 | .UnwrapOptional => { |
| 709 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | 1001 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 710 | try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // . | 1002 | try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // . |
| 711 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ? | 1003 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ? |
| 712 | }, | 1004 | }, |
| 713 | | 1005 | |
| 714 | .Slice => |range| { | 1006 | .Slice => |range| { |
| 715 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs.node, Space.None); | 1007 | try renderExpression(allocator, stream, tree, indent, start_col, suffix_op.lhs, Space.None); |
| 716 | | 1008 | |
| 717 | const lbracket = tree.prevToken(range.start.firstToken()); | 1009 | const lbracket = tree.prevToken(range.start.firstToken()); |
| 718 | const dotdot = tree.nextToken(range.start.lastToken()); | 1010 | const dotdot = tree.nextToken(range.start.lastToken()); |
| ... | @@ -737,278 +1029,6 @@ fn renderExpression( | ... | @@ -737,278 +1029,6 @@ fn renderExpression( |
| 737 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ] | 1029 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ] |
| 738 | }, | 1030 | }, |
| 739 | | 1031 | |
| 740 | .StructInitializer => |*field_inits| { | | |
| 741 | const lbrace = switch (suffix_op.lhs) { | | |
| 742 | .dot => |dot| tree.nextToken(dot), | | |
| 743 | .node => |node| tree.nextToken(node.lastToken()), | | |
| 744 | }; | | |
| 745 | | | |
| 746 | if (field_inits.first == null) { | | |
| 747 | switch (suffix_op.lhs) { | | |
| 748 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | | |
| 749 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | | |
| 750 | } | | |
| 751 | try renderToken(tree, stream, lbrace, indent + indent_delta, start_col, Space.None); | | |
| 752 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | | |
| 753 | } | | |
| 754 | | | |
| 755 | const src_has_trailing_comma = blk: { | | |
| 756 | const maybe_comma = tree.prevToken(suffix_op.rtoken); | | |
| 757 | break :blk tree.tokens[maybe_comma].id == .Comma; | | |
| 758 | }; | | |
| 759 | | | |
| 760 | const src_same_line = blk: { | | |
| 761 | const loc = tree.tokenLocation(tree.tokens[lbrace].end, suffix_op.rtoken); | | |
| 762 | break :blk loc.line == 0; | | |
| 763 | }; | | |
| 764 | | | |
| 765 | const expr_outputs_one_line = blk: { | | |
| 766 | // render field expressions until a LF is found | | |
| 767 | var it = field_inits.first; | | |
| 768 | while (it) |field_init_node| : (it = field_init_node.next) { | | |
| 769 | const field_init = field_init_node.data; | | |
| 770 | var find_stream = FindByteOutStream.init('\n'); | | |
| 771 | var dummy_col: usize = 0; | | |
| 772 | try renderExpression(allocator, find_stream.outStream(), tree, 0, &dummy_col, field_init, Space.None); | | |
| 773 | if (find_stream.byte_found) break :blk false; | | |
| 774 | } | | |
| 775 | break :blk true; | | |
| 776 | }; | | |
| 777 | | | |
| 778 | if (field_inits.first != null and field_inits.first.?.next == null) blk: { | | |
| 779 | const field_init = field_inits.first.?.data.cast(ast.Node.FieldInitializer).?; | | |
| 780 | | | |
| 781 | if (field_init.expr.cast(ast.Node.SuffixOp)) |nested_suffix_op| { | | |
| 782 | if (nested_suffix_op.op == .StructInitializer) { | | |
| 783 | break :blk; | | |
| 784 | } | | |
| 785 | } | | |
| 786 | | | |
| 787 | // if the expression outputs to multiline, make this struct multiline | | |
| 788 | if (!expr_outputs_one_line or src_has_trailing_comma) { | | |
| 789 | break :blk; | | |
| 790 | } | | |
| 791 | | | |
| 792 | switch (suffix_op.lhs) { | | |
| 793 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | | |
| 794 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | | |
| 795 | } | | |
| 796 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); | | |
| 797 | try renderExpression(allocator, stream, tree, indent, start_col, &field_init.base, Space.Space); | | |
| 798 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | | |
| 799 | } | | |
| 800 | | | |
| 801 | if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) { | | |
| 802 | // render all on one line, no trailing comma | | |
| 803 | switch (suffix_op.lhs) { | | |
| 804 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | | |
| 805 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | | |
| 806 | } | | |
| 807 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); | | |
| 808 | | | |
| 809 | var it = field_inits.first; | | |
| 810 | while (it) |field_init_node| : (it = field_init_node.next) { | | |
| 811 | const field_init = field_init_node.data; | | |
| 812 | if (field_init_node.next != null) { | | |
| 813 | try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.None); | | |
| 814 | | | |
| 815 | const comma = tree.nextToken(field_init.lastToken()); | | |
| 816 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); | | |
| 817 | } else { | | |
| 818 | try renderExpression(allocator, stream, tree, indent, start_col, field_init, Space.Space); | | |
| 819 | } | | |
| 820 | } | | |
| 821 | | | |
| 822 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | | |
| 823 | } | | |
| 824 | | | |
| 825 | const new_indent = indent + indent_delta; | | |
| 826 | | | |
| 827 | switch (suffix_op.lhs) { | | |
| 828 | .dot => |dot| try renderToken(tree, stream, dot, new_indent, start_col, Space.None), | | |
| 829 | .node => |node| try renderExpression(allocator, stream, tree, new_indent, start_col, node, Space.None), | | |
| 830 | } | | |
| 831 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); | | |
| 832 | | | |
| 833 | var it = field_inits.first; | | |
| 834 | while (it) |field_init_node| : (it = field_init_node.next) { | | |
| 835 | const field_init = field_init_node.data; | | |
| 836 | try stream.writeByteNTimes(' ', new_indent); | | |
| 837 | | | |
| 838 | if (field_init_node.next) |next_field_init| { | | |
| 839 | try renderExpression(allocator, stream, tree, new_indent, start_col, field_init, Space.None); | | |
| 840 | | | |
| 841 | const comma = tree.nextToken(field_init.lastToken()); | | |
| 842 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); | | |
| 843 | | | |
| 844 | try renderExtraNewline(tree, stream, start_col, next_field_init.data); | | |
| 845 | } else { | | |
| 846 | try renderExpression(allocator, stream, tree, new_indent, start_col, field_init, Space.Comma); | | |
| 847 | } | | |
| 848 | } | | |
| 849 | | | |
| 850 | try stream.writeByteNTimes(' ', indent); | | |
| 851 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | | |
| 852 | }, | | |
| 853 | | | |
| 854 | .ArrayInitializer => |*exprs| { | | |
| 855 | const lbrace = switch (suffix_op.lhs) { | | |
| 856 | .dot => |dot| tree.nextToken(dot), | | |
| 857 | .node => |node| tree.nextToken(node.lastToken()), | | |
| 858 | }; | | |
| 859 | | | |
| 860 | if (exprs.first == null) { | | |
| 861 | switch (suffix_op.lhs) { | | |
| 862 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | | |
| 863 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | | |
| 864 | } | | |
| 865 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); | | |
| 866 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | | |
| 867 | } | | |
| 868 | if (exprs.first) |first_expr_node| { | | |
| 869 | const expr = first_expr_node.data; | | |
| 870 | if (first_expr_node.next == null and tree.tokens[expr.lastToken() + 1].id == .RBrace) { | | |
| 871 | switch (suffix_op.lhs) { | | |
| 872 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | | |
| 873 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | | |
| 874 | } | | |
| 875 | try renderToken(tree, stream, lbrace, indent, start_col, Space.None); | | |
| 876 | try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None); | | |
| 877 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | | |
| 878 | } | | |
| 879 | } | | |
| 880 | | | |
| 881 | switch (suffix_op.lhs) { | | |
| 882 | .dot => |dot| try renderToken(tree, stream, dot, indent, start_col, Space.None), | | |
| 883 | .node => |node| try renderExpression(allocator, stream, tree, indent, start_col, node, Space.None), | | |
| 884 | } | | |
| 885 | | | |
| 886 | // scan to find row size | | |
| 887 | const maybe_row_size: ?usize = blk: { | | |
| 888 | var count: usize = 1; | | |
| 889 | var it = exprs.first; | | |
| 890 | while (true) { | | |
| 891 | const expr_node = it.?; | | |
| 892 | it = expr_node.next; | | |
| 893 | const expr = expr_node.data; | | |
| 894 | if (expr_node.next) |next_expr| { | | |
| 895 | const expr_last_token = expr.lastToken() + 1; | | |
| 896 | const loc = tree.tokenLocation(tree.tokens[expr_last_token].end, next_expr.data.firstToken()); | | |
| 897 | if (loc.line != 0) break :blk count; | | |
| 898 | count += 1; | | |
| 899 | } else { | | |
| 900 | const expr_last_token = expr.lastToken(); | | |
| 901 | const loc = tree.tokenLocation(tree.tokens[expr_last_token].end, suffix_op.rtoken); | | |
| 902 | if (loc.line == 0) { | | |
| 903 | // all on one line | | |
| 904 | const src_has_trailing_comma = trailblk: { | | |
| 905 | const maybe_comma = tree.prevToken(suffix_op.rtoken); | | |
| 906 | break :trailblk tree.tokens[maybe_comma].id == .Comma; | | |
| 907 | }; | | |
| 908 | if (src_has_trailing_comma) { | | |
| 909 | break :blk 1; // force row size 1 | | |
| 910 | } else { | | |
| 911 | break :blk null; // no newlines | | |
| 912 | } | | |
| 913 | } | | |
| 914 | break :blk count; | | |
| 915 | } | | |
| 916 | } | | |
| 917 | }; | | |
| 918 | | | |
| 919 | if (maybe_row_size) |row_size| { | | |
| 920 | // A place to store the width of each expression and its column's maximum | | |
| 921 | var widths = try allocator.alloc(usize, exprs.len() + row_size); | | |
| 922 | defer allocator.free(widths); | | |
| 923 | mem.set(usize, widths, 0); | | |
| 924 | | | |
| 925 | var expr_widths = widths[0 .. widths.len - row_size]; | | |
| 926 | var column_widths = widths[widths.len - row_size ..]; | | |
| 927 | | | |
| 928 | // Null stream for counting the printed length of each expression | | |
| 929 | var counting_stream = std.io.countingOutStream(std.io.null_out_stream); | | |
| 930 | | | |
| 931 | var it = exprs.first; | | |
| 932 | var i: usize = 0; | | |
| 933 | | | |
| 934 | while (it) |expr_node| : ({i += 1; it = expr_node.next;}) { | | |
| 935 | const expr = expr_node.data; | | |
| 936 | counting_stream.bytes_written = 0; | | |
| 937 | var dummy_col: usize = 0; | | |
| 938 | try renderExpression(allocator, counting_stream.outStream(), tree, indent, &dummy_col, expr, Space.None); | | |
| 939 | const width = @intCast(usize, counting_stream.bytes_written); | | |
| 940 | const col = i % row_size; | | |
| 941 | column_widths[col] = std.math.max(column_widths[col], width); | | |
| 942 | expr_widths[i] = width; | | |
| 943 | } | | |
| 944 | | | |
| 945 | var new_indent = indent + indent_delta; | | |
| 946 | | | |
| 947 | if (tree.tokens[tree.nextToken(lbrace)].id != .MultilineStringLiteralLine) { | | |
| 948 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.Newline); | | |
| 949 | try stream.writeByteNTimes(' ', new_indent); | | |
| 950 | } else { | | |
| 951 | new_indent -= indent_delta; | | |
| 952 | try renderToken(tree, stream, lbrace, new_indent, start_col, Space.None); | | |
| 953 | } | | |
| 954 | | | |
| 955 | it = exprs.first; | | |
| 956 | i = 0; | | |
| 957 | var col: usize = 1; | | |
| 958 | var last_node = it.?; | | |
| 959 | while (it) |expr_node| : ({i += 1; it = expr_node.next; last_node = expr_node;}) { | | |
| 960 | const expr = expr_node.data; | | |
| 961 | if (expr_node.next) |next_expr| { | | |
| 962 | try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.None); | | |
| 963 | | | |
| 964 | const comma = tree.nextToken(expr.lastToken()); | | |
| 965 | | | |
| 966 | if (col != row_size) { | | |
| 967 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Space); // , | | |
| 968 | | | |
| 969 | const padding = column_widths[i % row_size] - expr_widths[i]; | | |
| 970 | try stream.writeByteNTimes(' ', padding); | | |
| 971 | | | |
| 972 | col += 1; | | |
| 973 | continue; | | |
| 974 | } | | |
| 975 | col = 1; | | |
| 976 | | | |
| 977 | if (tree.tokens[tree.nextToken(comma)].id != .MultilineStringLiteralLine) { | | |
| 978 | try renderToken(tree, stream, comma, new_indent, start_col, Space.Newline); // , | | |
| 979 | } else { | | |
| 980 | try renderToken(tree, stream, comma, new_indent, start_col, Space.None); // , | | |
| 981 | } | | |
| 982 | | | |
| 983 | try renderExtraNewline(tree, stream, start_col, next_expr.data); | | |
| 984 | if (next_expr.data.id != .MultilineStringLiteral) { | | |
| 985 | try stream.writeByteNTimes(' ', new_indent); | | |
| 986 | } | | |
| 987 | } else { | | |
| 988 | try renderExpression(allocator, stream, tree, new_indent, start_col, expr, Space.Comma); // , | | |
| 989 | } | | |
| 990 | } | | |
| 991 | if (last_node.data.id != .MultilineStringLiteral) { | | |
| 992 | try stream.writeByteNTimes(' ', indent); | | |
| 993 | } | | |
| 994 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | | |
| 995 | } else { | | |
| 996 | try renderToken(tree, stream, lbrace, indent, start_col, Space.Space); | | |
| 997 | var it = exprs.first; | | |
| 998 | while (it) |expr_node| : (it = expr_node.next) { | | |
| 999 | const expr = expr_node.data; | | |
| 1000 | if (expr_node.next) |next_expr| { | | |
| 1001 | try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.None); | | |
| 1002 | const comma = tree.nextToken(expr.lastToken()); | | |
| 1003 | try renderToken(tree, stream, comma, indent, start_col, Space.Space); // , | | |
| 1004 | } else { | | |
| 1005 | try renderExpression(allocator, stream, tree, indent, start_col, expr, Space.Space); | | |
| 1006 | } | | |
| 1007 | } | | |
| 1008 | | | |
| 1009 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); | | |
| 1010 | } | | |
| 1011 | }, | | |
| 1012 | } | 1032 | } |
| 1013 | }, | 1033 | }, |
| 1014 | | 1034 | |