authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-22 23:25:12-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-22 23:25:12-07:00
log1e3a200ba604c8d19fcc1119d01c2e80f2a8beca
treeb4044c94ee618ffb72f33cbafb83e4c482a4d509
parent1253903fef07d7fd0435310f474bfe2745b41405

zig fmt: array literal with hint

This regresses the test case of `zig fmt` deleting empty line comments. Two open questions here: * What should the rules be about deleting empty line comments? It makes sense usually, but for array initization, empty line comments cause a line break, affecting the row/column alignment. Perhaps we should therefore respect all empty line comments? Or should we special case array initializations? * If we decide to special case some kinds of line comments to respect them (which is status quo!), how should that be implemented?

2 files changed, 230 insertions(+), 241 deletions(-)

lib/std/zig/parser_test.zig+208-208
......@@ -1655,112 +1655,110 @@ test "zig fmt: struct literal containing a multiline expression" {
16551655 );
16561656}
16571657
1658//test "zig fmt: array literal with hint" {
1659// try testTransform(
1660// \\const a = []u8{
1661// \\ 1, 2, //
1662// \\ 3,
1663// \\ 4,
1664// \\ 5,
1665// \\ 6,
1666// \\ 7 };
1667// \\const a = []u8{
1668// \\ 1, 2, //
1669// \\ 3,
1670// \\ 4,
1671// \\ 5,
1672// \\ 6,
1673// \\ 7, 8 };
1674// \\const a = []u8{
1675// \\ 1, 2, //
1676// \\ 3,
1677// \\ 4,
1678// \\ 5,
1679// \\ 6, // blah
1680// \\ 7, 8 };
1681// \\const a = []u8{
1682// \\ 1, 2, //
1683// \\ 3, //
1684// \\ 4,
1685// \\ 5,
1686// \\ 6,
1687// \\ 7 };
1688// \\const a = []u8{
1689// \\ 1,
1690// \\ 2,
1691// \\ 3, 4, //
1692// \\ 5, 6, //
1693// \\ 7, 8, //
1694// \\};
1695// ,
1696// \\const a = []u8{
1697// \\ 1, 2,
1698// \\ 3, 4,
1699// \\ 5, 6,
1700// \\ 7,
1701// \\};
1702// \\const a = []u8{
1703// \\ 1, 2,
1704// \\ 3, 4,
1705// \\ 5, 6,
1706// \\ 7, 8,
1707// \\};
1708// \\const a = []u8{
1709// \\ 1, 2,
1710// \\ 3, 4,
1711// \\ 5,
1712// \\ 6, // blah
1713// \\ 7,
1714// \\ 8,
1715// \\};
1716// \\const a = []u8{
1717// \\ 1, 2,
1718// \\ 3, //
1719// \\ 4,
1720// \\ 5, 6,
1721// \\ 7,
1722// \\};
1723// \\const a = []u8{
1724// \\ 1,
1725// \\ 2,
1726// \\ 3,
1727// \\ 4,
1728// \\ 5,
1729// \\ 6,
1730// \\ 7,
1731// \\ 8,
1732// \\};
1733// \\
1734// );
1735//}
1736//
1737//test "zig fmt: array literal veritical column alignment" {
1738// try testTransform(
1739// \\const a = []u8{
1740// \\ 1000, 200,
1741// \\ 30, 4,
1742// \\ 50000, 60
1743// \\};
1744// \\const a = []u8{0, 1, 2, 3, 40,
1745// \\ 4,5,600,7,
1746// \\ 80,
1747// \\ 9, 10, 11, 0, 13, 14, 15};
1748// \\
1749// ,
1750// \\const a = []u8{
1751// \\ 1000, 200,
1752// \\ 30, 4,
1753// \\ 50000, 60,
1754// \\};
1755// \\const a = []u8{
1756// \\ 0, 1, 2, 3, 40,
1757// \\ 4, 5, 600, 7, 80,
1758// \\ 9, 10, 11, 0, 13,
1759// \\ 14, 15,
1760// \\};
1761// \\
1762// );
1763//}
1658test "zig fmt: array literal with hint" {
1659 try testTransform(
1660 \\const a = []u8{
1661 \\ 1, 2, //
1662 \\ 3,
1663 \\ 4,
1664 \\ 5,
1665 \\ 6,
1666 \\ 7 };
1667 \\const a = []u8{
1668 \\ 1, 2, //
1669 \\ 3,
1670 \\ 4,
1671 \\ 5,
1672 \\ 6,
1673 \\ 7, 8 };
1674 \\const a = []u8{
1675 \\ 1, 2, //
1676 \\ 3,
1677 \\ 4,
1678 \\ 5,
1679 \\ 6, // blah
1680 \\ 7, 8 };
1681 \\const a = []u8{
1682 \\ 1, 2, //
1683 \\ 3, //
1684 \\ 4,
1685 \\ 5,
1686 \\ 6,
1687 \\ 7 };
1688 \\const a = []u8{
1689 \\ 1,
1690 \\ 2,
1691 \\ 3, 4, //
1692 \\ 5, 6, //
1693 \\ 7, 8, //
1694 \\};
1695 ,
1696 \\const a = []u8{
1697 \\ 1, 2, //
1698 \\ 3, 4,
1699 \\ 5, 6,
1700 \\ 7,
1701 \\};
1702 \\const a = []u8{
1703 \\ 1, 2, //
1704 \\ 3, 4,
1705 \\ 5, 6,
1706 \\ 7, 8,
1707 \\};
1708 \\const a = []u8{
1709 \\ 1, 2, //
1710 \\ 3, 4,
1711 \\ 5,
1712 \\ 6, // blah
1713 \\ 7,
1714 \\ 8,
1715 \\};
1716 \\const a = []u8{
1717 \\ 1, 2, //
1718 \\ 3, //
1719 \\ 4,
1720 \\ 5,
1721 \\ 6,
1722 \\ 7,
1723 \\};
1724 \\const a = []u8{
1725 \\ 1,
1726 \\ 2,
1727 \\ 3, 4, //
1728 \\ 5, 6, //
1729 \\ 7, 8, //
1730 \\};
1731 \\
1732 );
1733}
1734
1735test "zig fmt: array literal veritical column alignment" {
1736 try testTransform(
1737 \\const a = []u8{
1738 \\ 1000, 200,
1739 \\ 30, 4,
1740 \\ 50000, 60
1741 \\};
1742 \\const a = []u8{0, 1, 2, 3, 40,
1743 \\ 4,5,600,7,
1744 \\ 80,
1745 \\ 9, 10, 11, 0, 13, 14, 15};
1746 \\
1747 ,
1748 \\const a = []u8{
1749 \\ 1000, 200,
1750 \\ 30, 4,
1751 \\ 50000, 60,
1752 \\};
1753 \\const a = []u8{
1754 \\ 0, 1, 2, 3, 40,
1755 \\ 4, 5, 600, 7, 80,
1756 \\ 9, 10, 11, 0, 13,
1757 \\ 14, 15,
1758 \\};
1759 \\
1760 );
1761}
17641762
17651763test "zig fmt: multiline string with backslash at end of line" {
17661764 try testCanonical(
......@@ -1949,29 +1947,29 @@ test "zig fmt: slice align" {
19491947 );
19501948}
19511949
1952//test "zig fmt: add trailing comma to array literal" {
1953// try testTransform(
1954// \\comptime {
1955// \\ return []u16{'m', 's', 'y', 's', '-' // hi
1956// \\ };
1957// \\ return []u16{'m', 's', 'y', 's',
1958// \\ '-'};
1959// \\ return []u16{'m', 's', 'y', 's', '-'};
1960// \\}
1961// ,
1962// \\comptime {
1963// \\ return []u16{
1964// \\ 'm', 's', 'y', 's', '-', // hi
1965// \\ };
1966// \\ return []u16{
1967// \\ 'm', 's', 'y', 's',
1968// \\ '-',
1969// \\ };
1970// \\ return []u16{ 'm', 's', 'y', 's', '-' };
1971// \\}
1972// \\
1973// );
1974//}
1950test "zig fmt: add trailing comma to array literal" {
1951 try testTransform(
1952 \\comptime {
1953 \\ return []u16{'m', 's', 'y', 's', '-' // hi
1954 \\ };
1955 \\ return []u16{'m', 's', 'y', 's',
1956 \\ '-'};
1957 \\ return []u16{'m', 's', 'y', 's', '-'};
1958 \\}
1959 ,
1960 \\comptime {
1961 \\ return []u16{
1962 \\ 'm', 's', 'y', 's', '-', // hi
1963 \\ };
1964 \\ return []u16{
1965 \\ 'm', 's', 'y', 's',
1966 \\ '-',
1967 \\ };
1968 \\ return []u16{ 'm', 's', 'y', 's', '-' };
1969 \\}
1970 \\
1971 );
1972}
19751973
19761974test "zig fmt: first thing in file is line comment" {
19771975 try testCanonical(
......@@ -3406,30 +3404,30 @@ test "zig fmt: comptime block in container" {
34063404// );
34073405//}
34083406
3409//test "zig fmt: multiline string in array" {
3410// try testCanonical(
3411// \\const Foo = [][]const u8{
3412// \\ \\aaa
3413// \\ ,
3414// \\ \\bbb
3415// \\};
3416// \\
3417// \\fn bar() void {
3418// \\ const Foo = [][]const u8{
3419// \\ \\aaa
3420// \\ ,
3421// \\ \\bbb
3422// \\ };
3423// \\ const Bar = [][]const u8{ // comment here
3424// \\ \\aaa
3425// \\ \\
3426// \\ , // and another comment can go here
3427// \\ \\bbb
3428// \\ };
3429// \\}
3430// \\
3431// );
3432//}
3407test "zig fmt: multiline string in array" {
3408 try testCanonical(
3409 \\const Foo = [][]const u8{
3410 \\ \\aaa
3411 \\ ,
3412 \\ \\bbb
3413 \\};
3414 \\
3415 \\fn bar() void {
3416 \\ const Foo = [][]const u8{
3417 \\ \\aaa
3418 \\ ,
3419 \\ \\bbb
3420 \\ };
3421 \\ const Bar = [][]const u8{ // comment here
3422 \\ \\aaa
3423 \\ \\
3424 \\ , // and another comment can go here
3425 \\ \\bbb
3426 \\ };
3427 \\}
3428 \\
3429 );
3430}
34333431
34343432test "zig fmt: if type expr" {
34353433 try testCanonical(
......@@ -3449,19 +3447,21 @@ test "zig fmt: file ends with struct field" {
34493447 );
34503448}
34513449
3452test "zig fmt: comment after empty comment" {
3453 try testTransform(
3454 \\const x = true; //
3455 \\//
3456 \\//
3457 \\//a
3458 \\
3459 ,
3460 \\const x = true;
3461 \\//a
3462 \\
3463 );
3464}
3450// TODO intentionally change the behavior of this case?
3451// for array literals we necessarily have meaningful empty comments
3452//test "zig fmt: comment after empty comment" {
3453// try testTransform(
3454// \\const x = true; //
3455// \\//
3456// \\//
3457// \\//a
3458// \\
3459// ,
3460// \\const x = true;
3461// \\//a
3462// \\
3463// );
3464//}
34653465
34663466//test "zig fmt: line comment in array" {
34673467// try testTransform(
......@@ -3493,7 +3493,7 @@ test "zig fmt: comment after empty comment" {
34933493// \\
34943494// );
34953495//}
3496//
3496
34973497//test "zig fmt: comment after params" {
34983498// try testTransform(
34993499// \\fn a(
......@@ -3518,7 +3518,7 @@ test "zig fmt: comment after empty comment" {
35183518// \\
35193519// );
35203520//}
3521//
3521
35223522//test "zig fmt: comment in array initializer/access" {
35233523// try testCanonical(
35243524// \\test "a" {
......@@ -3550,7 +3550,7 @@ test "zig fmt: comment after empty comment" {
35503550// \\
35513551// );
35523552//}
3553//
3553
35543554//test "zig fmt: comments at several places in struct init" {
35553555// try testTransform(
35563556// \\var bar = Bar{
......@@ -3899,44 +3899,44 @@ test "zig fmt: regression test for #5722" {
38993899 );
39003900}
39013901
3902//test "zig fmt: allow trailing line comments to do manual array formatting" {
3903// try testCanonical(
3904// \\fn foo() void {
3905// \\ self.code.appendSliceAssumeCapacity(&[_]u8{
3906// \\ 0x55, // push rbp
3907// \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
3908// \\ 0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
3909// \\ });
3910// \\
3911// \\ di_buf.appendAssumeCapacity(&[_]u8{
3912// \\ 1, DW.TAG_compile_unit, DW.CHILDREN_no, // header
3913// \\ DW.AT_stmt_list, DW_FORM_data4, // form value pairs
3914// \\ DW.AT_low_pc, DW_FORM_addr,
3915// \\ DW.AT_high_pc, DW_FORM_addr,
3916// \\ DW.AT_name, DW_FORM_strp,
3917// \\ DW.AT_comp_dir, DW_FORM_strp,
3918// \\ DW.AT_producer, DW_FORM_strp,
3919// \\ DW.AT_language, DW_FORM_data2,
3920// \\ 0, 0, // sentinel
3921// \\ });
3922// \\
3923// \\ self.code.appendSliceAssumeCapacity(&[_]u8{
3924// \\ 0x55, // push rbp
3925// \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
3926// \\ // How do we handle this?
3927// \\ //0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
3928// \\ // Here's a blank line, should that be allowed?
3929// \\
3930// \\ 0x48, 0x89, 0xe5,
3931// \\ 0x33, 0x45,
3932// \\ // Now the comment breaks a single line -- how do we handle this?
3933// \\ 0x88,
3934// \\ });
3935// \\}
3936// \\
3937// );
3938//}
3939//
3902test "zig fmt: allow trailing line comments to do manual array formatting" {
3903 try testCanonical(
3904 \\fn foo() void {
3905 \\ self.code.appendSliceAssumeCapacity(&[_]u8{
3906 \\ 0x55, // push rbp
3907 \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
3908 \\ 0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
3909 \\ });
3910 \\
3911 \\ di_buf.appendAssumeCapacity(&[_]u8{
3912 \\ 1, DW.TAG_compile_unit, DW.CHILDREN_no, // header
3913 \\ DW.AT_stmt_list, DW_FORM_data4, // form value pairs
3914 \\ DW.AT_low_pc, DW_FORM_addr,
3915 \\ DW.AT_high_pc, DW_FORM_addr,
3916 \\ DW.AT_name, DW_FORM_strp,
3917 \\ DW.AT_comp_dir, DW_FORM_strp,
3918 \\ DW.AT_producer, DW_FORM_strp,
3919 \\ DW.AT_language, DW_FORM_data2,
3920 \\ 0, 0, // sentinel
3921 \\ });
3922 \\
3923 \\ self.code.appendSliceAssumeCapacity(&[_]u8{
3924 \\ 0x55, // push rbp
3925 \\ 0x48, 0x89, 0xe5, // mov rbp, rsp
3926 \\ // How do we handle this?
3927 \\ //0x48, 0x81, 0xec, // sub rsp, imm32 (with reloc)
3928 \\ // Here's a blank line, should that be allowed?
3929 \\
3930 \\ 0x48, 0x89, 0xe5,
3931 \\ 0x33, 0x45,
3932 \\ // Now the comment breaks a single line -- how do we handle this?
3933 \\ 0x88,
3934 \\ });
3935 \\}
3936 \\
3937 );
3938}
3939
39403940//test "zig fmt: multiline string literals should play nice with array initializers" {
39413941// try testCanonical(
39423942// \\fn main() void {
......@@ -3999,7 +3999,7 @@ test "zig fmt: regression test for #5722" {
39993999// \\
40004000// );
40014001//}
4002//
4002
40034003//test "zig fmt: use of comments and Multiline string literals may force the parameters over multiple lines" {
40044004// try testCanonical(
40054005// \\pub fn makeMemUndefined(qzz: []u8) i1 {
lib/std/zig/render.zig+22-33
......@@ -1640,7 +1640,11 @@ fn renderArrayInit(
16401640 const last_elem = array_init.ast.elements[array_init.ast.elements.len - 1];
16411641 const last_elem_token = tree.lastToken(last_elem);
16421642 const trailing_comma = token_tags[last_elem_token + 1] == .comma;
1643 if (!trailing_comma) {
1643 const rbrace = if (trailing_comma) last_elem_token + 2 else last_elem_token + 1;
1644 assert(token_tags[rbrace] == .r_brace);
1645 const contains_newlines = !tree.tokensOnSameLine(array_init.ast.lbrace, rbrace);
1646
1647 if (!trailing_comma and !contains_newlines) {
16441648 // Render all on one line, no trailing comma.
16451649 if (array_init.ast.elements.len == 1) {
16461650 // If there is only one element, we don't use spaces
......@@ -1658,8 +1662,6 @@ fn renderArrayInit(
16581662 ais.pushIndentNextLine();
16591663 try renderToken(ais, tree, array_init.ast.lbrace, .newline);
16601664
1661 const rbrace = last_elem_token + 2;
1662 assert(token_tags[rbrace] == .r_brace);
16631665
16641666 var expr_index: usize = 0;
16651667 while (rowSize(tree, array_init.ast.elements[expr_index..], rbrace)) |row_size| {
......@@ -1673,28 +1675,31 @@ fn renderArrayInit(
16731675 defer gpa.free(expr_newlines);
16741676 mem.set(bool, expr_newlines, false);
16751677
1676 const expr_widths = widths[0 .. widths.len - row_size];
1677 const column_widths = widths[widths.len - row_size ..];
1678 const expr_widths = widths[0..row_exprs.len];
1679 const column_widths = widths[row_exprs.len..];
16781680
1679 // Find next row with trailing comment (if any) to end the current section
1681 // Find next row with trailing comment (if any) to end the current section.
16801682 const section_end = sec_end: {
16811683 var this_line_first_expr: usize = 0;
16821684 var this_line_size = rowSize(tree, row_exprs, rbrace);
16831685 for (row_exprs) |expr, i| {
1684 // Ignore comment on first line of this section
1685 if (i == 0 or tree.tokensOnSameLine(tree.firstToken(row_exprs[0]), tree.lastToken(expr))) continue;
1686 // Track start of line containing comment
1687 if (!tree.tokensOnSameLine(tree.firstToken(row_exprs[this_line_first_expr]), tree.lastToken(expr))) {
1686 // Ignore comment on first line of this section.
1687 if (i == 0) continue;
1688 const expr_last_token = tree.lastToken(expr);
1689 if (tree.tokensOnSameLine(tree.firstToken(row_exprs[0]), expr_last_token))
1690 continue;
1691 // Track start of line containing comment.
1692 if (!tree.tokensOnSameLine(tree.firstToken(row_exprs[this_line_first_expr]), expr_last_token)) {
16881693 this_line_first_expr = i;
16891694 this_line_size = rowSize(tree, row_exprs[this_line_first_expr..], rbrace);
16901695 }
16911696
1692 const maybe_comma = tree.lastToken(expr) + 1;
1697 const maybe_comma = expr_last_token + 1;
16931698 if (token_tags[maybe_comma] == .comma) {
16941699 const after_comma_src = tree.source[token_starts[maybe_comma]..token_starts[maybe_comma + 1]];
1695 const same_line_comment = for (after_comma_src) |byte| switch (byte) {
1700 for (after_comma_src) |byte| switch (byte) {
16961701 '\n' => break,
1697 '/' => break :sec_end i - this_line_size.? + 1, // Found row ending in comment
1702 '/' => break :sec_end i - this_line_size.? + 1,
16981703 else => continue,
16991704 };
17001705 }
......@@ -1754,7 +1759,7 @@ fn renderArrayInit(
17541759 }
17551760 }
17561761
1757 // Render exprs in current section
1762 // Render exprs in current section.
17581763 column_counter = 0;
17591764 var last_col_index: usize = row_size - 1;
17601765 for (section_exprs) |expr, i| {
......@@ -1785,19 +1790,12 @@ fn renderArrayInit(
17851790 try renderToken(ais, tree, comma, .newline); // ,
17861791 try renderExtraNewline(ais, tree, next_expr);
17871792 } else {
1788 const maybe_comma = tree.lastToken(expr) + 1;
1789 if (token_tags[maybe_comma] == .comma) {
1790 try renderExpression(gpa, ais, tree, expr, .none); // ,
1791 try renderToken(ais, tree, maybe_comma, .newline); // ,
1792 } else {
1793 try renderExpression(gpa, ais, tree, expr, .comma); // ,
1794 }
1793 try renderExpression(gpa, ais, tree, expr, .comma); // ,
17951794 }
17961795 }
17971796
1798 if (expr_index == array_init.ast.elements.len) {
1797 if (expr_index == array_init.ast.elements.len)
17991798 break;
1800 }
18011799 }
18021800
18031801 ais.popIndent();
......@@ -2175,7 +2173,6 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp
21752173/// that end is the last byte before the next token.
21762174fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize) Error!bool {
21772175 var index: usize = start;
2178 var rendered_empty_comments = false;
21792176 while (mem.indexOf(u8, tree.source[index..end], "//")) |offset| {
21802177 const comment_start = index + offset;
21812178
......@@ -2196,11 +2193,6 @@ fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize) Error!boo
21962193 // Respect the newline directly before the comment.
21972194 // Note: This allows an empty line between comments
21982195 try ais.insertNewline();
2199 } else if (trimmed_comment.len == 2) {
2200 if (!rendered_empty_comments) {
2201 try ais.writer().writeByte('\n');
2202 rendered_empty_comments = true;
2203 }
22042196 } else if (index == start) {
22052197 // Otherwise if the first comment is on the same line as
22062198 // the token before it, prefix it with a single space.
......@@ -2208,10 +2200,7 @@ fn renderComments(ais: *Ais, tree: ast.Tree, start: usize, end: usize) Error!boo
22082200 }
22092201 }
22102202
2211 if (trimmed_comment.len != 2) {
2212 try ais.writer().print("{s}\n", .{trimmed_comment});
2213 rendered_empty_comments = false;
2214 }
2203 try ais.writer().print("{s}\n", .{trimmed_comment});
22152204 index = 1 + (newline orelse return true);
22162205
22172206 if (ais.disabled_offset) |disabled_offset| {