| ... | ... | @@ -206,6 +206,10 @@ fn renderExtraNewline(tree: *ast.Tree, stream: var, start_col: *usize, node: *as |
| 206 | 206 | } |
| 207 | 207 | |
| 208 | 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 | 213 | switch (decl.id) { |
| 210 | 214 | .FnProto => { |
| 211 | 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 | 217 | try renderDocComments(tree, stream, fn_proto, indent, start_col); |
| 214 | 218 | |
| 215 | 219 | if (fn_proto.body_node) |body_node| { |
| 216 | | try renderExpression(allocator, stream, tree, indent, start_col, decl, Space.Space); |
| 217 | | try renderExpression(allocator, stream, tree, indent, start_col, body_node, Space.Newline); |
| 220 | try renderExpression(allocator, stream, tree, indent, start_col, decl, .Space); |
| 221 | try renderExpression(allocator, stream, tree, indent, start_col, body_node, space); |
| 218 | 222 | } else { |
| 219 | | try renderExpression(allocator, stream, tree, indent, start_col, decl, Space.None); |
| 220 | | try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, start_col, Space.Newline); |
| 223 | try renderExpression(allocator, stream, tree, indent, start_col, decl, .None); |
| 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 | 229 | const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl); |
| 226 | 230 | |
| 227 | 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 |
| 231 | | try renderExpression(allocator, stream, tree, indent, start_col, use_decl.expr, Space.None); |
| 232 | | try renderToken(tree, stream, use_decl.semicolon_token, indent, start_col, Space.Newline); // ; |
| 234 | try renderToken(tree, stream, use_decl.use_token, indent, start_col, .Space); // usingnamespace |
| 235 | try renderExpression(allocator, stream, tree, indent, start_col, use_decl.expr, .None); |
| 236 | try renderToken(tree, stream, use_decl.semicolon_token, indent, start_col, space); // ; |
| 233 | 237 | }, |
| 234 | 238 | |
| 235 | 239 | .VarDecl => { |
| ... | ... | @@ -243,9 +247,9 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i |
| 243 | 247 | const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl); |
| 244 | 248 | |
| 245 | 249 | try renderDocComments(tree, stream, test_decl, indent, start_col); |
| 246 | | try renderToken(tree, stream, test_decl.test_token, indent, start_col, Space.Space); |
| 247 | | try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, Space.Space); |
| 248 | | try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, Space.Newline); |
| 250 | try renderToken(tree, stream, test_decl.test_token, indent, start_col, .Space); |
| 251 | try renderExpression(allocator, stream, tree, indent, start_col, test_decl.name, .Space); |
| 252 | try renderExpression(allocator, stream, tree, indent, start_col, test_decl.body_node, space); |
| 249 | 253 | }, |
| 250 | 254 | |
| 251 | 255 | .ContainerField => { |
| ... | ... | @@ -253,62 +257,76 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i |
| 253 | 257 | |
| 254 | 258 | try renderDocComments(tree, stream, field, indent, start_col); |
| 255 | 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 | 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 | 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 |
| 263 | | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // : |
| 275 | try renderToken(tree, stream, field.name_token, indent, start_col, .None); // name |
| 276 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // : |
| 264 | 277 | |
| 265 | 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 | 280 | const lparen_token = tree.prevToken(align_value_expr.firstToken()); |
| 268 | 281 | const align_kw = tree.prevToken(lparen_token); |
| 269 | 282 | const rparen_token = tree.nextToken(align_value_expr.lastToken()); |
| 270 | | try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align |
| 271 | | try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // ( |
| 272 | | try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, Space.None); // alignment |
| 273 | | try renderToken(tree, stream, rparen_token, indent, start_col, Space.Comma); // ), |
| 283 | try renderToken(tree, stream, align_kw, indent, start_col, .None); // align |
| 284 | try renderToken(tree, stream, lparen_token, indent, start_col, .None); // ( |
| 285 | try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, .None); // alignment |
| 286 | try renderToken(tree, stream, rparen_token, indent, start_col, last_token_space); // ) |
| 274 | 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 | 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 |
| 279 | | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // = |
| 280 | | return renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, Space.Comma); // value |
| 291 | try renderToken(tree, stream, field.name_token, indent, start_col, .Space); // name |
| 292 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // = |
| 293 | try renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, last_token_space); // value |
| 281 | 294 | } else { |
| 282 | | try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name |
| 283 | | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // : |
| 295 | try renderToken(tree, stream, field.name_token, indent, start_col, .None); // name |
| 296 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, .Space); // : |
| 284 | 297 | |
| 285 | 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 | 300 | const lparen_token = tree.prevToken(align_value_expr.firstToken()); |
| 288 | 301 | const align_kw = tree.prevToken(lparen_token); |
| 289 | 302 | const rparen_token = tree.nextToken(align_value_expr.lastToken()); |
| 290 | | try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align |
| 291 | | try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // ( |
| 292 | | try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, Space.None); // alignment |
| 293 | | try renderToken(tree, stream, rparen_token, indent, start_col, Space.Space); // ) |
| 303 | try renderToken(tree, stream, align_kw, indent, start_col, .None); // align |
| 304 | try renderToken(tree, stream, lparen_token, indent, start_col, .None); // ( |
| 305 | try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, .None); // alignment |
| 306 | try renderToken(tree, stream, rparen_token, indent, start_col, .Space); // ) |
| 294 | 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); // = |
| 298 | | return renderExpression(allocator, stream, tree, indent, start_col, field.value_expr.?, Space.Comma); // value, |
| 310 | try renderToken(tree, stream, tree.prevToken(field.value_expr.?.firstToken()), indent, start_col, .Space); // = |
| 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 | 320 | .Comptime => { |
| 303 | 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 | 325 | .DocComment => { |
| 308 | 326 | const comment = @fieldParentPtr(ast.Node.DocComment, "base", decl); |
| 309 | 327 | var it = comment.lines.iterator(0); |
| 310 | 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 | 330 | if (it.peek()) |_| { |
| 313 | 331 | try stream.writeByteNTimes(' ', indent); |
| 314 | 332 | } |
| ... | ... | @@ -1150,14 +1168,42 @@ fn renderExpression( |
| 1150 | 1168 | if (container_decl.fields_and_decls.len == 0) { |
| 1151 | 1169 | try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, start_col, Space.None); // { |
| 1152 | 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 | // Check if the first declaration and the { are on the same line |
| 1183 | const src_has_newline = !tree.tokensOnSameLine( |
| 1184 | container_decl.lbrace_token, |
| 1185 | container_decl.fields_and_decls.at(0).*.firstToken(), |
| 1186 | ); |
| 1187 | |
| 1188 | // We can only print all the elements in-line if all the |
| 1189 | // declarations inside are fields |
| 1190 | const src_has_only_fields = blk: { |
| 1191 | var it = container_decl.fields_and_decls.iterator(0); |
| 1192 | while (it.next()) |decl| { |
| 1193 | if (decl.*.id != .ContainerField) break :blk false; |
| 1194 | } |
| 1195 | break :blk true; |
| 1196 | }; |
| 1197 | |
| 1198 | if (src_has_trailing_comma or !src_has_only_fields) { |
| 1199 | // One declaration per line |
| 1154 | 1200 | const new_indent = indent + indent_delta; |
| 1155 | | try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, Space.Newline); // { |
| 1201 | try renderToken(tree, stream, container_decl.lbrace_token, new_indent, start_col, .Newline); // { |
| 1156 | 1202 | |
| 1157 | 1203 | var it = container_decl.fields_and_decls.iterator(0); |
| 1158 | 1204 | while (it.next()) |decl| { |
| 1159 | 1205 | try stream.writeByteNTimes(' ', new_indent); |
| 1160 | | try renderTopLevelDecl(allocator, stream, tree, new_indent, start_col, decl.*); |
| 1206 | try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl.*, .Newline); |
| 1161 | 1207 | |
| 1162 | 1208 | if (it.peek()) |next_decl| { |
| 1163 | 1209 | try renderExtraNewline(tree, stream, start_col, next_decl.*); |
| ... | ... | @@ -1165,8 +1211,30 @@ fn renderExpression( |
| 1165 | 1211 | } |
| 1166 | 1212 | |
| 1167 | 1213 | try stream.writeByteNTimes(' ', indent); |
| 1168 | | return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // } |
| 1214 | } else if (src_has_newline) { |
| 1215 | // All the declarations on the same line, but place the items on |
| 1216 | // their own line |
| 1217 | try renderToken(tree, stream, container_decl.lbrace_token, indent, start_col, .Newline); // { |
| 1218 | |
| 1219 | const new_indent = indent + indent_delta; |
| 1220 | try stream.writeByteNTimes(' ', new_indent); |
| 1221 | |
| 1222 | var it = container_decl.fields_and_decls.iterator(0); |
| 1223 | while (it.next()) |decl| { |
| 1224 | const space_after_decl: Space = if (it.peek() == null) .Newline else .Space; |
| 1225 | try renderContainerDecl(allocator, stream, tree, new_indent, start_col, decl.*, space_after_decl); |
| 1226 | } |
| 1227 | } else { |
| 1228 | // All the declarations on the same line |
| 1229 | try renderToken(tree, stream, container_decl.lbrace_token, indent, start_col, .Space); // { |
| 1230 | |
| 1231 | var it = container_decl.fields_and_decls.iterator(0); |
| 1232 | while (it.next()) |decl| { |
| 1233 | try renderContainerDecl(allocator, stream, tree, indent, start_col, decl.*, .Space); |
| 1234 | } |
| 1169 | 1235 | } |
| 1236 | |
| 1237 | return renderToken(tree, stream, container_decl.rbrace_token, indent, start_col, space); // } |
| 1170 | 1238 | }, |
| 1171 | 1239 | |
| 1172 | 1240 | .ErrorSetDecl => { |