authorgravatar for mail@isaacfreund.comIsaac Freund <mail@isaacfreund.com> 2021-02-08 13:38:24+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-02-08 15:41:31-08:00
logd869133a9fb96fb27a07c1e42c12c5270eae5940
tree6ea7c15c277ae03fa3d2c60a89a90288adce7532
parent837cd748a8607a6ac9f1a5bfc6d625512bacb906

zig fmt: implement switches


4 files changed, 249 insertions(+), 262 deletions(-)

lib/std/zig/ast.zig+88-13
......@@ -213,6 +213,7 @@ pub const Tree = struct {
213213 .Await,
214214 .OptionalType,
215215 .Switch,
216 .SwitchComma,
216217 .IfSimple,
217218 .If,
218219 .Suspend,
......@@ -313,7 +314,6 @@ pub const Tree = struct {
313314 .StructInit,
314315 .CallOne,
315316 .Call,
316 .SwitchCaseOne,
317317 .SwitchRange,
318318 .FnDecl,
319319 .ErrorUnion,
......@@ -406,7 +406,19 @@ pub const Tree = struct {
406406 };
407407 },
408408
409 .SwitchCaseMulti => unreachable, // TODO
409 .SwitchCaseOne => {
410 if (datas[n].lhs == 0) {
411 return main_tokens[n] - 1; // else token
412 } else {
413 n = datas[n].lhs;
414 }
415 },
416 .SwitchCase => {
417 const extra = tree.extraData(datas[n].lhs, Node.SubRange);
418 assert(extra.end - extra.start > 0);
419 n = extra.start;
420 },
421
410422 .WhileSimple => unreachable, // TODO
411423 .WhileCont => unreachable, // TODO
412424 .While => unreachable, // TODO
......@@ -494,6 +506,8 @@ pub const Tree = struct {
494506 .PtrTypeSentinel,
495507 .PtrType,
496508 .PtrTypeBitRange,
509 .SwitchCaseOne,
510 .SwitchCase,
497511 => n = datas[n].rhs,
498512
499513 .FieldAccess,
......@@ -532,6 +546,16 @@ pub const Tree = struct {
532546 }
533547 n = tree.extra_data[params.end - 1]; // last parameter
534548 },
549 .Switch => {
550 const cases = tree.extraData(datas[n].rhs, Node.SubRange);
551 if (cases.end - cases.start == 0) {
552 end_offset += 3; // rparen, lbrace, rbrace
553 n = datas[n].lhs; // condition expression
554 } else {
555 end_offset += 1; // for the rbrace
556 n = tree.extra_data[cases.end - 1]; // last case
557 }
558 },
535559 .ContainerDeclArg => {
536560 const members = tree.extraData(datas[n].rhs, Node.SubRange);
537561 if (members.end - members.start == 0) {
......@@ -542,7 +566,9 @@ pub const Tree = struct {
542566 n = tree.extra_data[members.end - 1]; // last parameter
543567 }
544568 },
545 .ContainerDeclArgComma => {
569 .ContainerDeclArgComma,
570 .SwitchComma,
571 => {
546572 const members = tree.extraData(datas[n].rhs, Node.SubRange);
547573 assert(members.end - members.start > 0);
548574 end_offset += 2; // for the comma + rbrace
......@@ -737,16 +763,13 @@ pub const Tree = struct {
737763
738764 .TaggedUnionEnumTag => unreachable, // TODO
739765 .TaggedUnionEnumTagComma => unreachable, // TODO
740 .Switch => unreachable, // TODO
741766 .If => unreachable, // TODO
742767 .Continue => unreachable, // TODO
743768 .AsmSimple => unreachable, // TODO
744769 .Asm => unreachable, // TODO
745 .SwitchCaseOne => unreachable, // TODO
746770 .SwitchRange => unreachable, // TODO
747771 .ArrayType => unreachable, // TODO
748772 .ArrayTypeSentinel => unreachable, // TODO
749 .SwitchCaseMulti => unreachable, // TODO
750773 .WhileCont => unreachable, // TODO
751774 .While => unreachable, // TODO
752775 .ForSimple => unreachable, // TODO
......@@ -1202,7 +1225,8 @@ pub const Tree = struct {
12021225 }
12031226
12041227 pub fn containerDeclArg(tree: Tree, node: Node.Index) Full.ContainerDecl {
1205 assert(tree.nodes.items(.tag)[node] == .ContainerDeclArg);
1228 assert(tree.nodes.items(.tag)[node] == .ContainerDeclArg or
1229 tree.nodes.items(.tag)[node] == .ContainerDeclArgComma);
12061230 const data = tree.nodes.items(.data)[node];
12071231 const members_range = tree.extraData(data.rhs, Node.SubRange);
12081232 return tree.fullContainerDecl(.{
......@@ -1214,7 +1238,8 @@ pub const Tree = struct {
12141238 }
12151239
12161240 pub fn taggedUnionTwo(tree: Tree, buffer: *[2]Node.Index, node: Node.Index) Full.ContainerDecl {
1217 assert(tree.nodes.items(.tag)[node] == .TaggedUnionTwo);
1241 assert(tree.nodes.items(.tag)[node] == .TaggedUnionTwo or
1242 tree.nodes.items(.tag)[node] == .TaggedUnionTwoComma);
12181243 const data = tree.nodes.items(.data)[node];
12191244 buffer.* = .{ data.lhs, data.rhs };
12201245 const members = if (data.rhs != 0)
......@@ -1233,7 +1258,8 @@ pub const Tree = struct {
12331258 }
12341259
12351260 pub fn taggedUnion(tree: Tree, node: Node.Index) Full.ContainerDecl {
1236 assert(tree.nodes.items(.tag)[node] == .TaggedUnion);
1261 assert(tree.nodes.items(.tag)[node] == .TaggedUnion or
1262 tree.nodes.items(.tag)[node] == .TaggedUnionComma);
12371263 const data = tree.nodes.items(.data)[node];
12381264 const main_token = tree.nodes.items(.main_token)[node];
12391265 return tree.fullContainerDecl(.{
......@@ -1245,7 +1271,8 @@ pub const Tree = struct {
12451271 }
12461272
12471273 pub fn taggedUnionEnumTag(tree: Tree, node: Node.Index) Full.ContainerDecl {
1248 assert(tree.nodes.items(.tag)[node] == .TaggedUnionEnumTag);
1274 assert(tree.nodes.items(.tag)[node] == .TaggedUnionEnumTag or
1275 tree.nodes.items(.tag)[node] == .TaggedUnionEnumTagComma);
12491276 const data = tree.nodes.items(.data)[node];
12501277 const members_range = tree.extraData(data.rhs, Node.SubRange);
12511278 const main_token = tree.nodes.items(.main_token)[node];
......@@ -1257,6 +1284,25 @@ pub const Tree = struct {
12571284 });
12581285 }
12591286
1287 pub fn switchCaseOne(tree: Tree, node: Node.Index) Full.SwitchCase {
1288 const data = &tree.nodes.items(.data)[node];
1289 return tree.fullSwitchCase(.{
1290 .values = if (data.lhs == 0) &.{} else @ptrCast([*]Node.Index, &data.lhs)[0..1],
1291 .arrow_token = tree.nodes.items(.main_token)[node],
1292 .target_expr = data.rhs,
1293 });
1294 }
1295
1296 pub fn switchCase(tree: Tree, node: Node.Index) Full.SwitchCase {
1297 const data = tree.nodes.items(.data)[node];
1298 const extra = tree.extraData(data.lhs, Node.SubRange);
1299 return tree.fullSwitchCase(.{
1300 .values = tree.extra_data[extra.start..extra.end],
1301 .arrow_token = tree.nodes.items(.main_token)[node],
1302 .target_expr = data.rhs,
1303 });
1304 }
1305
12601306 fn fullVarDecl(tree: Tree, info: Full.VarDecl.Ast) Full.VarDecl {
12611307 const token_tags = tree.tokens.items(.tag);
12621308 var result: Full.VarDecl = .{
......@@ -1407,6 +1453,18 @@ pub const Tree = struct {
14071453 }
14081454 return result;
14091455 }
1456
1457 fn fullSwitchCase(tree: Tree, info: Full.SwitchCase.Ast) Full.SwitchCase {
1458 const token_tags = tree.tokens.items(.tag);
1459 var result: Full.SwitchCase = .{
1460 .ast = info,
1461 .payload_token = null,
1462 };
1463 if (token_tags[info.arrow_token + 1] == .Pipe) {
1464 result.payload_token = info.arrow_token + 2;
1465 }
1466 return result;
1467 }
14101468};
14111469
14121470/// Fully assembled AST node information.
......@@ -1552,6 +1610,20 @@ pub const Full = struct {
15521610 arg: Node.Index,
15531611 };
15541612 };
1613
1614 pub const SwitchCase = struct {
1615 /// Points to the first token after the `|`. Will either be an identifier or
1616 /// a `*` (with an identifier immediately after it).
1617 payload_token: ?TokenIndex,
1618 ast: Ast,
1619
1620 pub const Ast = struct {
1621 /// If empty, this is an else case
1622 values: []const Node.Index,
1623 arrow_token: TokenIndex,
1624 target_expr: Node.Index,
1625 };
1626 };
15551627};
15561628
15571629pub const Error = union(enum) {
......@@ -1996,13 +2068,16 @@ pub const Node = struct {
19962068 /// `lhs(a, b, c)`. `sub_range_list[rhs]`.
19972069 /// main_token is the `(`.
19982070 Call,
1999 /// `switch(lhs) {}`. `sub_range_list[rhs]`.
2071 /// `switch(lhs) {}`. `SubRange[rhs]`.
20002072 Switch,
2073 /// Same as Switch except there is known to be a trailing comma
2074 /// before the final rbrace
2075 SwitchComma,
20012076 /// `lhs => rhs`. If lhs is omitted it means `else`.
20022077 /// main_token is the `=>`
20032078 SwitchCaseOne,
2004 /// `a, b, c => rhs`. `sub_range_list[lhs]`.
2005 SwitchCaseMulti,
2079 /// `a, b, c => rhs`. `SubRange[lhs]`.
2080 SwitchCase,
20062081 /// `lhs...rhs`.
20072082 SwitchRange,
20082083 /// `while (lhs) rhs`.
lib/std/zig/parse.zig+3-2
......@@ -2887,10 +2887,11 @@ const Parser = struct {
28872887 _ = try p.expectToken(.RParen);
28882888 _ = try p.expectToken(.LBrace);
28892889 const cases = try p.parseSwitchProngList();
2890 const trailing_comma = p.token_tags[p.tok_i - 1] == .Comma;
28902891 _ = try p.expectToken(.RBrace);
28912892
28922893 return p.addNode(.{
2893 .tag = .Switch,
2894 .tag = if (trailing_comma) .SwitchComma else .Switch,
28942895 .main_token = switch_token,
28952896 .data = .{
28962897 .lhs = expr_node,
......@@ -3208,7 +3209,7 @@ const Parser = struct {
32083209 const arrow_token = try p.expectToken(.EqualAngleBracketRight);
32093210 _ = try p.parsePtrPayload();
32103211 return p.addNode(.{
3211 .tag = .SwitchCaseMulti,
3212 .tag = .SwitchCase,
32123213 .main_token = arrow_token,
32133214 .data = .{
32143215 .lhs = try p.addExtra(Node.SubRange{
lib/std/zig/parser_test.zig+72-72
......@@ -1671,32 +1671,32 @@ test "zig fmt: block in slice expression" {
16711671// \\
16721672// );
16731673//}
1674//
1675//test "zig fmt: switch cases trailing comma" {
1676// try testTransform(
1677// \\fn switch_cases(x: i32) void {
1678// \\ switch (x) {
1679// \\ 1,2,3 => {},
1680// \\ 4,5, => {},
1681// \\ 6... 8, => {},
1682// \\ else => {},
1683// \\ }
1684// \\}
1685// ,
1686// \\fn switch_cases(x: i32) void {
1687// \\ switch (x) {
1688// \\ 1, 2, 3 => {},
1689// \\ 4,
1690// \\ 5,
1691// \\ => {},
1692// \\ 6...8 => {},
1693// \\ else => {},
1694// \\ }
1695// \\}
1696// \\
1697// );
1698//}
1699//
1674
1675test "zig fmt: switch cases trailing comma" {
1676 try testTransform(
1677 \\test "switch cases trailing comma"{
1678 \\ switch (x) {
1679 \\ 1,2,3 => {},
1680 \\ 4,5, => {},
1681 \\ 6... 8, => {},
1682 \\ else => {},
1683 \\ }
1684 \\}
1685 ,
1686 \\test "switch cases trailing comma" {
1687 \\ switch (x) {
1688 \\ 1, 2, 3 => {},
1689 \\ 4,
1690 \\ 5,
1691 \\ => {},
1692 \\ 6...8 => {},
1693 \\ else => {},
1694 \\ }
1695 \\}
1696 \\
1697 );
1698}
1699
17001700//test "zig fmt: slice align" {
17011701// try testCanonical(
17021702// \\const A = struct {
......@@ -1996,16 +1996,16 @@ test "zig fmt: ptr deref operator and unwrap optional operator" {
19961996// \\
19971997// );
19981998//}
1999//
2000//test "zig fmt: switch with empty body" {
2001// try testCanonical(
2002// \\test "" {
2003// \\ foo() catch |err| switch (err) {};
2004// \\}
2005// \\
2006// );
2007//}
2008//
1999
2000test "zig fmt: switch with empty body" {
2001 try testCanonical(
2002 \\test "" {
2003 \\ foo() catch |err| switch (err) {};
2004 \\}
2005 \\
2006 );
2007}
2008
20092009//test "zig fmt: line comments in struct initializer" {
20102010// try testCanonical(
20112011// \\fn foo() void {
......@@ -2725,42 +2725,42 @@ test "zig fmt: blocks" {
27252725 );
27262726}
27272727
2728//test "zig fmt: switch" {
2729// try testCanonical(
2730// \\test "switch" {
2731// \\ switch (0) {
2732// \\ 0 => {},
2733// \\ 1 => unreachable,
2734// \\ 2, 3 => {},
2735// \\ 4...7 => {},
2736// \\ 1 + 4 * 3 + 22 => {},
2737// \\ else => {
2738// \\ const a = 1;
2739// \\ const b = a;
2740// \\ },
2741// \\ }
2742// \\
2743// \\ const res = switch (0) {
2744// \\ 0 => 0,
2745// \\ 1 => 2,
2746// \\ 1 => a = 4,
2747// \\ else => 4,
2748// \\ };
2749// \\
2750// \\ const Union = union(enum) {
2751// \\ Int: i64,
2752// \\ Float: f64,
2753// \\ };
2754// \\
2755// \\ switch (u) {
2756// \\ Union.Int => |int| {},
2757// \\ Union.Float => |*float| unreachable,
2758// \\ }
2759// \\}
2760// \\
2761// );
2762//}
2763//
2728test "zig fmt: switch" {
2729 try testCanonical(
2730 \\test "switch" {
2731 \\ switch (0) {
2732 \\ 0 => {},
2733 \\ 1 => unreachable,
2734 \\ 2, 3 => {},
2735 \\ 4...7 => {},
2736 \\ 1 + 4 * 3 + 22 => {},
2737 \\ else => {
2738 \\ const a = 1;
2739 \\ const b = a;
2740 \\ },
2741 \\ }
2742 \\
2743 \\ const res = switch (0) {
2744 \\ 0 => 0,
2745 \\ 1 => 2,
2746 \\ 1 => a = 4,
2747 \\ else => 4,
2748 \\ };
2749 \\
2750 \\ const Union = union(enum) {
2751 \\ Int: i64,
2752 \\ Float: f64,
2753 \\ };
2754 \\
2755 \\ switch (u) {
2756 \\ Union.Int => |int| {},
2757 \\ Union.Float => |*float| unreachable,
2758 \\ }
2759 \\}
2760 \\
2761 );
2762}
2763
27642764//test "zig fmt: while" {
27652765// try testCanonical(
27662766// \\test "while" {
lib/std/zig/render.zig+86-175
......@@ -207,19 +207,18 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
207207 => {
208208 const statements = [2]ast.Node.Index{ datas[node].lhs, datas[node].rhs };
209209 if (datas[node].lhs == 0) {
210 return renderBlock(ais, tree, main_tokens[node], statements[0..0], space);
210 return renderBlock(ais, tree, node, statements[0..0], space);
211211 } else if (datas[node].rhs == 0) {
212 return renderBlock(ais, tree, main_tokens[node], statements[0..1], space);
212 return renderBlock(ais, tree, node, statements[0..1], space);
213213 } else {
214 return renderBlock(ais, tree, main_tokens[node], statements[0..2], space);
214 return renderBlock(ais, tree, node, statements[0..2], space);
215215 }
216216 },
217217 .Block,
218218 .BlockSemicolon,
219219 => {
220 const lbrace = main_tokens[node];
221220 const statements = tree.extra_data[datas[node].lhs..datas[node].rhs];
222 return renderBlock(ais, tree, main_tokens[node], statements, space);
221 return renderBlock(ais, tree, node, statements, space);
223222 },
224223
225224 .ErrDefer => {
......@@ -615,81 +614,6 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
615614 try renderToken(ais, tree, rbrace, space);
616615 }
617616 },
618 //.ErrorSetDecl => {
619 // const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
620
621 // const lbrace = tree.nextToken(err_set_decl.error_token);
622
623 // if (err_set_decl.decls_len == 0) {
624 // try renderToken(ais, tree, err_set_decl.error_token, Space.None);
625 // try renderToken(ais, tree, lbrace, Space.None);
626 // return renderToken(ais, tree, err_set_decl.rbrace_token, space);
627 // }
628
629 // if (err_set_decl.decls_len == 1) blk: {
630 // const node = err_set_decl.decls()[0];
631
632 // // if there are any doc comments or same line comments
633 // // don't try to put it all on one line
634 // if (node.cast(ast.Node.ErrorTag)) |tag| {
635 // if (tag.doc_comments != null) break :blk;
636 // } else {
637 // break :blk;
638 // }
639
640 // try renderToken(ais, tree, err_set_decl.error_token, Space.None); // error
641 // try renderToken(ais, tree, lbrace, Space.None); // lbrace
642 // try renderExpression(ais, tree, node, Space.None);
643 // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // rbrace
644 // }
645
646 // try renderToken(ais, tree, err_set_decl.error_token, Space.None); // error
647
648 // const src_has_trailing_comma = blk: {
649 // const maybe_comma = tree.prevToken(err_set_decl.rbrace_token);
650 // break :blk tree.token_tags[maybe_comma] == .Comma;
651 // };
652
653 // if (src_has_trailing_comma) {
654 // {
655 // ais.pushIndent();
656 // defer ais.popIndent();
657
658 // try renderToken(ais, tree, lbrace, Space.Newline); // lbrace
659 // const decls = err_set_decl.decls();
660 // for (decls) |node, i| {
661 // if (i + 1 < decls.len) {
662 // try renderExpression(ais, tree, node, Space.None);
663 // try renderToken(ais, tree, tree.nextToken(node.lastToken()), Space.Newline); // ,
664
665 // try renderExtraNewline(ais, tree, decls[i + 1]);
666 // } else {
667 // try renderExpression(ais, tree, node, Space.Comma);
668 // }
669 // }
670 // }
671
672 // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // rbrace
673 // } else {
674 // try renderToken(ais, tree, lbrace, Space.Space); // lbrace
675
676 // const decls = err_set_decl.decls();
677 // for (decls) |node, i| {
678 // if (i + 1 < decls.len) {
679 // try renderExpression(ais, tree, node, Space.None);
680
681 // const comma_token = tree.nextToken(node.lastToken());
682 // assert(tree.token_tags[comma_token] == .Comma);
683 // try renderToken(ais, tree, comma_token, Space.Space); // ,
684 // try renderExtraNewline(ais, tree, decls[i + 1]);
685 // } else {
686 // try renderExpression(ais, tree, node, Space.Space);
687 // }
688 // }
689
690 // return renderToken(ais, tree, err_set_decl.rbrace_token, space); // rbrace
691 // }
692 //},
693617
694618 .BuiltinCallTwo, .BuiltinCallTwoComma => {
695619 if (datas[node].lhs == 0) {
......@@ -732,92 +656,38 @@ fn renderExpression(ais: *Ais, tree: ast.Tree, node: ast.Node.Index, space: Spac
732656 // }
733657 //},
734658
735 .Switch => unreachable, // TODO
736 //.Switch => {
737 // const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
738
739 // try renderToken(ais, tree, switch_node.switch_token, Space.Space); // switch
740 // try renderToken(ais, tree, tree.nextToken(switch_node.switch_token), Space.None); // (
741
742 // const rparen = tree.nextToken(switch_node.expr.lastToken());
743 // const lbrace = tree.nextToken(rparen);
744
745 // if (switch_node.cases_len == 0) {
746 // try renderExpression(ais, tree, switch_node.expr, Space.None);
747 // try renderToken(ais, tree, rparen, Space.Space); // )
748 // try renderToken(ais, tree, lbrace, Space.None); // lbrace
749 // return renderToken(ais, tree, switch_node.rbrace, space); // rbrace
750 // }
751
752 // try renderExpression(ais, tree, switch_node.expr, Space.None);
753 // try renderToken(ais, tree, rparen, Space.Space); // )
754
755 // {
756 // ais.pushIndentNextLine();
757 // defer ais.popIndent();
758 // try renderToken(ais, tree, lbrace, Space.Newline); // lbrace
759
760 // const cases = switch_node.cases();
761 // for (cases) |node, i| {
762 // try renderExpression(ais, tree, node, Space.Comma);
763
764 // if (i + 1 < cases.len) {
765 // try renderExtraNewline(ais, tree, cases[i + 1]);
766 // }
767 // }
768 // }
769
770 // return renderToken(ais, tree, switch_node.rbrace, space); // rbrace
771 //},
772
773 .SwitchCaseOne => unreachable, // TODO
774 .SwitchCaseMulti => unreachable, // TODO
775 //.SwitchCase => {
776 // const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
777
778 // assert(switch_case.items_len != 0);
779 // const src_has_trailing_comma = blk: {
780 // const last_node = switch_case.items()[switch_case.items_len - 1];
781 // const maybe_comma = tree.nextToken(last_node.lastToken());
782 // break :blk tree.token_tags[maybe_comma] == .Comma;
783 // };
784
785 // if (switch_case.items_len == 1 or !src_has_trailing_comma) {
786 // const items = switch_case.items();
787 // for (items) |node, i| {
788 // if (i + 1 < items.len) {
789 // try renderExpression(ais, tree, node, Space.None);
790
791 // const comma_token = tree.nextToken(node.lastToken());
792 // try renderToken(ais, tree, comma_token, Space.Space); // ,
793 // try renderExtraNewline(ais, tree, items[i + 1]);
794 // } else {
795 // try renderExpression(ais, tree, node, Space.Space);
796 // }
797 // }
798 // } else {
799 // const items = switch_case.items();
800 // for (items) |node, i| {
801 // if (i + 1 < items.len) {
802 // try renderExpression(ais, tree, node, Space.None);
803
804 // const comma_token = tree.nextToken(node.lastToken());
805 // try renderToken(ais, tree, comma_token, Space.Newline); // ,
806 // try renderExtraNewline(ais, tree, items[i + 1]);
807 // } else {
808 // try renderExpression(ais, tree, node, Space.Comma);
809 // }
810 // }
811 // }
812
813 // try renderToken(ais, tree, switch_case.arrow_token, Space.Space); // =>
814
815 // if (switch_case.payload) |payload| {
816 // try renderExpression(ais, tree, payload, Space.Space);
817 // }
659 .Switch,
660 .SwitchComma,
661 => {
662 const switch_token = main_tokens[node];
663 const condition = datas[node].lhs;
664 const extra = tree.extraData(datas[node].rhs, ast.Node.SubRange);
665 const cases = tree.extra_data[extra.start..extra.end];
666 const rparen = tree.lastToken(condition) + 1;
667
668 try renderToken(ais, tree, switch_token, .Space); // switch keyword
669 try renderToken(ais, tree, switch_token + 1, .None); // lparen
670 try renderExpression(ais, tree, condition, .None); // condtion expression
671 try renderToken(ais, tree, rparen, .Space); // rparen
672
673 if (cases.len == 0) {
674 try renderToken(ais, tree, rparen + 1, .None); // lbrace
675 try renderToken(ais, tree, rparen + 2, space); // rbrace
676 } else {
677 try renderToken(ais, tree, rparen + 1, .Newline); // lbrace
678 ais.pushIndent();
679 try renderExpression(ais, tree, cases[0], .Comma);
680 for (cases[1..]) |case| {
681 try renderExtraNewline(ais, tree, case);
682 try renderExpression(ais, tree, case, .Comma);
683 }
684 ais.popIndent();
685 try renderToken(ais, tree, tree.lastToken(node), space); // rbrace
686 }
687 },
818688
819 // return renderExpression(ais, tree, switch_case.expr, space);
820 //},
689 .SwitchCaseOne => try renderSwitchCase(ais, tree, tree.switchCaseOne(node), space),
690 .SwitchCase => try renderSwitchCase(ais, tree, tree.switchCase(node), space),
821691
822692 .WhileSimple => unreachable, // TODO
823693 .WhileCont => unreachable, // TODO
......@@ -1745,16 +1615,64 @@ fn renderFnProto(ais: *Ais, tree: ast.Tree, fn_proto: ast.Full.FnProto, space: S
17451615 return renderExpression(ais, tree, fn_proto.ast.return_type, space);
17461616}
17471617
1618fn renderSwitchCase(
1619 ais: *Ais,
1620 tree: ast.Tree,
1621 switch_case: ast.Full.SwitchCase,
1622 space: Space,
1623) Error!void {
1624 const token_tags = tree.tokens.items(.tag);
1625 const trailing_comma = token_tags[switch_case.ast.arrow_token - 1] == .Comma;
1626
1627 // Render everything before the arrow
1628 if (switch_case.ast.values.len == 0) {
1629 try renderToken(ais, tree, switch_case.ast.arrow_token - 1, .Space); // else keyword
1630 } else if (switch_case.ast.values.len == 1) {
1631 // render on one line and drop the trailing comma if any
1632 try renderExpression(ais, tree, switch_case.ast.values[0], .Space);
1633 } else if (trailing_comma) {
1634 // Render each value on a new line
1635 try renderExpression(ais, tree, switch_case.ast.values[0], .Comma);
1636 for (switch_case.ast.values[1..]) |value_expr| {
1637 try renderExtraNewline(ais, tree, value_expr);
1638 try renderExpression(ais, tree, value_expr, .Comma);
1639 }
1640 } else {
1641 // Render on one line
1642 for (switch_case.ast.values) |value_expr| {
1643 try renderExpression(ais, tree, value_expr, .CommaSpace);
1644 }
1645 }
1646
1647 // Render the arrow and everything after it
1648 try renderToken(ais, tree, switch_case.ast.arrow_token, .Space);
1649
1650 if (switch_case.payload_token) |payload_token| {
1651 try renderToken(ais, tree, payload_token - 1, .None); // pipe
1652 if (token_tags[payload_token] == .Asterisk) {
1653 try renderToken(ais, tree, payload_token, .None); // asterisk
1654 try renderToken(ais, tree, payload_token + 1, .None); // identifier
1655 try renderToken(ais, tree, payload_token + 2, .Space); // pipe
1656 } else {
1657 try renderToken(ais, tree, payload_token, .None); // identifier
1658 try renderToken(ais, tree, payload_token + 1, .Space); // pipe
1659 }
1660 }
1661
1662 try renderExpression(ais, tree, switch_case.ast.target_expr, space);
1663}
1664
17481665fn renderBlock(
17491666 ais: *Ais,
17501667 tree: ast.Tree,
1751 lbrace: ast.TokenIndex,
1668 block_node: ast.Node.Index,
17521669 statements: []const ast.Node.Index,
17531670 space: Space,
17541671) Error!void {
17551672 const token_tags = tree.tokens.items(.tag);
17561673 const node_tags = tree.nodes.items(.tag);
17571674 const nodes_data = tree.nodes.items(.data);
1675 const lbrace = tree.nodes.items(.main_token)[block_node];
17581676
17591677 if (token_tags[lbrace - 1] == .Colon and
17601678 token_tags[lbrace - 2] == .Identifier)
......@@ -1783,15 +1701,8 @@ fn renderBlock(
17831701 }
17841702 }
17851703 ais.popIndent();
1786 // The rbrace could be +1 or +2 from the last token of the last
1787 // statement in the block because lastToken() does not count semicolons.
1788 const maybe_rbrace = tree.lastToken(statements[statements.len - 1]) + 1;
1789 if (token_tags[maybe_rbrace] == .RBrace) {
1790 return renderToken(ais, tree, maybe_rbrace, space);
1791 } else {
1792 assert(token_tags[maybe_rbrace + 1] == .RBrace);
1793 return renderToken(ais, tree, maybe_rbrace + 1, space);
1794 }
1704
1705 try renderToken(ais, tree, tree.lastToken(block_node), space); // rbrace
17951706}
17961707
17971708// TODO: handle comments between fields