authorgravatar for legaul@cisco.comLewis Gaul <legaul@cisco.com> 2021-02-28 23:46:35+00:00
committergravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-03-15 14:55:34+01:00
logb4db03d8bb29f0cded857300df460b4247e85670
tree57d801b9efa60deaa615c16a1c3a6db0604e46bd
parenta502c160cd51ce3de80b3be945245b7a91967a85

zig fmt: fix extra newline before if nested in for

Add failing testcase to reproduce issue 8088 Tidy up renderWhile(), factoring out renderWhilePayload() Ensure correct newline is used before 'then' token in while/for/if Handle indents for 'if' inside 'for' or 'while' Stop special-casing 'if' compared to 'for' and 'while'

2 files changed, 76 insertions(+), 75 deletions(-)

lib/std/zig/parser_test.zig+25
...@@ -3184,6 +3184,31 @@ test "zig fmt: for" {...@@ -3184,6 +3184,31 @@ test "zig fmt: for" {
3184 );3184 );
3185}3185}
31863186
3187test "zig fmt: for if" {
3188 try testCanonical(
3189 \\test "for if" {
3190 \\ for (a) |x| if (x) f(x);
3191 \\
3192 \\ for (a) |x| if (x)
3193 \\ f(x);
3194 \\
3195 \\ for (a) |x| if (x) {
3196 \\ f(x);
3197 \\ };
3198 \\
3199 \\ for (a) |x|
3200 \\ if (x)
3201 \\ f(x);
3202 \\
3203 \\ for (a) |x|
3204 \\ if (x) {
3205 \\ f(x);
3206 \\ };
3207 \\}
3208 \\
3209 );
3210}
3211
3187test "zig fmt: if" {3212test "zig fmt: if" {
3188 try testCanonical(3213 try testCanonical(
3189 \\test "if" {3214 \\test "if" {
lib/std/zig/render.zig+51-75
...@@ -1025,31 +1025,11 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full....@@ -1025,31 +1025,11 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full.
1025 const then_tag = node_tags[while_node.ast.then_expr];1025 const then_tag = node_tags[while_node.ast.then_expr];
1026 if (nodeIsBlock(then_tag) and !nodeIsIf(then_tag)) {1026 if (nodeIsBlock(then_tag) and !nodeIsIf(then_tag)) {
1027 if (while_node.payload_token) |payload_token| {1027 if (while_node.payload_token) |payload_token| {
1028 try renderToken(ais, tree, payload_token - 2, .space); // rparen
1029 try renderToken(ais, tree, payload_token - 1, .none); // |
1030 const ident = blk: {
1031 if (token_tags[payload_token] == .asterisk) {
1032 try renderToken(ais, tree, payload_token, .none); // *
1033 break :blk payload_token + 1;
1034 } else {
1035 break :blk payload_token;
1036 }
1037 };
1038 try renderToken(ais, tree, ident, .none); // identifier
1039 const pipe = blk: {
1040 if (token_tags[ident + 1] == .comma) {
1041 try renderToken(ais, tree, ident + 1, .space); // ,
1042 try renderToken(ais, tree, ident + 2, .none); // index
1043 break :blk ident + 3;
1044 } else {
1045 break :blk ident + 1;
1046 }
1047 };
1048 const brace_space = if (while_node.ast.cont_expr == 0 and ais.isLineOverIndented())1028 const brace_space = if (while_node.ast.cont_expr == 0 and ais.isLineOverIndented())
1049 Space.newline1029 Space.newline
1050 else1030 else
1051 Space.space;1031 Space.space;
1052 try renderToken(ais, tree, pipe, brace_space); // |1032 try renderWhilePayload(gpa, ais, tree, payload_token, brace_space);
1053 } else {1033 } else {
1054 const rparen = tree.lastToken(while_node.ast.cond_expr) + 1;1034 const rparen = tree.lastToken(while_node.ast.cond_expr) + 1;
1055 const brace_space = if (while_node.ast.cont_expr == 0 and ais.isLineOverIndented())1035 const brace_space = if (while_node.ast.cont_expr == 0 and ais.isLineOverIndented())
...@@ -1082,38 +1062,23 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full....@@ -1082,38 +1062,23 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full.
1082 }1062 }
10831063
1084 const rparen = tree.lastToken(while_node.ast.cond_expr) + 1;1064 const rparen = tree.lastToken(while_node.ast.cond_expr) + 1;
1065 const first_then_token = tree.firstToken(while_node.ast.then_expr);
1085 const last_then_token = tree.lastToken(while_node.ast.then_expr);1066 const last_then_token = tree.lastToken(while_node.ast.then_expr);
1086 const src_has_newline = !tree.tokensOnSameLine(rparen, last_then_token);1067 const src_has_newline = !tree.tokensOnSameLine(rparen, last_then_token);
10871068
1088 if (src_has_newline) {1069 if (src_has_newline) {
1070 const newline_before_then_token = !tree.tokensOnSameLine(rparen, first_then_token);
1071 const space_before_then_token: Space = if (newline_before_then_token) .newline else .space;
1072 const indent_expression = !nodeIsIf(then_tag) or newline_before_then_token;
1073
1089 if (while_node.payload_token) |payload_token| {1074 if (while_node.payload_token) |payload_token| {
1090 try renderToken(ais, tree, payload_token - 2, .space); // rparen1075 const after_space: Space = if (while_node.ast.cont_expr != 0) .space else space_before_then_token;
1091 try renderToken(ais, tree, payload_token - 1, .none); // |1076 try renderWhilePayload(gpa, ais, tree, payload_token, after_space);
1092 const ident = blk: {
1093 if (token_tags[payload_token] == .asterisk) {
1094 try renderToken(ais, tree, payload_token, .none); // *
1095 break :blk payload_token + 1;
1096 } else {
1097 break :blk payload_token;
1098 }
1099 };
1100 try renderToken(ais, tree, ident, .none); // identifier
1101 const pipe = blk: {
1102 if (token_tags[ident + 1] == .comma) {
1103 try renderToken(ais, tree, ident + 1, .space); // ,
1104 try renderToken(ais, tree, ident + 2, .none); // index
1105 break :blk ident + 3;
1106 } else {
1107 break :blk ident + 1;
1108 }
1109 };
1110 const after_space: Space = if (while_node.ast.cont_expr != 0) .space else .newline;
1111 try renderToken(ais, tree, pipe, after_space); // |
1112 } else {1077 } else {
1113 ais.pushIndent();1078 if (indent_expression) ais.pushIndent();
1114 const after_space: Space = if (while_node.ast.cont_expr != 0) .space else .newline;1079 const after_space: Space = if (while_node.ast.cont_expr != 0) .space else space_before_then_token;
1115 try renderToken(ais, tree, rparen, after_space); // rparen1080 try renderToken(ais, tree, rparen, after_space); // rparen
1116 ais.popIndent();1081 if (indent_expression) ais.popIndent();
1117 }1082 }
1118 if (while_node.ast.cont_expr != 0) {1083 if (while_node.ast.cont_expr != 0) {
1119 const cont_rparen = tree.lastToken(while_node.ast.cont_expr) + 1;1084 const cont_rparen = tree.lastToken(while_node.ast.cont_expr) + 1;
...@@ -1121,12 +1086,12 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full....@@ -1121,12 +1086,12 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full.
1121 try renderToken(ais, tree, cont_lparen - 1, .space); // :1086 try renderToken(ais, tree, cont_lparen - 1, .space); // :
1122 try renderToken(ais, tree, cont_lparen, .none); // lparen1087 try renderToken(ais, tree, cont_lparen, .none); // lparen
1123 try renderExpression(gpa, ais, tree, while_node.ast.cont_expr, .none);1088 try renderExpression(gpa, ais, tree, while_node.ast.cont_expr, .none);
1124 try renderToken(ais, tree, cont_rparen, .newline); // rparen1089 try renderToken(ais, tree, cont_rparen, space_before_then_token); // rparen
1125 }1090 }
1126 if (while_node.ast.else_expr != 0) {1091 if (while_node.ast.else_expr != 0) {
1127 ais.pushIndent();1092 if (indent_expression) ais.pushIndent();
1128 try renderExpression(gpa, ais, tree, while_node.ast.then_expr, Space.newline);1093 try renderExpression(gpa, ais, tree, while_node.ast.then_expr, .newline);
1129 ais.popIndent();1094 if (indent_expression) ais.popIndent();
1130 const else_is_block = nodeIsBlock(node_tags[while_node.ast.else_expr]);1095 const else_is_block = nodeIsBlock(node_tags[while_node.ast.else_expr]);
1131 if (else_is_block) {1096 if (else_is_block) {
1132 try renderToken(ais, tree, while_node.else_token, .space); // else1097 try renderToken(ais, tree, while_node.else_token, .space); // else
...@@ -1145,12 +1110,18 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full....@@ -1145,12 +1110,18 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full.
1145 } else {1110 } else {
1146 try renderToken(ais, tree, while_node.else_token, .newline); // else1111 try renderToken(ais, tree, while_node.else_token, .newline); // else
1147 }1112 }
1148 try renderExpressionIndented(gpa, ais, tree, while_node.ast.else_expr, space);1113 if (indent_expression) {
1149 return;1114 return renderExpressionIndented(gpa, ais, tree, while_node.ast.else_expr, space);
1115 } else {
1116 return renderExpression(gpa, ais, tree, while_node.ast.else_expr, space);
1117 }
1150 }1118 }
1151 } else {1119 } else {
1152 try renderExpressionIndented(gpa, ais, tree, while_node.ast.then_expr, space);1120 if (indent_expression) {
1153 return;1121 return renderExpressionIndented(gpa, ais, tree, while_node.ast.then_expr, space);
1122 } else {
1123 return renderExpression(gpa, ais, tree, while_node.ast.then_expr, space);
1124 }
1154 }1125 }
1155 }1126 }
11561127
...@@ -1158,27 +1129,7 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full....@@ -1158,27 +1129,7 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full.
11581129
1159 if (while_node.payload_token) |payload_token| {1130 if (while_node.payload_token) |payload_token| {
1160 assert(payload_token - 2 == rparen);1131 assert(payload_token - 2 == rparen);
1161 try renderToken(ais, tree, payload_token - 2, .space); // )1132 try renderWhilePayload(gpa, ais, tree, payload_token, .space);
1162 try renderToken(ais, tree, payload_token - 1, .none); // |
1163 const ident = blk: {
1164 if (token_tags[payload_token] == .asterisk) {
1165 try renderToken(ais, tree, payload_token, .none); // *
1166 break :blk payload_token + 1;
1167 } else {
1168 break :blk payload_token;
1169 }
1170 };
1171 try renderToken(ais, tree, ident, .none); // identifier
1172 const pipe = blk: {
1173 if (token_tags[ident + 1] == .comma) {
1174 try renderToken(ais, tree, ident + 1, .space); // ,
1175 try renderToken(ais, tree, ident + 2, .none); // index
1176 break :blk ident + 3;
1177 } else {
1178 break :blk ident + 1;
1179 }
1180 };
1181 try renderToken(ais, tree, pipe, .space); // |
1182 } else {1133 } else {
1183 try renderToken(ais, tree, rparen, .space); // )1134 try renderToken(ais, tree, rparen, .space); // )
1184 }1135 }
...@@ -1208,6 +1159,31 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full....@@ -1208,6 +1159,31 @@ fn renderWhile(gpa: *Allocator, ais: *Ais, tree: ast.Tree, while_node: ast.full.
1208 }1159 }
1209}1160}
12101161
1162fn renderWhilePayload(gpa: *Allocator, ais: *Ais, tree: ast.Tree, payload_token: ast.TokenIndex, space: Space) Error!void {
1163 const token_tags = tree.tokens.items(.tag);
1164 try renderToken(ais, tree, payload_token - 2, .space); // rparen
1165 try renderToken(ais, tree, payload_token - 1, .none); // |
1166 const ident = blk: {
1167 if (token_tags[payload_token] == .asterisk) {
1168 try renderToken(ais, tree, payload_token, .none); // *
1169 break :blk payload_token + 1;
1170 } else {
1171 break :blk payload_token;
1172 }
1173 };
1174 try renderToken(ais, tree, ident, .none); // identifier
1175 const pipe = blk: {
1176 if (token_tags[ident + 1] == .comma) {
1177 try renderToken(ais, tree, ident + 1, .space); // ,
1178 try renderToken(ais, tree, ident + 2, .none); // index
1179 break :blk ident + 3;
1180 } else {
1181 break :blk ident + 1;
1182 }
1183 };
1184 try renderToken(ais, tree, pipe, space); // |
1185}
1186
1211fn renderContainerField(1187fn renderContainerField(
1212 gpa: *Allocator,1188 gpa: *Allocator,
1213 ais: *Ais,1189 ais: *Ais,