authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-26 22:59:46-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-26 22:59:46-04:00
log118d41ef8325b4c1ca8be1fea66c2e8368b67e32
treeef2bbb8f8de4565aa3bf7155eab6f548f25de461
parent349365d9a483bc6be8c1677149ec1a31a789e4b2

zig fmt: support array literal row size hint

See #1003

3 files changed, 167 insertions(+), 8 deletions(-)

std/mem.zig+8
...@@ -177,6 +177,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {...@@ -177,6 +177,14 @@ pub fn eql(comptime T: type, a: []const T, b: []const T) bool {
177 return true;177 return true;
178}178}
179179
180/// Returns true if all elements in a slice are equal to the scalar value provided
181pub fn allEqual(comptime T: type, slice: []const T, scalar: T) bool {
182 for (slice) |item| {
183 if (item != scalar) return false;
184 }
185 return true;
186}
187
180/// Copies ::m to newly allocated memory. Caller is responsible to free it.188/// Copies ::m to newly allocated memory. Caller is responsible to free it.
181pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) ![]T {189pub fn dupe(allocator: &Allocator, comptime T: type, m: []const T) ![]T {
182 const new_buf = try allocator.alloc(T, m.len);190 const new_buf = try allocator.alloc(T, m.len);
std/zig/parser_test.zig+59
...@@ -1,3 +1,62 @@...@@ -1,3 +1,62 @@
1test "zig fmt: array literal with hint" {
2 try testTransform(
3 \\const a = []u8{
4 \\ 1, 2, //
5 \\ 3,
6 \\ 4,
7 \\ 5,
8 \\ 6,
9 \\ 7 };
10 \\const a = []u8{
11 \\ 1, 2, //
12 \\ 3,
13 \\ 4,
14 \\ 5,
15 \\ 6,
16 \\ 7, 8 };
17 \\const a = []u8{
18 \\ 1, 2, //
19 \\ 3,
20 \\ 4,
21 \\ 5,
22 \\ 6, // blah
23 \\ 7, 8 };
24 \\const a = []u8{
25 \\ 1, 2, //
26 \\ 3, //
27 \\ 4,
28 \\ 5,
29 \\ 6,
30 \\ 7 };
31 ,
32 \\const a = []u8{
33 \\ 1, 2, //
34 \\ 3, 4, //
35 \\ 5, 6, //
36 \\ 7,
37 \\};
38 \\const a = []u8{
39 \\ 1, 2, //
40 \\ 3, 4, //
41 \\ 5, 6, //
42 \\ 7, 8, //
43 \\};
44 \\const a = []u8{
45 \\ 1, 2, //
46 \\ 3, 4, //
47 \\ 5, 6, // blah
48 \\ 7, 8, //
49 \\};
50 \\const a = []u8{
51 \\ 1, 2, //
52 \\ 3, 4, //
53 \\ 5, 6, //
54 \\ 7,
55 \\};
56 \\
57 );
58}
59
1test "zig fmt: multiline string with backslash at end of line" {60test "zig fmt: multiline string with backslash at end of line" {
2 try testCanonical(61 try testCanonical(
3 \\comptime {62 \\comptime {
std/zig/render.zig+100-8
...@@ -19,7 +19,7 @@ pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) (@typeOf(...@@ -19,7 +19,7 @@ pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) (@typeOf(
19 var tok_it = tree.tokens.iterator(0);19 var tok_it = tree.tokens.iterator(0);
20 while (tok_it.next()) |token| {20 while (tok_it.next()) |token| {
21 if (token.id != Token.Id.LineComment) break;21 if (token.id != Token.Id.LineComment) break;
22 try stream.print("{}\n", tree.tokenSlicePtr(token));22 try stream.print("{}\n", mem.trimRight(u8, tree.tokenSlicePtr(token), " "));
23 if (tok_it.peek()) |next_token| {23 if (tok_it.peek()) |next_token| {
24 const loc = tree.tokenLocationPtr(token.end, next_token);24 const loc = tree.tokenLocationPtr(token.end, next_token);
25 if (loc.line >= 2) {25 if (loc.line >= 2) {
...@@ -532,12 +532,73 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -532,12 +532,73 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
532532
533 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);533 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
534534
535 // scan to find row size
536 const maybe_row_size: ?usize = blk: {
537 var count: usize = 0;
538 var it = exprs.iterator(0);
539 var prev_token = (??it.peek()).*.lastToken() + 1;
540 while (it.next()) |expr| {
541 const expr_last_token = expr.*.lastToken() + 1;
542 const next_token = tree.tokens.at(expr_last_token + 1);
543 const loc = tree.tokenLocationPtr(tree.tokens.at(prev_token).end, next_token);
544 if (loc.line != 0) break :blk null;
545 if (next_token.id == Token.Id.LineComment) {
546 const trimmed = mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ");
547 if (trimmed.len == 2) {
548 break :blk count;
549 } else {
550 break :blk null;
551 }
552 }
553 prev_token = expr_last_token;
554 count += 1;
555 }
556 break :blk null;
557 };
558
559
535 const new_indent = indent + indent_delta;560 const new_indent = indent + indent_delta;
536 try renderToken(tree, stream, lbrace, new_indent, Space.Newline);561 try renderToken(tree, stream, lbrace, new_indent, Space.Newline);
562 try stream.writeByteNTimes(' ', new_indent);
563
564 if (maybe_row_size) |row_size| {
565 var it = exprs.iterator(0);
566 var i: usize = 0;
567 while (it.next()) |expr| {
568 if (it.peek()) |next_expr| {
569 try renderExpression(allocator, stream, tree, new_indent, expr.*, Space.None);
570
571 const comma = tree.nextToken(expr.*.lastToken());
572
573 if (i != row_size) {
574 try renderToken(tree, stream, comma, new_indent, Space.IgnoreEmptyComment); // ,
575 i += 1;
576 continue;
577 }
578 i = 0;
579
580 try renderToken(tree, stream, comma, new_indent, Space.NoIndent); // ,
581
582 const next_token = tree.tokens.at(comma + 1);
583 if (next_token.id != Token.Id.LineComment) {
584 try stream.print(" //\n");
585 }
586
587 try renderExtraNewline(tree, stream, next_expr.*);
588 try stream.writeByteNTimes(' ', new_indent);
589 } else if (i == row_size) {
590 try renderTrailingCommaAndEmptyComment(allocator, stream, tree, new_indent, expr.*); // , //
591 } else {
592 try renderTrailingComma(allocator, stream, tree, new_indent, expr.*, Space.Newline); // ,
593 }
594 }
595 try stream.writeByteNTimes(' ', indent);
596 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
597 return;
598 }
537599
538 var it = exprs.iterator(0);600 var it = exprs.iterator(0);
539 while (it.next()) |expr| {601 while (it.next()) |expr| {
540 try stream.writeByteNTimes(' ', new_indent);
541602
542 if (it.peek()) |next_expr| {603 if (it.peek()) |next_expr| {
543 try renderExpression(allocator, stream, tree, new_indent, expr.*, Space.None);604 try renderExpression(allocator, stream, tree, new_indent, expr.*, Space.None);
...@@ -546,6 +607,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -546,6 +607,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
546 try renderToken(tree, stream, comma, new_indent, Space.Newline); // ,607 try renderToken(tree, stream, comma, new_indent, Space.Newline); // ,
547608
548 try renderExtraNewline(tree, stream, next_expr.*);609 try renderExtraNewline(tree, stream, next_expr.*);
610 try stream.writeByteNTimes(' ', new_indent);
549 } else {611 } else {
550 try renderTrailingComma(allocator, stream, tree, new_indent, expr.*, Space.Newline);612 try renderTrailingComma(allocator, stream, tree, new_indent, expr.*, Space.Newline);
551 }613 }
...@@ -1496,11 +1558,12 @@ const Space = enum {...@@ -1496,11 +1558,12 @@ const Space = enum {
1496 NoNewline,1558 NoNewline,
1497 NoIndent,1559 NoIndent,
1498 NoComment,1560 NoComment,
1561 IgnoreEmptyComment,
1499};1562};
15001563
1501fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent: usize, space: Space) (@typeOf(stream).Child.Error || Error)!void {1564fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent: usize, space: Space) (@typeOf(stream).Child.Error || Error)!void {
1502 var token = tree.tokens.at(token_index);1565 var token = tree.tokens.at(token_index);
1503 try stream.write(tree.tokenSlicePtr(token));1566 try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(token), " "));
15041567
1505 if (space == Space.NoComment) return;1568 if (space == Space.NoComment) return;
15061569
...@@ -1515,15 +1578,19 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent...@@ -1515,15 +1578,19 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent
1515 return stream.write("\n");1578 return stream.write("\n");
1516 }1579 }
1517 },1580 },
1518 Space.Space => return stream.writeByte(' '),1581 Space.Space, Space.IgnoreEmptyComment => return stream.writeByte(' '),
1519 Space.NoComment => unreachable,1582 Space.NoComment => unreachable,
1520 }1583 }
1521 }1584 }
15221585
1586 if (space == Space.IgnoreEmptyComment and mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ").len == 2) {
1587 return stream.writeByte(' ');
1588 }
1589
1523 var loc = tree.tokenLocationPtr(token.end, next_token);1590 var loc = tree.tokenLocationPtr(token.end, next_token);
1524 var offset: usize = 1;1591 var offset: usize = 1;
1525 if (loc.line == 0) {1592 if (loc.line == 0) {
1526 try stream.print(" {}", tree.tokenSlicePtr(next_token));1593 try stream.print(" {}", mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));
1527 offset = 2;1594 offset = 2;
1528 token = next_token;1595 token = next_token;
1529 next_token = tree.tokens.at(token_index + offset);1596 next_token = tree.tokens.at(token_index + offset);
...@@ -1546,7 +1613,7 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent...@@ -1546,7 +1613,7 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent
1546 }1613 }
1547 },1614 },
1548 Space.NoNewline => {},1615 Space.NoNewline => {},
1549 Space.NoComment => unreachable,1616 Space.NoComment, Space.IgnoreEmptyComment => unreachable,
1550 }1617 }
1551 return;1618 return;
1552 }1619 }
...@@ -1558,7 +1625,7 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent...@@ -1558,7 +1625,7 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent
1558 const newline_count = if (loc.line == 1) u8(1) else u8(2);1625 const newline_count = if (loc.line == 1) u8(1) else u8(2);
1559 try stream.writeByteNTimes('\n', newline_count);1626 try stream.writeByteNTimes('\n', newline_count);
1560 try stream.writeByteNTimes(' ', indent);1627 try stream.writeByteNTimes(' ', indent);
1561 try stream.write(tree.tokenSlicePtr(next_token));1628 try stream.write(mem.trimRight(u8, tree.tokenSlicePtr(next_token), " "));
15621629
1563 offset += 1;1630 offset += 1;
1564 token = next_token;1631 token = next_token;
...@@ -1583,7 +1650,7 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent...@@ -1583,7 +1650,7 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent
1583 try stream.writeByteNTimes(' ', next_line_indent);1650 try stream.writeByteNTimes(' ', next_line_indent);
1584 },1651 },
1585 Space.NoNewline => {},1652 Space.NoNewline => {},
1586 Space.NoComment => unreachable,1653 Space.NoComment, Space.IgnoreEmptyComment => unreachable,
1587 }1654 }
1588 return;1655 return;
1589 }1656 }
...@@ -1621,3 +1688,28 @@ fn renderTrailingComma(allocator: &mem.Allocator, stream: var, tree: &ast.Tree,...@@ -1621,3 +1688,28 @@ fn renderTrailingComma(allocator: &mem.Allocator, stream: var, tree: &ast.Tree,
1621 },1688 },
1622 }1689 }
1623}1690}
1691
1692fn renderTrailingCommaAndEmptyComment(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void
1693{
1694 const end_token = base.lastToken() + 1;
1695 switch (tree.tokens.at(end_token).id) {
1696 Token.Id.Comma => {
1697 try renderExpression(allocator, stream, tree, indent, base, Space.None);
1698 try renderToken(tree, stream, end_token, indent, Space.Space); // ,
1699
1700 const next_token = tree.tokens.at(end_token + 1);
1701 if (next_token.id != Token.Id.LineComment) {
1702 try stream.print("//\n");
1703 }
1704 },
1705 Token.Id.LineComment => {
1706 try renderExpression(allocator, stream, tree, indent, base, Space.NoComment);
1707 try stream.write(", ");
1708 try renderToken(tree, stream, end_token, indent, Space.Newline);
1709 },
1710 else => {
1711 try renderExpression(allocator, stream, tree, indent, base, Space.None);
1712 try stream.write(", //\n");
1713 },
1714 }
1715}