| ... | @@ -206,6 +206,10 @@ fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *as | ... | @@ -206,6 +206,10 @@ fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *as |
| 206 | } | 206 | } |
| 207 | | 207 | |
| 208 | fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node) (@TypeOf(stream).Child.Error || Error)!void { | 208 | fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node) (@TypeOf(stream).Child.Error || Error)!void { |
| | 209 | try renderContainerDecl(allocator, stream, tree, indent, start_col, decl, .Newline); |
| | 210 | } |
| | 211 | |
| | 212 | fn renderContainerDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, indent: usize, start_col: *usize, decl: *ast.Node, space: Space) (@TypeOf(stream).Child.Error || Error)!void { |
| 209 | switch (decl.id) { | 213 | switch (decl.id) { |
| 210 | .FnProto => { | 214 | .FnProto => { |
| 211 | const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl); | 215 | const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl); |
| ... | @@ -213,11 +217,11 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i | ... | @@ -213,11 +217,11 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i |
| 213 | try renderDocComments(tree, stream, fn_proto, indent, start_col); | 217 | try renderDocComments(tree, stream, fn_proto, indent, start_col); |
| 214 | | 218 | |
| 215 | if (fn_proto.body_node) |body_node| { | 219 | if (fn_proto.body_node) |body_node| { |
| 216 | try renderExpression(allocator, stream, tree, indent, start_col, decl, Space.Space); | 220 | try renderExpression(allocator, stream, tree, indent, start_col, decl, .Space); |
| 217 | try renderExpression(allocator, stream, tree, indent, start_col, body_node, Space.Newline); | 221 | try renderExpression(allocator, stream, tree, indent, start_col, body_node, space); |
| 218 | } else { | 222 | } else { |
| 219 | try renderExpression(allocator, stream, tree, indent, start_col, decl, Space.None); | 223 | try renderExpression(allocator, stream, tree, indent, start_col, decl, .None); |
| 220 | try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, start_col, Space.Newline); | 224 | try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, start_col, space); |
| 221 | } | 225 | } |
| 222 | }, | 226 | }, |
| 223 | | 227 | |
| ... | @@ -225,11 +229,11 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i | ... | @@ -225,11 +229,11 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i |
| 225 | const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl); | 229 | const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl); |
| 226 | | 230 | |
| 227 | if (use_decl.visib_token) |visib_token| { | 231 | if (use_decl.visib_token) |visib_token| { |
| 228 | try renderToken(tree, stream, visib_token, indent, start_col, Space.Space); // pub | 232 | try renderToken(tree, stream, visib_token, indent, start_col, .Space); // pub |
| 229 | } | 233 | } |
| 230 | try renderToken(tree, stream, use_decl.use_token, indent, start_col, Space.Space); // usingnamespace | 234 | try renderToken(tree, stream, use_decl.use_token, indent, start_col, .Space); // usingnamespace |
| 231 | try renderExpression(allocator, stream, tree, indent, start_col, use_decl.expr, Space.None); | 235 | try renderExpression(allocator, stream, tree, indent, start_col, use_decl.expr, .None); |
| 232 | try renderToken(tree, stream, use_decl.semicolon_token, indent, start_col, Space.Newline); // ; | 236 | try renderToken(tree, stream, use_decl.semicolon_token, indent, start_col, space); // ; |
| 233 | }, | 237 | }, |
| 234 | | 238 | |
| 235 | .VarDecl => { | 239 | .VarDecl => { |
| ... | @@ -243,9 +247,9 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i | ... | @@ -243,9 +247,9 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i |
| 243 | const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl); | 247 | const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl); |
| 244 | | 248 | |
| 245 | try renderDocComments(tree, stream, test_decl, indent, start_col); | 249 | try renderDocComments(tree, stream, test_decl, indent, start_col); |
| 246 | try renderToken(tree, stream, test_decl.test_token, indent, start_col, Space.Space); | 250 | try renderToken(tree, stream, test_decl.test_token, indent, start_col, .Space); |
| 247 | try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, Space.Space); | 251 | try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, .Space); |
| 248 | try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, Space.Newline); | 252 | try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, space); |
| 249 | }, | 253 | }, |
| 250 | | 254 | |
| 251 | .ContainerField => { | 255 | .ContainerField => { |
| ... | @@ -253,62 +257,76 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i | ... | @@ -253,62 +257,76 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i |
| 253 | | 257 | |
| 254 | try renderDocComments(tree, stream, field, indent, start_col); | 258 | try renderDocComments(tree, stream, field, indent, start_col); |
| 255 | if (field.comptime_token) |t| { | 259 | if (field.comptime_token) |t| { |
| 256 | try renderToken(tree, stream, t, indent, start_col, Space.Space); // comptime | 260 | try renderToken(tree, stream, t, indent, start_col, .Space); // comptime |
| 257 | } | 261 | } |
| 258 | | 262 | |
| | 263 | const src_has_trailing_comma = blk: { |
| | 264 | const maybe_comma = tree.nextToken(field.lastToken()); |
| | 265 | break :blk tree.tokens.at(maybe_comma).id == .Comma; |
| | 266 | }; |
| | 267 | |
| | 268 | // The trailing comma is emitted at the end, but if it's not present |
| | 269 | // we still have to respect the specified `space` parameter |
| | 270 | const last_token_space: Space = if (src_has_trailing_comma) .None else space; |
| | 271 | |
| 259 | if (field.type_expr == null and field.value_expr == null) { | 272 | if (field.type_expr == null and field.value_expr == null) { |
| 260 | return renderToken(tree, stream, field.name_token, indent, start_col, Space.Comma); // name, | 273 | try renderToken(tree, stream, field.name_token, indent, start_col, last_token_space); // name |
| 261 | } else if (field.type_expr != null and field.value_expr == null) { | 274 | } else if (field.type_expr != null and field.value_expr == null) { |
| 262 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name | 275 | try renderToken(tree, stream, field.name_token, indent, start_col, .None); // name |
| 263 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // : | 276 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // : |
| 264 | | 277 | |
| 265 | if (field.align_expr) |align_value_expr| { | 278 | if (field.align_expr) |align_value_expr| { |
| 266 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Space); // type | 279 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, .Space); // type |
| 267 | const lparen_token = tree.prevToken(align_value_expr.firstToken()); | 280 | const lparen_token = tree.prevToken(align_value_expr.firstToken()); |
| 268 | const align_kw = tree.prevToken(lparen_token); | 281 | const align_kw = tree.prevToken(lparen_token); |
| 269 | const rparen_token = tree.nextToken(align_value_expr.lastToken()); | 282 | const rparen_token = tree.nextToken(align_value_expr.lastToken()); |
| 270 | try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align | 283 | try renderToken(tree, stream, align_kw, indent, start_col, .None); // align |
| 271 | try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // ( | 284 | try renderToken(tree, stream, lparen_token, indent, start_col, .None); // ( |
| 272 | try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, Space.None); // alignment | 285 | try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, .None); // alignment |
| 273 | try renderToken(tree, stream, rparen_token, indent, start_col, Space.Comma); // ), | 286 | try renderToken(tree, stream, rparen_token, indent, start_col, last_token_space); // ) |
| 274 | } else { | 287 | } else { |
| 275 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Comma); // type, | 288 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, last_token_space); // type |
| 276 | } | 289 | } |
| 277 | } else if (field.type_expr == null and field.value_expr != null) { | 290 | } else if (field.type_expr == null and field.value_expr != null) { |
| 278 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.Space); // name | 291 | try renderToken(tree, stream, field.name_token, indent, start_col, .Space); // name |
| 279 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // = | 292 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // = |
| 280 | return renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, Space.Comma); // value | 293 | try renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, last_token_space); // value |
| 281 | } else { | 294 | } else { |
| 282 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name | 295 | try renderToken(tree, stream, field.name_token, indent, start_col, .None); // name |
| 283 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // : | 296 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // : |
| 284 | | 297 | |
| 285 | if (field.align_expr) |align_value_expr| { | 298 | if (field.align_expr) |align_value_expr| { |
| 286 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Space); // type | 299 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, .Space); // type |
| 287 | const lparen_token = tree.prevToken(align_value_expr.firstToken()); | 300 | const lparen_token = tree.prevToken(align_value_expr.firstToken()); |
| 288 | const align_kw = tree.prevToken(lparen_token); | 301 | const align_kw = tree.prevToken(lparen_token); |
| 289 | const rparen_token = tree.nextToken(align_value_expr.lastToken()); | 302 | const rparen_token = tree.nextToken(align_value_expr.lastToken()); |
| 290 | try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align | 303 | try renderToken(tree, stream, align_kw, indent, start_col, .None); // align |
| 291 | try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // ( | 304 | try renderToken(tree, stream, lparen_token, indent, start_col, .None); // ( |
| 292 | try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, Space.None); // alignment | 305 | try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, .None); // alignment |
| 293 | try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // ) | 306 | try renderToken(tree, stream, rparen_token, indent, start_col, .Space); // ) |
| 294 | } else { | 307 | } else { |
| 295 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Space); // type | 308 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, .Space); // type |
| 296 | } | 309 | } |
| 297 | try renderToken(tree, stream, tree.prevToken(field.value_expr.?.firstToken()), indent, start_col, Space.Space); // = | 310 | try renderToken(tree, stream, tree.prevToken(field.value_expr.?.firstToken()), indent, start_col, .Space); // = |
| 298 | return renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, Space.Comma); // value, | 311 | try renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, last_token_space); // value |
| | 312 | } |
| | 313 | |
| | 314 | if (src_has_trailing_comma) { |
| | 315 | const comma = tree.nextToken(field.lastToken()); |
| | 316 | try renderToken(tree, stream, comma, indent, start_col, space); |
| 299 | } | 317 | } |
| 300 | }, | 318 | }, |
| 301 | | 319 | |
| 302 | .Comptime => { | 320 | .Comptime => { |
| 303 | assert(!decl.requireSemiColon()); | 321 | assert(!decl.requireSemiColon()); |
| 304 | try renderExpression(allocator, stream, tree, indent, start_col, decl, Space.Newline); | 322 | try renderExpression(allocator, stream, tree, indent, start_col, decl, space); |
| 305 | }, | 323 | }, |
| 306 | | 324 | |
| 307 | .DocComment => { | 325 | .DocComment => { |
| 308 | const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl); | 326 | const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl); |
| 309 | var it = comment.lines.iterator(0); | 327 | var it = comment.lines.iterator(0); |
| 310 | while (it.next()) |line_token_index| { | 328 | while (it.next()) |line_token_index| { |
| 311 | try renderToken(tree, stream, line_token_index.*, indent, start_col, Space.Newline); | 329 | try renderToken(tree, stream, line_token_index.*, indent, start_col, .Newline); |
| 312 | if (it.peek()) |_| { | 330 | if (it.peek()) |_| { |
| 313 | try stream.writeByteNTimes(' ', indent); | 331 | try stream.writeByteNTimes(' ', indent); |
| 314 | } | 332 | } |
| ... | @@ -1150,14 +1168,36 @@ fn renderExpression( | ... | @@ -1150,14 +1168,36 @@ fn renderExpression( |
| 1150 | if (container_decl.fields_and_decls.len == 0) { | 1168 | if (container_decl.fields_and_decls.len == 0) { |
| 1151 | try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, start_col, Space.None); // { | 1169 | try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, start_col, Space.None); // { |
| 1152 | return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // } | 1170 | return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // } |
| 1153 | } else { | 1171 | } |
| | 1172 | |
| | 1173 | const src_has_trailing_comma = blk: { |
| | 1174 | var maybe_comma = tree.prevToken(container_decl.lastToken()); |
| | 1175 | // Doc comments for a field may also appear after the comma, eg. |
| | 1176 | // field_name: T, // comment attached to field_name |
| | 1177 | if (tree.tokens.at(maybe_comma).id == .DocComment) |
| | 1178 | maybe_comma = tree.prevToken(maybe_comma); |
| | 1179 | break :blk tree.tokens.at(maybe_comma).id == .Comma; |
| | 1180 | }; |
| | 1181 | |
| | 1182 | // We can only print all the elements in-line if all the |
| | 1183 | // declarations inside are fields |
| | 1184 | const src_has_only_fields = blk: { |
| | 1185 | var it = container_decl.fields_and_decls.iterator(0); |
| | 1186 | while (it.next()) |decl| { |
| | 1187 | if (decl.*.id != .ContainerField) break :blk false; |
| | 1188 | } |
| | 1189 | break :blk true; |
| | 1190 | }; |
| | 1191 | |
| | 1192 | if (src_has_trailing_comma or !src_has_only_fields) { |
| | 1193 | // One declaration per line |
| 1154 | const new_indent = indent + indent_delta; | 1194 | const new_indent = indent + indent_delta; |
| 1155 | try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, Space.Newline); // { | 1195 | try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, .Newline); // { |
| 1156 | | 1196 | |
| 1157 | var it = container_decl.fields_and_decls.iterator(0); | 1197 | var it = container_decl.fields_and_decls.iterator(0); |
| 1158 | while (it.next()) |decl| { | 1198 | while (it.next()) |decl| { |
| 1159 | try stream.writeByteNTimes(' ', new_indent); | 1199 | try stream.writeByteNTimes(' ', new_indent); |
| 1160 | try renderTopLevelDecl(allocator, stream, tree, new_indent, start_col, decl.*); | 1200 | try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl.*, .Newline); |
| 1161 | | 1201 | |
| 1162 | if (it.peek()) |next_decl| { | 1202 | if (it.peek()) |next_decl| { |
| 1163 | try renderExtraNewline(tree, stream, start_col, next_decl.*); | 1203 | try renderExtraNewline(tree, stream, start_col, next_decl.*); |
| ... | @@ -1165,8 +1205,17 @@ fn renderExpression( | ... | @@ -1165,8 +1205,17 @@ fn renderExpression( |
| 1165 | } | 1205 | } |
| 1166 | | 1206 | |
| 1167 | try stream.writeByteNTimes(' ', indent); | 1207 | try stream.writeByteNTimes(' ', indent); |
| 1168 | return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // } | 1208 | } else { |
| | 1209 | // All the declarations on the same line |
| | 1210 | try renderToken(tree, stream, container_decl.lbrace_token, indent, start_col, .Space); // { |
| | 1211 | |
| | 1212 | var it = container_decl.fields_and_decls.iterator(0); |
| | 1213 | while (it.next()) |decl| { |
| | 1214 | try renderContainerDecl(allocator, stream, tree, indent, start_col, decl.*, .Space); |
| | 1215 | } |
| 1169 | } | 1216 | } |
| | 1217 | |
| | 1218 | return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // } |
| 1170 | }, | 1219 | }, |
| 1171 | | 1220 | |
| 1172 | .ErrorSetDecl => { | 1221 | .ErrorSetDecl => { |