| ... | ... | @@ -611,6 +611,298 @@ fn renderExpression( |
| 611 | 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 | 906 | .SuffixOp => { |
| 615 | 907 | const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base); |
| 616 | 908 | |
| ... | ... | @@ -620,9 +912,9 @@ fn renderExpression( |
| 620 | 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 | 919 | if (call_info.params.first == null) { |
| 628 | 920 | try renderToken(tree, stream, lparen, indent, start_col, Space.None); |
| ... | ... | @@ -680,10 +972,10 @@ fn renderExpression( |
| 680 | 972 | }, |
| 681 | 973 | |
| 682 | 974 | .ArrayAccess => |index_expr| { |
| 683 | | const lbracket = tree.nextToken(suffix_op.lhs.node.lastToken()); |
| 975 | const lbracket = tree.nextToken(suffix_op.lhs.lastToken()); |
| 684 | 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 | 979 | try renderToken(tree, stream, lbracket, indent, start_col, Space.None); // [ |
| 688 | 980 | |
| 689 | 981 | const starts_with_comment = tree.tokens[lbracket + 1].id == .LineComment; |
| ... | ... | @@ -701,18 +993,18 @@ fn renderExpression( |
| 701 | 993 | }, |
| 702 | 994 | |
| 703 | 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 | 997 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // .* |
| 706 | 998 | }, |
| 707 | 999 | |
| 708 | 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 | 1002 | try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, start_col, Space.None); // . |
| 711 | 1003 | return renderToken(tree, stream, suffix_op.rtoken, indent, start_col, space); // ? |
| 712 | 1004 | }, |
| 713 | 1005 | |
| 714 | 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 | 1009 | const lbracket = tree.prevToken(range.start.firstToken()); |
| 718 | 1010 | const dotdot = tree.nextToken(range.start.lastToken()); |
| ... | ... | @@ -737,278 +1029,6 @@ fn renderExpression( |
| 737 | 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 | |