authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-04 19:59:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-04 19:59:06-07:00
log7069459a76ad507bb1ce56b2d8de923b93385def
tree75db4438d313d676093beb62b492c7f3b0721f24
parent8e46d06650cf26f6769817f75ced486e9ee5c0dd

zig fmt: implement struct init


4 files changed, 344 insertions(+), 243 deletions(-)

lib/std/zig/ast.zig+162-17
...@@ -214,8 +214,6 @@ pub const Tree = struct {...@@ -214,8 +214,6 @@ pub const Tree = struct {
214 .OptionalType,214 .OptionalType,
215 .ArrayInitDotTwo,215 .ArrayInitDotTwo,
216 .ArrayInitDot,216 .ArrayInitDot,
217 .StructInitDotTwo,
218 .StructInitDot,
219 .Switch,217 .Switch,
220 .IfSimple,218 .IfSimple,
221 .If,219 .If,
...@@ -252,6 +250,11 @@ pub const Tree = struct {...@@ -252,6 +250,11 @@ pub const Tree = struct {
252 .FnProto,250 .FnProto,
253 => return main_tokens[n],251 => return main_tokens[n],
254252
253 .StructInitDotTwo,
254 .StructInitDotTwoComma,
255 .StructInitDot,
256 => return main_tokens[n] - 1,
257
255 .Catch,258 .Catch,
256 .FieldAccess,259 .FieldAccess,
257 .UnwrapOptional,260 .UnwrapOptional,
...@@ -403,6 +406,7 @@ pub const Tree = struct {...@@ -403,6 +406,7 @@ pub const Tree = struct {
403 .Resume,406 .Resume,
404 .Break,407 .Break,
405 .Return,408 .Return,
409 .Nosuspend,
406 => n = datas[n].lhs,410 => n = datas[n].lhs,
407411
408 .TestDecl,412 .TestDecl,
...@@ -451,7 +455,6 @@ pub const Tree = struct {...@@ -451,7 +455,6 @@ pub const Tree = struct {
451 .AnyFrameType,455 .AnyFrameType,
452 .ErrorUnion,456 .ErrorUnion,
453 .Comptime,457 .Comptime,
454 .Nosuspend,
455 .IfSimple,458 .IfSimple,
456 .WhileSimple,459 .WhileSimple,
457 => n = datas[n].rhs,460 => n = datas[n].rhs,
...@@ -503,27 +506,97 @@ pub const Tree = struct {...@@ -503,27 +506,97 @@ pub const Tree = struct {
503 n = datas[n].rhs;506 n = datas[n].rhs;
504 },507 },
505508
506 .BuiltinCallTwo, .BlockTwo => {509 .BuiltinCallTwo,
510 .BlockTwo,
511 .StructInitDotTwo,
512 => {
507 end_offset += 1; // for the rparen/rbrace513 end_offset += 1; // for the rparen/rbrace
508 if (datas[n].rhs == 0) {514 if (datas[n].rhs != 0) {
509 if (datas[n].lhs == 0) {515 n = datas[n].rhs;
510 return main_tokens[n] + end_offset;516 } else if (datas[n].lhs != 0) {
517 n = datas[n].lhs;
518 } else {
519 return main_tokens[n] + end_offset;
520 }
521 },
522 .StructInitDotTwoComma => {
523 end_offset += 2; // for the comma + rbrace
524 if (datas[n].rhs != 0) {
525 n = datas[n].rhs;
526 } else if (datas[n].lhs != 0) {
527 n = datas[n].lhs;
528 } else {
529 unreachable;
530 }
531 },
532 .SimpleVarDecl => {
533 if (datas[n].rhs != 0) {
534 n = datas[n].rhs;
535 } else if (datas[n].lhs != 0) {
536 n = datas[n].lhs;
537 } else {
538 end_offset += 1; // from mut token to name
539 return main_tokens[n] + end_offset;
540 }
541 },
542 .AlignedVarDecl => {
543 if (datas[n].rhs != 0) {
544 n = datas[n].rhs;
545 } else if (datas[n].lhs != 0) {
546 end_offset += 1; // for the rparen
547 n = datas[n].lhs;
548 } else {
549 end_offset += 1; // from mut token to name
550 return main_tokens[n] + end_offset;
551 }
552 },
553 .GlobalVarDecl => {
554 if (datas[n].rhs != 0) {
555 n = datas[n].rhs;
556 } else {
557 const extra = tree.extraData(datas[n].lhs, Node.GlobalVarDecl);
558 if (extra.section_node != 0) {
559 end_offset += 1; // for the rparen
560 n = extra.section_node;
561 } else if (extra.align_node != 0) {
562 end_offset += 1; // for the rparen
563 n = extra.align_node;
564 } else if (extra.type_node != 0) {
565 n = extra.type_node;
511 } else {566 } else {
512 n = datas[n].lhs;567 end_offset += 1; // from mut token to name
568 return main_tokens[n] + end_offset;
513 }569 }
514 } else {570 }
571 },
572 .LocalVarDecl => {
573 if (datas[n].rhs != 0) {
515 n = datas[n].rhs;574 n = datas[n].rhs;
575 } else {
576 const extra = tree.extraData(datas[n].lhs, Node.LocalVarDecl);
577 if (extra.align_node != 0) {
578 end_offset += 1; // for the rparen
579 n = extra.align_node;
580 } else if (extra.type_node != 0) {
581 n = extra.type_node;
582 } else {
583 end_offset += 1; // from mut token to name
584 return main_tokens[n] + end_offset;
585 }
516 }586 }
517 },587 },
518588
589 // These are not supported by lastToken() because implementation would
590 // require recursion due to the optional comma followed by rbrace.
591 // TODO follow the pattern set by StructInitDotTwoComma which will allow
592 // lastToken to work for all of these.
593 .StructInitDot => unreachable,
519 .ContainerFieldInit => unreachable,594 .ContainerFieldInit => unreachable,
520 .ContainerFieldAlign => unreachable,595 .ContainerFieldAlign => unreachable,
521 .ContainerField => unreachable,596 .ContainerField => unreachable,
522597
523 .ArrayInitDotTwo => unreachable, // TODO598 .ArrayInitDotTwo => unreachable, // TODO
524 .ArrayInitDot => unreachable, // TODO599 .ArrayInitDot => unreachable, // TODO
525 .StructInitDotTwo => unreachable, // TODO
526 .StructInitDot => unreachable, // TODO
527 .Switch => unreachable, // TODO600 .Switch => unreachable, // TODO
528 .If => unreachable, // TODO601 .If => unreachable, // TODO
529 .Continue => unreachable, // TODO602 .Continue => unreachable, // TODO
...@@ -539,10 +612,6 @@ pub const Tree = struct {...@@ -539,10 +612,6 @@ pub const Tree = struct {
539 .SwitchCaseOne => unreachable, // TODO612 .SwitchCaseOne => unreachable, // TODO
540 .SwitchRange => unreachable, // TODO613 .SwitchRange => unreachable, // TODO
541 .FnDecl => unreachable, // TODO614 .FnDecl => unreachable, // TODO
542 .GlobalVarDecl => unreachable, // TODO
543 .LocalVarDecl => unreachable, // TODO
544 .SimpleVarDecl => unreachable, // TODO
545 .AlignedVarDecl => unreachable, // TODO
546 .ArrayType => unreachable, // TODO615 .ArrayType => unreachable, // TODO
547 .ArrayTypeSentinel => unreachable, // TODO616 .ArrayTypeSentinel => unreachable, // TODO
548 .PtrTypeAligned => unreachable, // TODO617 .PtrTypeAligned => unreachable, // TODO
...@@ -743,6 +812,57 @@ pub const Tree = struct {...@@ -743,6 +812,57 @@ pub const Tree = struct {
743 });812 });
744 }813 }
745814
815 pub fn structInitOne(tree: Tree, buffer: *[1]Node.Index, node: Node.Index) Full.StructInit {
816 assert(tree.nodes.items(.tag)[node] == .StructInitOne);
817 const data = tree.nodes.items(.data)[node];
818 buffer[0] = data.rhs;
819 const fields = if (data.rhs == 0) buffer[0..0] else buffer[0..1];
820 return tree.fullStructInit(.{
821 .lbrace = tree.nodes.items(.main_token)[node],
822 .fields = fields,
823 .type_expr = data.lhs,
824 });
825 }
826
827 pub fn structInitDotTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) Full.StructInit {
828 assert(tree.nodes.items(.tag)[node] == .StructInitDotTwo or
829 tree.nodes.items(.tag)[node] == .StructInitDotTwoComma);
830 const data = tree.nodes.items(.data)[node];
831 buffer.* = .{ data.lhs, data.rhs };
832 const fields = if (data.rhs != 0)
833 buffer[0..2]
834 else if (data.lhs != 0)
835 buffer[0..1]
836 else
837 buffer[0..0];
838 return tree.fullStructInit(.{
839 .lbrace = tree.nodes.items(.main_token)[node],
840 .fields = fields,
841 .type_expr = 0,
842 });
843 }
844
845 pub fn structInitDot(tree: Tree, node: Node.Index) Full.StructInit {
846 assert(tree.nodes.items(.tag)[node] == .StructInitDot);
847 const data = tree.nodes.items(.data)[node];
848 return tree.fullStructInit(.{
849 .lbrace = tree.nodes.items(.main_token)[node],
850 .fields = tree.extra_data[data.lhs..data.rhs],
851 .type_expr = 0,
852 });
853 }
854
855 pub fn structInit(tree: Tree, node: Node.Index) Full.StructInit {
856 assert(tree.nodes.items(.tag)[node] == .StructInit);
857 const data = tree.nodes.items(.data)[node];
858 const fields_range = tree.extraData(data.rhs, Node.SubRange);
859 return tree.fullStructInit(.{
860 .lbrace = tree.nodes.items(.main_token)[node],
861 .fields = tree.extra_data[fields_range.start..fields_range.end],
862 .type_expr = data.lhs,
863 });
864 }
865
746 fn fullVarDecl(tree: Tree, info: Full.VarDecl.Ast) Full.VarDecl {866 fn fullVarDecl(tree: Tree, info: Full.VarDecl.Ast) Full.VarDecl {
747 const token_tags = tree.tokens.items(.tag);867 const token_tags = tree.tokens.items(.tag);
748 var result: Full.VarDecl = .{868 var result: Full.VarDecl = .{
...@@ -814,6 +934,14 @@ pub const Tree = struct {...@@ -814,6 +934,14 @@ pub const Tree = struct {
814 };934 };
815 return result;935 return result;
816 }936 }
937
938 fn fullStructInit(tree: Tree, info: Full.StructInit.Ast) Full.StructInit {
939 const token_tags = tree.tokens.items(.tag);
940 var result: Full.StructInit = .{
941 .ast = info,
942 };
943 return result;
944 }
817};945};
818946
819/// Fully assembled AST node information.947/// Fully assembled AST node information.
...@@ -877,6 +1005,16 @@ pub const Full = struct {...@@ -877,6 +1005,16 @@ pub const Full = struct {
877 callconv_expr: Node.Index,1005 callconv_expr: Node.Index,
878 };1006 };
879 };1007 };
1008
1009 pub const StructInit = struct {
1010 ast: Ast,
1011
1012 pub const Ast = struct {
1013 lbrace: TokenIndex,
1014 fields: []const Node.Index,
1015 type_expr: Node.Index,
1016 };
1017 };
880};1018};
8811019
882pub const Error = union(enum) {1020pub const Error = union(enum) {
...@@ -1288,13 +1426,20 @@ pub const Node = struct {...@@ -1288,13 +1426,20 @@ pub const Node = struct {
1288 /// `lhs{a, b}`. `sub_range_list[rhs]`. lhs can be omitted which means `.{a, b}`.1426 /// `lhs{a, b}`. `sub_range_list[rhs]`. lhs can be omitted which means `.{a, b}`.
1289 ArrayInit,1427 ArrayInit,
1290 /// `lhs{.a = rhs}`. rhs can be omitted making it empty.1428 /// `lhs{.a = rhs}`. rhs can be omitted making it empty.
1429 /// main_token is the lbrace.
1291 StructInitOne,1430 StructInitOne,
1292 /// `.{.a = lhs, .b = rhs}`. lhs and rhs can be omitted.1431 /// `.{.a = lhs, .b = rhs}`. lhs and rhs can be omitted.
1432 /// main_token is the lbrace.
1293 StructInitDotTwo,1433 StructInitDotTwo,
1434 /// Same as `StructInitDotTwo` except there is known to be a trailing comma
1435 /// before the final rbrace.
1436 StructInitDotTwoComma,
1294 /// `.{.a = b, .c = d}`. `sub_list[lhs..rhs]`.1437 /// `.{.a = b, .c = d}`. `sub_list[lhs..rhs]`.
1438 /// main_token is the lbrace.
1295 StructInitDot,1439 StructInitDot,
1296 /// `lhs{.a = b, .c = d}`. `sub_range_list[rhs]`.1440 /// `lhs{.a = b, .c = d}`. `sub_range_list[rhs]`.
1297 /// lhs can be omitted which means `.{.a = b, .c = d}`.1441 /// lhs can be omitted which means `.{.a = b, .c = d}`.
1442 /// main_token is the lbrace.
1298 StructInit,1443 StructInit,
1299 /// `lhs(rhs)`. rhs can be omitted.1444 /// `lhs(rhs)`. rhs can be omitted.
1300 CallOne,1445 CallOne,
...@@ -1421,10 +1566,10 @@ pub const Node = struct {...@@ -1421,10 +1566,10 @@ pub const Node = struct {
1421 /// `nosuspend lhs`. rhs unused.1566 /// `nosuspend lhs`. rhs unused.
1422 Nosuspend,1567 Nosuspend,
1423 /// `{lhs; rhs;}`. rhs or lhs can be omitted.1568 /// `{lhs; rhs;}`. rhs or lhs can be omitted.
1424 /// main_token points at the `{`.1569 /// main_token points at the lbrace.
1425 BlockTwo,1570 BlockTwo,
1426 /// `{}`. `sub_list[lhs..rhs]`.1571 /// `{}`. `sub_list[lhs..rhs]`.
1427 /// main_token points at the `{`.1572 /// main_token points at the lbrace.
1428 Block,1573 Block,
1429 /// `asm(lhs)`. rhs unused.1574 /// `asm(lhs)`. rhs unused.
1430 AsmSimple,1575 AsmSimple,
lib/std/zig/parse.zig+10-2
...@@ -2447,8 +2447,12 @@ const Parser = struct {...@@ -2447,8 +2447,12 @@ const Parser = struct {
2447 if (field_init_one != 0) {2447 if (field_init_one != 0) {
2448 const comma_one = p.eatToken(.Comma);2448 const comma_one = p.eatToken(.Comma);
2449 if (p.eatToken(.RBrace)) |_| {2449 if (p.eatToken(.RBrace)) |_| {
2450 const tag: Node.Tag = if (comma_one != null)
2451 .StructInitDotTwoComma
2452 else
2453 .StructInitDotTwo;
2450 return p.addNode(.{2454 return p.addNode(.{
2451 .tag = .StructInitDotTwo,2455 .tag = tag,
2452 .main_token = lbrace,2456 .main_token = lbrace,
2453 .data = .{2457 .data = .{
2454 .lhs = field_init_one,2458 .lhs = field_init_one,
...@@ -2464,8 +2468,12 @@ const Parser = struct {...@@ -2464,8 +2468,12 @@ const Parser = struct {
2464 const field_init_two = try p.expectFieldInit();2468 const field_init_two = try p.expectFieldInit();
2465 const comma_two = p.eatToken(.Comma);2469 const comma_two = p.eatToken(.Comma);
2466 if (p.eatToken(.RBrace)) |_| {2470 if (p.eatToken(.RBrace)) |_| {
2471 const tag: Node.Tag = if (comma_two != null)
2472 .StructInitDotTwoComma
2473 else
2474 .StructInitDotTwo;
2467 return p.addNode(.{2475 return p.addNode(.{
2468 .tag = .StructInitDotTwo,2476 .tag = tag,
2469 .main_token = lbrace,2477 .main_token = lbrace,
2470 .data = .{2478 .data = .{
2471 .lhs = field_init_one,2479 .lhs = field_init_one,
lib/std/zig/parser_test.zig+16-16
...@@ -138,17 +138,17 @@ test "zig fmt: errdefer with payload" {...@@ -138,17 +138,17 @@ test "zig fmt: errdefer with payload" {
138 );138 );
139}139}
140140
141//test "zig fmt: nosuspend block" {141test "zig fmt: nosuspend block" {
142// try testCanonical(142 try testCanonical(
143// \\pub fn main() anyerror!void {143 \\pub fn main() anyerror!void {
144// \\ nosuspend {144 \\ nosuspend {
145// \\ var foo: Foo = .{ .bar = 42 };145 \\ var foo: Foo = .{ .bar = 42 };
146// \\ }146 \\ }
147// \\}147 \\}
148// \\148 \\
149// );149 );
150//}150}
151//151
152//test "zig fmt: nosuspend await" {152//test "zig fmt: nosuspend await" {
153// try testCanonical(153// try testCanonical(
154// \\fn foo() void {154// \\fn foo() void {
...@@ -1505,11 +1505,11 @@ test "zig fmt: errdefer with payload" {...@@ -1505,11 +1505,11 @@ test "zig fmt: errdefer with payload" {
1505//}1505//}
15061506
1507test "zig fmt: ptr deref operator and unwrap optional operator" {1507test "zig fmt: ptr deref operator and unwrap optional operator" {
1508 try testCanonical(1508 try testCanonical(
1509 \\const a = b.*;1509 \\const a = b.*;
1510 \\const a = b.?;1510 \\const a = b.?;
1511 \\1511 \\
1512 );1512 );
1513}1513}
15141514
1515//test "zig fmt: comment after if before another if" {1515//test "zig fmt: comment after if before another if" {
lib/std/zig/render.zig+156-208
...@@ -719,145 +719,16 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -719,145 +719,16 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
719 // return renderToken(ais, tree, rtoken, space);719 // return renderToken(ais, tree, rtoken, space);
720 //},720 //},
721721
722 .StructInitOne => unreachable, // TODO722 .StructInitOne => {
723 .StructInitDotTwo => unreachable, // TODO723 var fields: [1]ast.Node.Index = undefined;
724 .StructInitDot => unreachable, // TODO724 return renderStructInit(ais, tree, tree.structInitOne(&fields, node), space);
725 .StructInit => unreachable, // TODO725 },
726 //.StructInitializer, .StructInitializerDot => {726 .StructInitDotTwo, .StructInitDotTwoComma => {
727 // var rtoken: ast.TokenIndex = undefined;727 var fields: [2]ast.Node.Index = undefined;
728 // var field_inits: []ast.Node.Index = undefined;728 return renderStructInit(ais, tree, tree.structInitDotTwo(&fields, node), space);
729 // const lhs: union(enum) { dot: ast.TokenIndex, node: ast.Node.Index } = switch (base.tag) {729 },
730 // .StructInitializerDot => blk: {730 .StructInitDot => return renderStructInit(ais, tree, tree.structInitDot(node), space),
731 // const casted = @fieldParentPtr(ast.Node.StructInitializerDot, "base", base);731 .StructInit => return renderStructInit(ais, tree, tree.structInit(node), space),
732 // rtoken = casted.rtoken;
733 // field_inits = casted.list();
734 // break :blk .{ .dot = casted.dot };
735 // },
736 // .StructInitializer => blk: {
737 // const casted = @fieldParentPtr(ast.Node.StructInitializer, "base", base);
738 // rtoken = casted.rtoken;
739 // field_inits = casted.list();
740 // break :blk .{ .node = casted.lhs };
741 // },
742 // else => unreachable,
743 // };
744
745 // const lbrace = switch (lhs) {
746 // .dot => |dot| tree.nextToken(dot),
747 // .node => |node| tree.nextToken(node.lastToken()),
748 // };
749
750 // if (field_inits.len == 0) {
751 // switch (lhs) {
752 // .dot => |dot| try renderToken(ais, tree, dot, Space.None),
753 // .node => |node| try renderExpression(ais, tree, node, Space.None),
754 // }
755
756 // {
757 // ais.pushIndentNextLine();
758 // defer ais.popIndent();
759 // try renderToken(ais, tree, lbrace, Space.None);
760 // }
761
762 // return renderToken(ais, tree, rtoken, space);
763 // }
764
765 // const src_has_trailing_comma = blk: {
766 // const maybe_comma = tree.prevToken(rtoken);
767 // break :blk tree.token_tags[maybe_comma] == .Comma;
768 // };
769
770 // const src_same_line = blk: {
771 // const loc = tree.tokenLocation(tree.token_locs[lbrace].end, rtoken);
772 // break :blk loc.line == 0;
773 // };
774
775 // const expr_outputs_one_line = blk: {
776 // // render field expressions until a LF is found
777 // for (field_inits) |field_init| {
778 // var find_stream = std.io.findByteWriter('\n', std.io.null_writer);
779 // var auto_indenting_stream = std.io.autoIndentingStream(indent_delta, find_stream.writer());
780
781 // try renderExpression(allocator, &auto_indenting_stream, tree, field_init, Space.None);
782 // if (find_stream.byte_found) break :blk false;
783 // }
784 // break :blk true;
785 // };
786
787 // if (field_inits.len == 1) blk: {
788 // if (field_inits[0].cast(ast.Node.FieldInitializer)) |field_init| {
789 // switch (field_init.expr.tag) {
790 // .StructInitializer,
791 // .StructInitializerDot,
792 // => break :blk,
793 // else => {},
794 // }
795 // }
796
797 // // if the expression outputs to multiline, make this struct multiline
798 // if (!expr_outputs_one_line or src_has_trailing_comma) {
799 // break :blk;
800 // }
801
802 // switch (lhs) {
803 // .dot => |dot| try renderToken(ais, tree, dot, Space.None),
804 // .node => |node| try renderExpression(ais, tree, node, Space.None),
805 // }
806 // try renderToken(ais, tree, lbrace, Space.Space);
807 // try renderExpression(ais, tree, field_inits[0], Space.Space);
808 // return renderToken(ais, tree, rtoken, space);
809 // }
810
811 // if (!src_has_trailing_comma and src_same_line and expr_outputs_one_line) {
812 // // render all on one line, no trailing comma
813 // switch (lhs) {
814 // .dot => |dot| try renderToken(ais, tree, dot, Space.None),
815 // .node => |node| try renderExpression(ais, tree, node, Space.None),
816 // }
817 // try renderToken(ais, tree, lbrace, Space.Space);
818
819 // for (field_inits) |field_init, i| {
820 // if (i + 1 < field_inits.len) {
821 // try renderExpression(ais, tree, field_init, Space.None);
822
823 // const comma = tree.nextToken(field_init.lastToken());
824 // try renderToken(ais, tree, comma, Space.Space);
825 // } else {
826 // try renderExpression(ais, tree, field_init, Space.Space);
827 // }
828 // }
829
830 // return renderToken(ais, tree, rtoken, space);
831 // }
832
833 // {
834 // switch (lhs) {
835 // .dot => |dot| try renderToken(ais, tree, dot, Space.None),
836 // .node => |node| try renderExpression(ais, tree, node, Space.None),
837 // }
838
839 // ais.pushIndentNextLine();
840 // defer ais.popIndent();
841
842 // try renderToken(ais, tree, lbrace, Space.Newline);
843
844 // for (field_inits) |field_init, i| {
845 // if (i + 1 < field_inits.len) {
846 // const next_field_init = field_inits[i + 1];
847 // try renderExpression(ais, tree, field_init, Space.None);
848
849 // const comma = tree.nextToken(field_init.lastToken());
850 // try renderToken(ais, tree, comma, Space.Newline);
851
852 // try renderExtraNewline(ais, tree, next_field_init);
853 // } else {
854 // try renderExpression(ais, tree, field_init, Space.Comma);
855 // }
856 // }
857 // }
858
859 // return renderToken(ais, tree, rtoken, space);
860 //},
861732
862 .CallOne => unreachable, // TODO733 .CallOne => unreachable, // TODO
863 .Call => {734 .Call => {
...@@ -1078,9 +949,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -1078,9 +949,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
1078 // {949 // {
1079 // ais.pushIndentNextLine();950 // ais.pushIndentNextLine();
1080 // defer ais.popIndent();951 // defer ais.popIndent();
1081 // try renderToken(ais, tree, container_decl.lbrace_token, Space.None); // {952 // try renderToken(ais, tree, container_decl.lbrace_token, Space.None); // lbrace
1082 // }953 // }
1083 // return renderToken(ais, tree, container_decl.rbrace_token, space); // }954 // return renderToken(ais, tree, container_decl.rbrace_token, space); // rbrace
1084 // }955 // }
1085956
1086 // const src_has_trailing_comma = blk: {957 // const src_has_trailing_comma = blk: {
...@@ -1113,7 +984,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -1113,7 +984,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
1113 // // One declaration per line984 // // One declaration per line
1114 // ais.pushIndentNextLine();985 // ais.pushIndentNextLine();
1115 // defer ais.popIndent();986 // defer ais.popIndent();
1116 // try renderToken(ais, tree, container_decl.lbrace_token, .Newline); // {987 // try renderToken(ais, tree, container_decl.lbrace_token, .Newline); // lbrace
1117988
1118 // for (fields_and_decls) |decl, i| {989 // for (fields_and_decls) |decl, i| {
1119 // try renderContainerDecl(allocator, ais, tree, decl, .Newline);990 // try renderContainerDecl(allocator, ais, tree, decl, .Newline);
...@@ -1125,7 +996,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -1125,7 +996,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
1125 // } else if (src_has_newline) {996 // } else if (src_has_newline) {
1126 // // All the declarations on the same line, but place the items on997 // // All the declarations on the same line, but place the items on
1127 // // their own line998 // // their own line
1128 // try renderToken(ais, tree, container_decl.lbrace_token, .Newline); // {999 // try renderToken(ais, tree, container_decl.lbrace_token, .Newline); // lbrace
11291000
1130 // ais.pushIndent();1001 // ais.pushIndent();
1131 // defer ais.popIndent();1002 // defer ais.popIndent();
...@@ -1136,14 +1007,14 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -1136,14 +1007,14 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
1136 // }1007 // }
1137 // } else {1008 // } else {
1138 // // All the declarations on the same line1009 // // All the declarations on the same line
1139 // try renderToken(ais, tree, container_decl.lbrace_token, .Space); // {1010 // try renderToken(ais, tree, container_decl.lbrace_token, .Space); // lbrace
11401011
1141 // for (fields_and_decls) |decl| {1012 // for (fields_and_decls) |decl| {
1142 // try renderContainerDecl(allocator, ais, tree, decl, .Space);1013 // try renderContainerDecl(allocator, ais, tree, decl, .Space);
1143 // }1014 // }
1144 // }1015 // }
11451016
1146 // return renderToken(ais, tree, container_decl.rbrace_token, space); // }1017 // return renderToken(ais, tree, container_decl.rbrace_token, space); // rbrace
1147 //},1018 //},
11481019
1149 .ErrorSetDecl => unreachable, // TODO1020 .ErrorSetDecl => unreachable, // TODO
...@@ -1170,9 +1041,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -1170,9 +1041,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
1170 // }1041 // }
11711042
1172 // try renderToken(ais, tree, err_set_decl.error_token, Space.None); // error1043 // try renderToken(ais, tree, err_set_decl.error_token, Space.None); // error
1173 // try renderToken(ais, tree, lbrace, Space.None); // {1044 // try renderToken(ais, tree, lbrace, Space.None); // lbrace
1174 // try renderExpression(ais, tree, node, Space.None);1045 // try renderExpression(ais, tree, node, Space.None);
1175 // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // }1046 // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // rbrace
1176 // }1047 // }
11771048
1178 // try renderToken(ais, tree, err_set_decl.error_token, Space.None); // error1049 // try renderToken(ais, tree, err_set_decl.error_token, Space.None); // error
...@@ -1187,7 +1058,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -1187,7 +1058,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
1187 // ais.pushIndent();1058 // ais.pushIndent();
1188 // defer ais.popIndent();1059 // defer ais.popIndent();
11891060
1190 // try renderToken(ais, tree, lbrace, Space.Newline); // {1061 // try renderToken(ais, tree, lbrace, Space.Newline); // lbrace
1191 // const decls = err_set_decl.decls();1062 // const decls = err_set_decl.decls();
1192 // for (decls) |node, i| {1063 // for (decls) |node, i| {
1193 // if (i + 1 < decls.len) {1064 // if (i + 1 < decls.len) {
...@@ -1201,9 +1072,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -1201,9 +1072,9 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
1201 // }1072 // }
1202 // }1073 // }
12031074
1204 // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // }1075 // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // rbrace
1205 // } else {1076 // } else {
1206 // try renderToken(ais, tree, lbrace, Space.Space); // {1077 // try renderToken(ais, tree, lbrace, Space.Space); // lbrace
12071078
1208 // const decls = err_set_decl.decls();1079 // const decls = err_set_decl.decls();
1209 // for (decls) |node, i| {1080 // for (decls) |node, i| {
...@@ -1219,7 +1090,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -1219,7 +1090,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
1219 // }1090 // }
1220 // }1091 // }
12211092
1222 // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // }1093 // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // rbrace
1223 // }1094 // }
1224 //},1095 //},
12251096
...@@ -1277,8 +1148,8 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -1277,8 +1148,8 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
1277 // if (switch_node.cases_len == 0) {1148 // if (switch_node.cases_len == 0) {
1278 // try renderExpression(ais, tree, switch_node.expr, Space.None);1149 // try renderExpression(ais, tree, switch_node.expr, Space.None);
1279 // try renderToken(ais, tree, rparen, Space.Space); // )1150 // try renderToken(ais, tree, rparen, Space.Space); // )
1280 // try renderToken(ais, tree, lbrace, Space.None); // {1151 // try renderToken(ais, tree, lbrace, Space.None); // lbrace
1281 // return renderToken(ais, tree, switch_node.rbrace, space); // }1152 // return renderToken(ais, tree, switch_node.rbrace, space); // rbrace
1282 // }1153 // }
12831154
1284 // try renderExpression(ais, tree, switch_node.expr, Space.None);1155 // try renderExpression(ais, tree, switch_node.expr, Space.None);
...@@ -1287,7 +1158,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -1287,7 +1158,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
1287 // {1158 // {
1288 // ais.pushIndentNextLine();1159 // ais.pushIndentNextLine();
1289 // defer ais.popIndent();1160 // defer ais.popIndent();
1290 // try renderToken(ais, tree, lbrace, Space.Newline); // {1161 // try renderToken(ais, tree, lbrace, Space.Newline); // lbrace
12911162
1292 // const cases = switch_node.cases();1163 // const cases = switch_node.cases();
1293 // for (cases) |node, i| {1164 // for (cases) |node, i| {
...@@ -1299,7 +1170,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -1299,7 +1170,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
1299 // }1170 // }
1300 // }1171 // }
13011172
1302 // return renderToken(ais, tree, switch_node.rbrace, space); // }1173 // return renderToken(ais, tree, switch_node.rbrace, space); // rbrace
1303 //},1174 //},
13041175
1305 .SwitchCaseOne => unreachable, // TODO1176 .SwitchCaseOne => unreachable, // TODO
...@@ -1379,7 +1250,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac...@@ -1379,7 +1250,7 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
13791250
1380 // if (body_is_block) {1251 // if (body_is_block) {
1381 // block_start_space = Space.BlockStart;1252 // block_start_space = Space.BlockStart;
1382 // after_body_space = if (while_node.@"else" == null) space else Space.SpaceOrOutdent;1253 // after_body_space = if (while_node.@"else" == null) space else Space.Space;
1383 // } else if (tree.tokensOnSameLine(cond_rparen, while_node.body.lastToken())) {1254 // } else if (tree.tokensOnSameLine(cond_rparen, while_node.body.lastToken())) {
1384 // block_start_space = Space.Space;1255 // block_start_space = Space.Space;
1385 // after_body_space = if (while_node.@"else" == null) space else Space.Space;1256 // after_body_space = if (while_node.@"else" == null) space else Space.Space;
...@@ -1782,10 +1653,7 @@ fn renderVarDecl(ais: *Ais, tree: ast.Tree, var_decl: ast.Full.VarDecl) Error!vo...@@ -1782,10 +1653,7 @@ fn renderVarDecl(ais: *Ais, tree: ast.Tree, var_decl: ast.Full.VarDecl) Error!vo
1782 ais.popIndent();1653 ais.popIndent();
1783 }1654 }
1784 ais.pushIndentOneShot();1655 ais.pushIndentOneShot();
1785 try renderExpression(ais, tree, var_decl.ast.init_node, Space.None);1656 try renderExpression(ais, tree, var_decl.ast.init_node, .Semicolon);
1786
1787 const semicolon = tree.lastToken(var_decl.ast.init_node) + 1;
1788 return renderToken(ais, tree, semicolon, Space.Newline);
1789}1657}
17901658
1791fn renderIf(ais: *Ais, tree: ast.Tree, if_node: ast.Full.If, space: Space) Error!void {1659fn renderIf(ais: *Ais, tree: ast.Tree, if_node: ast.Full.If, space: Space) Error!void {
...@@ -1820,7 +1688,7 @@ fn renderIf(ais: *Ais, tree: ast.Tree, if_node: ast.Full.If, space: Space) Error...@@ -1820,7 +1688,7 @@ fn renderIf(ais: *Ais, tree: ast.Tree, if_node: ast.Full.If, space: Space) Error
1820 try renderToken(ais, tree, rparen, .BlockStart); // )1688 try renderToken(ais, tree, rparen, .BlockStart); // )
1821 }1689 }
1822 if (if_node.ast.else_expr != 0) {1690 if (if_node.ast.else_expr != 0) {
1823 try renderExpression(ais, tree, if_node.ast.then_expr, Space.SpaceOrOutdent);1691 try renderExpression(ais, tree, if_node.ast.then_expr, Space.Space);
1824 try renderToken(ais, tree, if_node.else_token, .Space); // else1692 try renderToken(ais, tree, if_node.else_token, .Space); // else
1825 if (if_node.error_token) |error_token| {1693 if (if_node.error_token) |error_token| {
1826 try renderToken(ais, tree, error_token - 1, .None); // |1694 try renderToken(ais, tree, error_token - 1, .None); // |
...@@ -2197,6 +2065,7 @@ fn renderBlock(...@@ -2197,6 +2065,7 @@ fn renderBlock(
2197) Error!void {2065) Error!void {
2198 const token_tags = tree.tokens.items(.tag);2066 const token_tags = tree.tokens.items(.tag);
2199 const node_tags = tree.nodes.items(.tag);2067 const node_tags = tree.nodes.items(.tag);
2068 const nodes_data = tree.nodes.items(.data);
22002069
2201 if (token_tags[lbrace - 1] == .Colon and2070 if (token_tags[lbrace - 1] == .Colon and
2202 token_tags[lbrace - 2] == .Identifier)2071 token_tags[lbrace - 2] == .Identifier)
...@@ -2204,50 +2073,88 @@ fn renderBlock(...@@ -2204,50 +2073,88 @@ fn renderBlock(
2204 try renderToken(ais, tree, lbrace - 2, .None);2073 try renderToken(ais, tree, lbrace - 2, .None);
2205 try renderToken(ais, tree, lbrace - 1, .Space);2074 try renderToken(ais, tree, lbrace - 1, .Space);
2206 }2075 }
2207 const nodes_data = tree.nodes.items(.data);
22082076
2209 if (statements.len == 0) {2077 if (statements.len == 0) {
2210 ais.pushIndentNextLine();
2211 try renderToken(ais, tree, lbrace, .None);2078 try renderToken(ais, tree, lbrace, .None);
2212 ais.popIndent();2079 return renderToken(ais, tree, lbrace + 1, space); // rbrace
2213 const rbrace = lbrace + 1;2080 }
2214 return renderToken(ais, tree, rbrace, space);2081
2082 ais.pushIndent();
2083 try renderToken(ais, tree, lbrace, .Newline);
2084 for (statements) |stmt, i| {
2085 switch (node_tags[stmt]) {
2086 .GlobalVarDecl => try renderVarDecl(ais, tree, tree.globalVarDecl(stmt)),
2087 .LocalVarDecl => try renderVarDecl(ais, tree, tree.localVarDecl(stmt)),
2088 .SimpleVarDecl => try renderVarDecl(ais, tree, tree.simpleVarDecl(stmt)),
2089 .AlignedVarDecl => try renderVarDecl(ais, tree, tree.alignedVarDecl(stmt)),
2090 else => try renderExpression(ais, tree, stmt, .Semicolon),
2091 }
2092 if (i + 1 < statements.len) {
2093 try renderExtraNewline(ais, tree, statements[i + 1]);
2094 }
2095 }
2096 ais.popIndent();
2097 // The rbrace could be +1 or +2 from the last token of the last
2098 // statement in the block because lastToken() does not count semicolons.
2099 const maybe_rbrace = tree.lastToken(statements[statements.len - 1]) + 1;
2100 if (token_tags[maybe_rbrace] == .RBrace) {
2101 return renderToken(ais, tree, maybe_rbrace, space);
2215 } else {2102 } else {
2216 ais.pushIndentNextLine();2103 assert(token_tags[maybe_rbrace + 1] == .RBrace);
22172104 return renderToken(ais, tree, maybe_rbrace + 1, space);
2218 try renderToken(ais, tree, lbrace, .Newline);2105 }
22192106}
2220 for (statements) |stmt, i| {
2221 switch (node_tags[stmt]) {
2222 .GlobalVarDecl => try renderVarDecl(ais, tree, tree.globalVarDecl(stmt)),
2223 .LocalVarDecl => try renderVarDecl(ais, tree, tree.localVarDecl(stmt)),
2224 .SimpleVarDecl => try renderVarDecl(ais, tree, tree.simpleVarDecl(stmt)),
2225 .AlignedVarDecl => try renderVarDecl(ais, tree, tree.alignedVarDecl(stmt)),
2226 else => {
2227 const semicolon = tree.lastToken(stmt) + 1;
2228 if (token_tags[semicolon] == .Semicolon) {
2229 try renderExpression(ais, tree, stmt, .None);
2230 try renderToken(ais, tree, semicolon, .Newline);
2231 } else {
2232 try renderExpression(ais, tree, stmt, .Newline);
2233 }
2234 },
2235 }
22362107
2237 if (i + 1 < statements.len) {2108fn renderStructInit(
2238 try renderExtraNewline(ais, tree, statements[i + 1]);2109 ais: *Ais,
2239 }2110 tree: ast.Tree,
2111 struct_init: ast.Full.StructInit,
2112 space: Space,
2113) Error!void {
2114 const token_tags = tree.tokens.items(.tag);
2115 if (struct_init.ast.type_expr == 0) {
2116 try renderToken(ais, tree, struct_init.ast.lbrace - 1, .None); // .
2117 } else {
2118 try renderExpression(ais, tree, struct_init.ast.type_expr, .None); // T
2119 }
2120 if (struct_init.ast.fields.len == 0) {
2121 try renderToken(ais, tree, struct_init.ast.lbrace, .None); // lbrace
2122 return renderToken(ais, tree, struct_init.ast.lbrace + 1, space); // rbrace
2123 }
2124 const last_field = struct_init.ast.fields[struct_init.ast.fields.len - 1];
2125 const last_field_token = tree.lastToken(last_field);
2126 if (token_tags[last_field_token + 1] == .Comma) {
2127 // Render one field init per line.
2128 ais.pushIndent();
2129 try renderToken(ais, tree, struct_init.ast.lbrace, .Newline);
2130
2131 try renderToken(ais, tree, struct_init.ast.lbrace + 1, .None); // .
2132 try renderToken(ais, tree, struct_init.ast.lbrace + 2, .Space); // name
2133 try renderToken(ais, tree, struct_init.ast.lbrace + 3, .Space); // =
2134 try renderExpression(ais, tree, struct_init.ast.fields[0], .Comma);
2135
2136 for (struct_init.ast.fields[1..]) |field_init| {
2137 const init_token = tree.firstToken(field_init);
2138 try renderToken(ais, tree, init_token - 3, .None); // .
2139 try renderToken(ais, tree, init_token - 2, .Space); // name
2140 try renderToken(ais, tree, init_token - 1, .Space); // =
2141 try renderExpressionNewlined(ais, tree, field_init, .Comma);
2240 }2142 }
2241 ais.popIndent();2143 ais.popIndent();
2242 // The rbrace could be +1 or +2 from the last token of the last2144 return renderToken(ais, tree, last_field_token + 2, space); // rbrace
2243 // statement in the block because lastToken() does not count semicolons.2145 } else {
2244 const maybe_rbrace = tree.lastToken(statements[statements.len - 1]) + 1;2146 // Render all on one line, no trailing comma.
2245 if (token_tags[maybe_rbrace] == .RBrace) {2147 try renderToken(ais, tree, struct_init.ast.lbrace, .Space);
2246 return renderToken(ais, tree, maybe_rbrace, space);2148
2247 } else {2149 for (struct_init.ast.fields) |field_init| {
2248 assert(token_tags[maybe_rbrace + 1] == .RBrace);2150 const init_token = tree.firstToken(field_init);
2249 return renderToken(ais, tree, maybe_rbrace + 1, space);2151 try renderToken(ais, tree, init_token - 3, .None); // .
2152 try renderToken(ais, tree, init_token - 2, .Space); // name
2153 try renderToken(ais, tree, init_token - 1, .Space); // =
2154 try renderExpression(ais, tree, field_init, .CommaSpace);
2250 }2155 }
2156
2157 return renderToken(ais, tree, last_field_token + 1, space); // rbrace
2251 }2158 }
2252}2159}
22532160
...@@ -2263,6 +2170,22 @@ fn renderExpressionComma(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space:...@@ -2263,6 +2170,22 @@ fn renderExpressionComma(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space:
2263 }2170 }
2264}2171}
22652172
2173/// Render an expression, but first insert an extra newline if the previous token is 2 or
2174/// more lines away.
2175fn renderExpressionNewlined(
2176 ais: *Ais,
2177 tree: ast.Tree,
2178 node: ast.Node.Index,
2179 space: Space,
2180) Error!void {
2181 const token_starts = tree.tokens.items(.start);
2182 const first_token = tree.firstToken(node);
2183 if (tree.tokenLocation(token_starts[first_token - 1], first_token).line >= 2) {
2184 try ais.insertNewline();
2185 }
2186 return renderExpression(ais, tree, node, space);
2187}
2188
2266fn renderTokenComma(ais: *Ais, tree: ast.Tree, token: ast.TokenIndex, space: Space) Error!void {2189fn renderTokenComma(ais: *Ais, tree: ast.Tree, token: ast.TokenIndex, space: Space) Error!void {
2267 const token_tags = tree.tokens.items(.tag);2190 const token_tags = tree.tokens.items(.tag);
2268 const maybe_comma = token + 1;2191 const maybe_comma = token + 1;
...@@ -2275,22 +2198,32 @@ fn renderTokenComma(ais: *Ais, tree: ast.Tree, token: ast.TokenIndex, space: Spa...@@ -2275,22 +2198,32 @@ fn renderTokenComma(ais: *Ais, tree: ast.Tree, token: ast.TokenIndex, space: Spa
2275}2198}
22762199
2277const Space = enum {2200const Space = enum {
2201 /// Output the token lexeme only.
2278 None,2202 None,
2203 /// Output the token lexeme followed by a single space.
2204 Space,
2205 /// Output the token lexeme followed by a newline.
2279 Newline,2206 Newline,
2280 /// `renderToken` will additionally consume the next token if it is a comma.2207 /// Additionally consume the next token if it is a comma.
2208 /// In either case, a newline will be inserted afterwards.
2281 Comma,2209 Comma,
2282 Space,2210 /// Additionally consume the next token if it is a comma.
2283 SpaceOrOutdent,2211 /// In either case, a space will be inserted afterwards.
2284 NoNewline,2212 CommaSpace,
2213 /// Additionally consume the next token if it is a semicolon.
2214 /// In either case, a newline will be inserted afterwards.
2215 Semicolon,
2285 /// Skips writing the possible line comment after the token.2216 /// Skips writing the possible line comment after the token.
2286 NoComment,2217 NoComment,
2218 /// Intended when rendering lbrace tokens. Depending on whether the line is
2219 /// "over indented", will output a newline or a single space afterwards.
2220 /// See `std.io.AutoIndentingStream` for the definition of "over indented".
2287 BlockStart,2221 BlockStart,
2288};2222};
22892223
2290fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Space) Error!void {2224fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Space) Error!void {
2291 if (space == Space.BlockStart) {2225 if (space == Space.BlockStart) {
2292 // If placing the lbrace on the current line would cause an ugly gap then put the lbrace on the next line.2226 const new_space: Space = if (ais.isLineOverIndented()) .Newline else .Space;
2293 const new_space = if (ais.isLineOverIndented()) Space.Newline else Space.Space;
2294 return renderToken(ais, tree, token_index, new_space);2227 return renderToken(ais, tree, token_index, new_space);
2295 }2228 }
22962229
...@@ -2313,7 +2246,6 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp...@@ -2313,7 +2246,6 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp
23132246
2314 switch (space) {2247 switch (space) {
2315 .NoComment => {},2248 .NoComment => {},
2316 .NoNewline => {},
2317 .None => {},2249 .None => {},
2318 .Comma => {2250 .Comma => {
2319 const count = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], ", ");2251 const count = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], ", ");
...@@ -2326,10 +2258,25 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp...@@ -2326,10 +2258,25 @@ fn renderToken(ais: *Ais, tree: ast.Tree, token_index: ast.TokenIndex, space: Sp
2326 try ais.insertNewline();2258 try ais.insertNewline();
2327 }2259 }
2328 },2260 },
2329 .SpaceOrOutdent => @panic("what does this even do"),2261 .CommaSpace => {
2262 _ = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], "");
2263 if (token_tags[token_index + 1] == .Comma) {
2264 return renderToken(ais, tree, token_index + 1, .Space);
2265 } else {
2266 return ais.writer().writeByte(' ');
2267 }
2268 },
2269 .Semicolon => {
2270 _ = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], "");
2271 if (token_tags[token_index + 1] == .Semicolon) {
2272 return renderToken(ais, tree, token_index + 1, .Newline);
2273 } else {
2274 return ais.insertNewline();
2275 }
2276 },
2330 .Space => {2277 .Space => {
2331 _ = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], "");2278 _ = try renderComments(ais, tree, token_start + lexeme.len, token_starts[token_index + 1], "");
2332 try ais.writer().writeByte(' ');2279 return ais.writer().writeByte(' ');
2333 },2280 },
2334 .Newline => {2281 .Newline => {
2335 if (token_tags[token_index + 1] != .MultilineStringLiteralLine) {2282 if (token_tags[token_index + 1] != .MultilineStringLiteralLine) {
...@@ -2437,10 +2384,11 @@ fn nodeCausesSliceOpSpace(base: ast.Node.Index) bool {...@@ -2437,10 +2384,11 @@ fn nodeCausesSliceOpSpace(base: ast.Node.Index) bool {
2437}2384}
24382385
2439fn copyFixingWhitespace(ais: *Ais, slice: []const u8) @TypeOf(ais.*).Error!void {2386fn copyFixingWhitespace(ais: *Ais, slice: []const u8) @TypeOf(ais.*).Error!void {
2387 const writer = ais.writer();
2440 for (slice) |byte| switch (byte) {2388 for (slice) |byte| switch (byte) {
2441 '\t' => try ais.writer().writeAll(" "),2389 '\t' => try writer.writeAll(" "),
2442 '\r' => {},2390 '\r' => {},
2443 else => try ais.writer().writeByte(byte),2391 else => try writer.writeByte(byte),
2444 };2392 };
2445}2393}
24462394