authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-20 21:59:20-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-24 00:35:53-04:00
logb132a17a749c27040c7fed43b268c2f0d9a401ce
tree0f52e69442e0e23d3d11edcb1730e10a4e41e915
parent4f4afe186d854fb81aca7db4862c366271f24d06

std.zig.parse ignores comments

std.zig.render handles comments by looking at nearby tokens

5 files changed, 899 insertions(+), 701 deletions(-)

README.md+3
......@@ -182,6 +182,9 @@ binary.
182182
183183This is the actual compiler binary that we will install to the system.
184184
185*Note: Stage 2 compiler is not yet able to build Stage 3. Building Stage 3 is
186not yet supported.*
187
185188#### Debug / Development Build
186189
187190```
std/zig/ast.zig+37-44
......@@ -71,6 +71,24 @@ pub const Tree = struct {
7171 pub fn dump(self: &Tree) void {
7272 self.root_node.base.dump(0);
7373 }
74
75 /// Skips over comments
76 pub fn prevToken(self: &Tree, token_index: TokenIndex) TokenIndex {
77 var index = token_index - 1;
78 while (self.tokens.at(index).id == Token.Id.LineComment) {
79 index -= 1;
80 }
81 return index;
82 }
83
84 /// Skips over comments
85 pub fn nextToken(self: &Tree, token_index: TokenIndex) TokenIndex {
86 var index = token_index + 1;
87 while (self.tokens.at(index).id == Token.Id.LineComment) {
88 index += 1;
89 }
90 return index;
91 }
7492};
7593
7694pub const Error = union(enum) {
......@@ -272,7 +290,6 @@ pub const Node = struct {
272290 Block,
273291
274292 // Misc
275 LineComment,
276293 DocComment,
277294 SwitchCase,
278295 SwitchElse,
......@@ -359,7 +376,6 @@ pub const Node = struct {
359376 Id.SwitchElse,
360377 Id.FieldInitializer,
361378 Id.DocComment,
362 Id.LineComment,
363379 Id.TestDecl => return false,
364380 Id.While => {
365381 const while_node = @fieldParentPtr(While, "base", n);
......@@ -506,6 +522,7 @@ pub const Node = struct {
506522 base: Node,
507523 doc_comments: ?&DocComment,
508524 visib_token: ?TokenIndex,
525 use_token: TokenIndex,
509526 expr: &Node,
510527 semicolon_token: TokenIndex,
511528
......@@ -520,7 +537,7 @@ pub const Node = struct {
520537
521538 pub fn firstToken(self: &Use) TokenIndex {
522539 if (self.visib_token) |visib_token| return visib_token;
523 return self.expr.firstToken();
540 return self.use_token;
524541 }
525542
526543 pub fn lastToken(self: &Use) TokenIndex {
......@@ -556,27 +573,15 @@ pub const Node = struct {
556573
557574 pub const ContainerDecl = struct {
558575 base: Node,
559 ltoken: TokenIndex,
560 layout: Layout,
561 kind: Kind,
576 layout_token: ?TokenIndex,
577 kind_token: TokenIndex,
562578 init_arg_expr: InitArg,
563579 fields_and_decls: DeclList,
580 lbrace_token: TokenIndex,
564581 rbrace_token: TokenIndex,
565582
566583 pub const DeclList = Root.DeclList;
567584
568 const Layout = enum {
569 Auto,
570 Extern,
571 Packed,
572 };
573
574 const Kind = enum {
575 Struct,
576 Enum,
577 Union,
578 };
579
580585 const InitArg = union(enum) {
581586 None,
582587 Enum: ?&Node,
......@@ -602,7 +607,10 @@ pub const Node = struct {
602607 }
603608
604609 pub fn firstToken(self: &ContainerDecl) TokenIndex {
605 return self.ltoken;
610 if (self.layout_token) |layout_token| {
611 return layout_token;
612 }
613 return self.kind_token;
606614 }
607615
608616 pub fn lastToken(self: &ContainerDecl) TokenIndex {
......@@ -1113,7 +1121,7 @@ pub const Node = struct {
11131121 switch_token: TokenIndex,
11141122 expr: &Node,
11151123
1116 /// these can be SwitchCase nodes or LineComment nodes
1124 /// these must be SwitchCase nodes
11171125 cases: CaseList,
11181126 rbrace: TokenIndex,
11191127
......@@ -1143,6 +1151,7 @@ pub const Node = struct {
11431151 pub const SwitchCase = struct {
11441152 base: Node,
11451153 items: ItemList,
1154 arrow_token: TokenIndex,
11461155 payload: ?&Node,
11471156 expr: &Node,
11481157
......@@ -1963,9 +1972,11 @@ pub const Node = struct {
19631972
19641973 pub const AsmOutput = struct {
19651974 base: Node,
1975 lbracket: TokenIndex,
19661976 symbolic_name: &Node,
19671977 constraint: &Node,
19681978 kind: Kind,
1979 rparen: TokenIndex,
19691980
19701981 const Kind = union(enum) {
19711982 Variable: &Identifier,
......@@ -1996,22 +2007,21 @@ pub const Node = struct {
19962007 }
19972008
19982009 pub fn firstToken(self: &AsmOutput) TokenIndex {
1999 return self.symbolic_name.firstToken();
2010 return self.lbracket;
20002011 }
20012012
20022013 pub fn lastToken(self: &AsmOutput) TokenIndex {
2003 return switch (self.kind) {
2004 Kind.Variable => |variable_name| variable_name.lastToken(),
2005 Kind.Return => |return_type| return_type.lastToken(),
2006 };
2014 return self.rparen;
20072015 }
20082016 };
20092017
20102018 pub const AsmInput = struct {
20112019 base: Node,
2020 lbracket: TokenIndex,
20122021 symbolic_name: &Node,
20132022 constraint: &Node,
20142023 expr: &Node,
2024 rparen: TokenIndex,
20152025
20162026 pub fn iterate(self: &AsmInput, index: usize) ?&Node {
20172027 var i = index;
......@@ -2029,11 +2039,11 @@ pub const Node = struct {
20292039 }
20302040
20312041 pub fn firstToken(self: &AsmInput) TokenIndex {
2032 return self.symbolic_name.firstToken();
2042 return self.lbracket;
20332043 }
20342044
20352045 pub fn lastToken(self: &AsmInput) TokenIndex {
2036 return self.expr.lastToken();
2046 return self.rparen;
20372047 }
20382048 };
20392049
......@@ -2126,23 +2136,6 @@ pub const Node = struct {
21262136 }
21272137 };
21282138
2129 pub const LineComment = struct {
2130 base: Node,
2131 token: TokenIndex,
2132
2133 pub fn iterate(self: &LineComment, index: usize) ?&Node {
2134 return null;
2135 }
2136
2137 pub fn firstToken(self: &LineComment) TokenIndex {
2138 return self.token;
2139 }
2140
2141 pub fn lastToken(self: &LineComment) TokenIndex {
2142 return self.token;
2143 }
2144 };
2145
21462139 pub const DocComment = struct {
21472140 base: Node,
21482141 lines: LineList,
std/zig/parse.zig+111-144
......@@ -49,10 +49,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
4949
5050 switch (state) {
5151 State.TopLevel => {
52 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
53 try root_node.decls.push(&line_comment.base);
54 }
55
5652 const comments = try eatDocComments(arena, &tok_it, &tree);
5753
5854 const token = nextToken(&tok_it, &tree);
......@@ -80,7 +76,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
8076 try stack.append(State{ .Block = block });
8177 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
8278 .id = Token.Id.LBrace,
83 .ptr = &block.rbrace,
79 .ptr = &block.lbrace,
8480 } });
8581 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &test_node.name } });
8682 continue;
......@@ -121,12 +117,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
121117 try stack.append(State{ .Block = block });
122118 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
123119 .id = Token.Id.LBrace,
124 .ptr = &block.rbrace,
120 .ptr = &block.lbrace,
125121 } });
126122 continue;
127123 },
128124 else => {
129 putBackToken(&tok_it, &tree);
125 prevToken(&tok_it, &tree);
130126 stack.append(State.TopLevel) catch unreachable;
131127 try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{
132128 .decls = &root_node.decls,
......@@ -172,7 +168,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
172168 continue;
173169 },
174170 else => {
175 putBackToken(&tok_it, &tree);
171 prevToken(&tok_it, &tree);
176172 stack.append(State{ .TopLevelDecl = ctx }) catch unreachable;
177173 continue;
178174 },
......@@ -184,7 +180,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
184180 const lib_name_token_index = lib_name_token.index;
185181 const lib_name_token_ptr = lib_name_token.ptr;
186182 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) ?? {
187 putBackToken(&tok_it, &tree);
183 prevToken(&tok_it, &tree);
188184 break :blk null;
189185 };
190186 };
......@@ -211,6 +207,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
211207
212208 const node = try arena.construct(ast.Node.Use{
213209 .base = ast.Node{ .id = ast.Node.Id.Use },
210 .use_token = token_index,
214211 .visib_token = ctx.visib_token,
215212 .expr = undefined,
216213 .semicolon_token = undefined,
......@@ -310,7 +307,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
310307 },
311308 State.TopLevelExternOrField => |ctx| {
312309 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| {
313 std.debug.assert(ctx.container_decl.kind == ast.Node.ContainerDecl.Kind.Struct);
314310 const node = try arena.construct(ast.Node.StructField{
315311 .base = ast.Node{ .id = ast.Node.Id.StructField },
316312 .doc_comments = ctx.comments,
......@@ -343,7 +339,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
343339 const eq_tok_index = eq_tok.index;
344340 const eq_tok_ptr = eq_tok.ptr;
345341 if (eq_tok_ptr.id != Token.Id.Equal) {
346 putBackToken(&tok_it, &tree);
342 prevToken(&tok_it, &tree);
347343 continue;
348344 }
349345 stack.append(State{ .Expression = ctx }) catch unreachable;
......@@ -356,12 +352,11 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
356352 const token_ptr = token.ptr;
357353 const node = try arena.construct(ast.Node.ContainerDecl{
358354 .base = ast.Node{ .id = ast.Node.Id.ContainerDecl },
359 .ltoken = ctx.ltoken,
360 .layout = ctx.layout,
361 .kind = switch (token_ptr.id) {
362 Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct,
363 Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union,
364 Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum,
355 .layout_token = ctx.layout_token,
356 .kind_token = switch (token_ptr.id) {
357 Token.Id.Keyword_struct,
358 Token.Id.Keyword_union,
359 Token.Id.Keyword_enum => token_index,
365360 else => {
366361 ((try tree.errors.addOne())).* = Error{ .ExpectedAggregateKw = Error.ExpectedAggregateKw{ .token = token_index } };
367362 return tree;
......@@ -369,12 +364,16 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
369364 },
370365 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
371366 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),
367 .lbrace_token = undefined,
372368 .rbrace_token = undefined,
373369 });
374370 ctx.opt_ctx.store(&node.base);
375371
376372 stack.append(State{ .ContainerDecl = node }) catch unreachable;
377 try stack.append(State{ .ExpectToken = Token.Id.LBrace });
373 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
374 .id = Token.Id.LBrace,
375 .ptr = &node.lbrace_token,
376 } });
378377 try stack.append(State{ .ContainerInitArgStart = node });
379378 continue;
380379 },
......@@ -403,11 +402,11 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
403402 try stack.append(State{ .ExpectToken = Token.Id.RParen });
404403 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &container_decl.init_arg_expr.Enum } });
405404 } else {
406 putBackToken(&tok_it, &tree);
405 prevToken(&tok_it, &tree);
407406 }
408407 },
409408 else => {
410 putBackToken(&tok_it, &tree);
409 prevToken(&tok_it, &tree);
411410 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg{ .Type = undefined };
412411 stack.append(State{ .Expression = OptionalCtx{ .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
413412 },
......@@ -416,18 +415,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
416415 },
417416
418417 State.ContainerDecl => |container_decl| {
419 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
420 try container_decl.fields_and_decls.push(&line_comment.base);
421 }
422
423418 const comments = try eatDocComments(arena, &tok_it, &tree);
424419 const token = nextToken(&tok_it, &tree);
425420 const token_index = token.index;
426421 const token_ptr = token.ptr;
427422 switch (token_ptr.id) {
428423 Token.Id.Identifier => {
429 switch (container_decl.kind) {
430 ast.Node.ContainerDecl.Kind.Struct => {
424 switch (tree.tokens.at(container_decl.kind_token).id) {
425 Token.Id.Keyword_struct => {
431426 const node = try arena.construct(ast.Node.StructField{
432427 .base = ast.Node{ .id = ast.Node.Id.StructField },
433428 .doc_comments = comments,
......@@ -443,7 +438,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
443438 try stack.append(State{ .ExpectToken = Token.Id.Colon });
444439 continue;
445440 },
446 ast.Node.ContainerDecl.Kind.Union => {
441 Token.Id.Keyword_union => {
447442 const node = try arena.construct(ast.Node.UnionTag{
448443 .base = ast.Node{ .id = ast.Node.Id.UnionTag },
449444 .name_token = token_index,
......@@ -459,7 +454,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
459454 try stack.append(State{ .IfToken = Token.Id.Colon });
460455 continue;
461456 },
462 ast.Node.ContainerDecl.Kind.Enum => {
457 Token.Id.Keyword_enum => {
463458 const node = try arena.construct(ast.Node.EnumTag{
464459 .base = ast.Node{ .id = ast.Node.Id.EnumTag },
465460 .name_token = token_index,
......@@ -473,11 +468,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
473468 try stack.append(State{ .IfToken = Token.Id.Equal });
474469 continue;
475470 },
471 else => unreachable,
476472 }
477473 },
478474 Token.Id.Keyword_pub => {
479 switch (container_decl.kind) {
480 ast.Node.ContainerDecl.Kind.Struct => {
475 switch (tree.tokens.at(container_decl.kind_token).id) {
476 Token.Id.Keyword_struct => {
481477 try stack.append(State{ .TopLevelExternOrField = TopLevelExternOrFieldCtx{
482478 .visib_token = token_index,
483479 .container_decl = container_decl,
......@@ -518,7 +514,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
518514 continue;
519515 },
520516 else => {
521 putBackToken(&tok_it, &tree);
517 prevToken(&tok_it, &tree);
522518 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
523519 try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{
524520 .decls = &container_decl.fields_and_decls,
......@@ -573,7 +569,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
573569 continue;
574570 }
575571
576 putBackToken(&tok_it, &tree);
572 prevToken(&tok_it, &tree);
577573 continue;
578574 },
579575 State.VarDeclEq => |var_decl| {
......@@ -616,7 +612,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
616612 if (loc.line == 0) {
617613 try pushDocComment(arena, doc_comment_token, &var_decl.doc_comments);
618614 } else {
619 putBackToken(&tok_it, &tree);
615 prevToken(&tok_it, &tree);
620616 }
621617 }
622618 },
......@@ -688,7 +684,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
688684 }
689685 }
690686
691 putBackToken(&tok_it, &tree);
687 prevToken(&tok_it, &tree);
692688 fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = undefined };
693689 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &fn_proto.return_type.Explicit } }) catch unreachable;
694690 continue;
......@@ -733,7 +729,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
733729 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {
734730 param_decl.name_token = ident_token;
735731 } else {
736 putBackToken(&tok_it, &tree);
732 prevToken(&tok_it, &tree);
737733 }
738734 }
739735 continue;
......@@ -838,7 +834,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
838834 return tree;
839835 }
840836
841 putBackToken(&tok_it, &tree);
837 prevToken(&tok_it, &tree);
842838 continue;
843839 },
844840 }
......@@ -872,7 +868,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
872868 return tree;
873869 }
874870
875 putBackToken(&tok_it, &tree);
871 prevToken(&tok_it, &tree);
876872 continue;
877873 },
878874 }
......@@ -927,11 +923,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
927923 continue;
928924 },
929925 State.Else => |dest| {
930 const old_index = tok_it.index;
931 var need_index_restore = false;
932 while (try eatLineComment(arena, &tok_it, &tree)) |_| {
933 need_index_restore = true;
934 }
935926 if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| {
936927 const node = try arena.construct(ast.Node.Else{
937928 .base = ast.Node{ .id = ast.Node.Id.Else },
......@@ -945,9 +936,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
945936 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
946937 continue;
947938 } else {
948 if (need_index_restore) {
949 tok_it.set(old_index);
950 }
951939 continue;
952940 }
953941 },
......@@ -962,16 +950,9 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
962950 continue;
963951 },
964952 else => {
965 putBackToken(&tok_it, &tree);
953 prevToken(&tok_it, &tree);
966954 stack.append(State{ .Block = block }) catch unreachable;
967955
968 var any_comments = false;
969 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
970 try block.statements.push(&line_comment.base);
971 any_comments = true;
972 }
973 if (any_comments) continue;
974
975956 try stack.append(State{ .Statement = block });
976957 continue;
977958 },
......@@ -1035,7 +1016,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
10351016 continue;
10361017 },
10371018 else => {
1038 putBackToken(&tok_it, &tree);
1019 prevToken(&tok_it, &tree);
10391020 const statement = try block.statements.addOne();
10401021 try stack.append(State{ .Semicolon = statement });
10411022 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
......@@ -1062,8 +1043,8 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
10621043 continue;
10631044 },
10641045 else => {
1065 putBackToken(&tok_it, &tree);
1066 putBackToken(&tok_it, &tree);
1046 prevToken(&tok_it, &tree);
1047 prevToken(&tok_it, &tree);
10671048 const statement = try ctx.block.statements.addOne();
10681049 try stack.append(State{ .Semicolon = statement });
10691050 try stack.append(State{ .Expression = OptionalCtx{ .Required = statement } });
......@@ -1085,21 +1066,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
10851066 const lbracket_index = lbracket.index;
10861067 const lbracket_ptr = lbracket.ptr;
10871068 if (lbracket_ptr.id != Token.Id.LBracket) {
1088 putBackToken(&tok_it, &tree);
1069 prevToken(&tok_it, &tree);
10891070 continue;
10901071 }
10911072
10921073 const node = try arena.construct(ast.Node.AsmOutput{
10931074 .base = ast.Node{ .id = ast.Node.Id.AsmOutput },
1075 .lbracket = lbracket_index,
10941076 .symbolic_name = undefined,
10951077 .constraint = undefined,
10961078 .kind = undefined,
1079 .rparen = undefined,
10971080 });
10981081 try items.push(node);
10991082
11001083 stack.append(State{ .AsmOutputItems = items }) catch unreachable;
11011084 try stack.append(State{ .IfToken = Token.Id.Comma });
1102 try stack.append(State{ .ExpectToken = Token.Id.RParen });
1085 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1086 .id = Token.Id.RParen,
1087 .ptr = &node.rparen,
1088 } });
11031089 try stack.append(State{ .AsmOutputReturnOrType = node });
11041090 try stack.append(State{ .ExpectToken = Token.Id.LParen });
11051091 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.constraint } });
......@@ -1132,21 +1118,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
11321118 const lbracket_index = lbracket.index;
11331119 const lbracket_ptr = lbracket.ptr;
11341120 if (lbracket_ptr.id != Token.Id.LBracket) {
1135 putBackToken(&tok_it, &tree);
1121 prevToken(&tok_it, &tree);
11361122 continue;
11371123 }
11381124
11391125 const node = try arena.construct(ast.Node.AsmInput{
11401126 .base = ast.Node{ .id = ast.Node.Id.AsmInput },
1127 .lbracket = lbracket_index,
11411128 .symbolic_name = undefined,
11421129 .constraint = undefined,
11431130 .expr = undefined,
1131 .rparen = undefined,
11441132 });
11451133 try items.push(node);
11461134
11471135 stack.append(State{ .AsmInputItems = items }) catch unreachable;
11481136 try stack.append(State{ .IfToken = Token.Id.Comma });
1149 try stack.append(State{ .ExpectToken = Token.Id.RParen });
1137 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1138 .id = Token.Id.RParen,
1139 .ptr = &node.rparen,
1140 } });
11501141 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
11511142 try stack.append(State{ .ExpectToken = Token.Id.LParen });
11521143 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.constraint } });
......@@ -1187,10 +1178,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
11871178 }
11881179 },
11891180 State.FieldInitListItemOrEnd => |list_state| {
1190 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1191 try list_state.list.push(&line_comment.base);
1192 }
1193
11941181 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
11951182 (list_state.ptr).* = rbrace;
11961183 continue;
......@@ -1248,10 +1235,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
12481235 }
12491236 },
12501237 State.ErrorTagListItemOrEnd => |list_state| {
1251 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1252 try list_state.list.push(&line_comment.base);
1253 }
1254
12551238 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
12561239 (list_state.ptr).* = rbrace;
12571240 continue;
......@@ -1279,10 +1262,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
12791262 }
12801263 },
12811264 State.SwitchCaseOrEnd => |list_state| {
1282 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
1283 try list_state.list.push(&line_comment.base);
1284 }
1285
12861265 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
12871266 (list_state.ptr).* = rbrace;
12881267 continue;
......@@ -1294,12 +1273,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
12941273 .items = ast.Node.SwitchCase.ItemList.init(arena),
12951274 .payload = null,
12961275 .expr = undefined,
1276 .arrow_token = undefined,
12971277 });
12981278 try list_state.list.push(&node.base);
12991279 try stack.append(State{ .SwitchCaseCommaOrEnd = list_state });
13001280 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
13011281 try stack.append(State{ .PointerPayload = OptionalCtx{ .Optional = &node.payload } });
1302 try stack.append(State{ .SwitchCaseFirstItem = &node.items });
1282 try stack.append(State{ .SwitchCaseFirstItem = node });
13031283
13041284 continue;
13051285 },
......@@ -1320,7 +1300,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
13201300 }
13211301 },
13221302
1323 State.SwitchCaseFirstItem => |case_items| {
1303 State.SwitchCaseFirstItem => |switch_case| {
13241304 const token = nextToken(&tok_it, &tree);
13251305 const token_index = token.index;
13261306 const token_ptr = token.ptr;
......@@ -1329,25 +1309,30 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
13291309 .base = ast.Node{ .id = ast.Node.Id.SwitchElse },
13301310 .token = token_index,
13311311 });
1332 try case_items.push(&else_node.base);
1312 try switch_case.items.push(&else_node.base);
13331313
1334 try stack.append(State{ .ExpectToken = Token.Id.EqualAngleBracketRight });
1314 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
1315 .id = Token.Id.EqualAngleBracketRight,
1316 .ptr = &switch_case.arrow_token,
1317 } });
13351318 continue;
13361319 } else {
1337 putBackToken(&tok_it, &tree);
1338 try stack.append(State{ .SwitchCaseItem = case_items });
1320 prevToken(&tok_it, &tree);
1321 try stack.append(State{ .SwitchCaseItem = switch_case });
13391322 continue;
13401323 }
13411324 },
1342 State.SwitchCaseItem => |case_items| {
1343 stack.append(State{ .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;
1344 try stack.append(State{ .RangeExpressionBegin = OptionalCtx{ .Required = try case_items.addOne() } });
1325 State.SwitchCaseItem => |node| {
1326 stack.append(State{ .SwitchCaseItemCommaOrEnd = node }) catch unreachable;
1327 try stack.append(State{ .RangeExpressionBegin = OptionalCtx{ .Required = try node.items.addOne() } });
13451328 },
1346 State.SwitchCaseItemCommaOrEnd => |case_items| {
1329 State.SwitchCaseItemCommaOrEnd => |node| {
13471330 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.EqualAngleBracketRight)) {
1348 ExpectCommaOrEndResult.end_token => |t| {
1349 if (t == null) {
1350 stack.append(State{ .SwitchCaseItem = case_items }) catch unreachable;
1331 ExpectCommaOrEndResult.end_token => |end_token| {
1332 if (end_token) |t| {
1333 node.arrow_token = t;
1334 } else {
1335 stack.append(State{ .SwitchCaseItem = node }) catch unreachable;
13511336 }
13521337 continue;
13531338 },
......@@ -1429,8 +1414,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
14291414
14301415 stack.append(State{ .ContainerKind = ContainerKindCtx{
14311416 .opt_ctx = ctx.opt_ctx,
1432 .ltoken = ctx.extern_token,
1433 .layout = ast.Node.ContainerDecl.Layout.Extern,
1417 .layout_token = ctx.extern_token,
14341418 } }) catch unreachable;
14351419 continue;
14361420 },
......@@ -1518,7 +1502,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
15181502 continue;
15191503 },
15201504 else => {
1521 putBackToken(&tok_it, &tree);
1505 prevToken(&tok_it, &tree);
15221506 continue;
15231507 },
15241508 }
......@@ -1537,7 +1521,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
15371521 return tree;
15381522 }
15391523
1540 putBackToken(&tok_it, &tree);
1524 prevToken(&tok_it, &tree);
15411525 continue;
15421526 }
15431527
......@@ -1569,7 +1553,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
15691553 return tree;
15701554 }
15711555
1572 putBackToken(&tok_it, &tree);
1556 prevToken(&tok_it, &tree);
15731557 continue;
15741558 }
15751559
......@@ -1606,7 +1590,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
16061590 return tree;
16071591 }
16081592
1609 putBackToken(&tok_it, &tree);
1593 prevToken(&tok_it, &tree);
16101594 continue;
16111595 }
16121596
......@@ -1691,7 +1675,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
16911675 },
16921676 else => {
16931677 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {
1694 putBackToken(&tok_it, &tree);
1678 prevToken(&tok_it, &tree);
16951679 stack.append(State{ .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
16961680 }
16971681 continue;
......@@ -1744,7 +1728,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
17441728 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } });
17451729 continue;
17461730 } else {
1747 putBackToken(&tok_it, &tree);
1731 prevToken(&tok_it, &tree);
17481732 continue;
17491733 }
17501734 },
......@@ -1779,7 +1763,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
17791763 }
17801764 continue;
17811765 } else {
1782 putBackToken(&tok_it, &tree);
1766 prevToken(&tok_it, &tree);
17831767 continue;
17841768 }
17851769 },
......@@ -1857,7 +1841,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
18571841 try stack.append(State{ .BinaryOrExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
18581842 continue;
18591843 } else {
1860 putBackToken(&tok_it, &tree);
1844 prevToken(&tok_it, &tree);
18611845 continue;
18621846 }
18631847 },
......@@ -1959,7 +1943,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
19591943 try stack.append(State{ .AdditionExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
19601944 continue;
19611945 } else {
1962 putBackToken(&tok_it, &tree);
1946 prevToken(&tok_it, &tree);
19631947 continue;
19641948 }
19651949 },
......@@ -1989,7 +1973,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
19891973 try stack.append(State{ .MultiplyExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
19901974 continue;
19911975 } else {
1992 putBackToken(&tok_it, &tree);
1976 prevToken(&tok_it, &tree);
19931977 continue;
19941978 }
19951979 },
......@@ -2019,7 +2003,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
20192003 try stack.append(State{ .CurlySuffixExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
20202004 continue;
20212005 } else {
2022 putBackToken(&tok_it, &tree);
2006 prevToken(&tok_it, &tree);
20232007 continue;
20242008 }
20252009 },
......@@ -2124,7 +2108,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
21242108 }
21252109 continue;
21262110 } else {
2127 putBackToken(&tok_it, &tree);
2111 prevToken(&tok_it, &tree);
21282112 stack.append(State{ .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
21292113 continue;
21302114 }
......@@ -2220,7 +2204,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
22202204 continue;
22212205 },
22222206 else => {
2223 putBackToken(&tok_it, &tree);
2207 prevToken(&tok_it, &tree);
22242208 continue;
22252209 },
22262210 }
......@@ -2277,7 +2261,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
22772261 const next_token_index = next_token.index;
22782262 const next_token_ptr = next_token.ptr;
22792263 if (next_token_ptr.id != Token.Id.Arrow) {
2280 putBackToken(&tok_it, &tree);
2264 prevToken(&tok_it, &tree);
22812265 continue;
22822266 }
22832267 node.result = ast.Node.PromiseType.Result{
......@@ -2348,8 +2332,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
23482332 Token.Id.Keyword_packed => {
23492333 stack.append(State{ .ContainerKind = ContainerKindCtx{
23502334 .opt_ctx = opt_ctx,
2351 .ltoken = token.index,
2352 .layout = ast.Node.ContainerDecl.Layout.Packed,
2335 .layout_token = token.index,
23532336 } }) catch unreachable;
23542337 continue;
23552338 },
......@@ -2364,11 +2347,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
23642347 Token.Id.Keyword_struct,
23652348 Token.Id.Keyword_union,
23662349 Token.Id.Keyword_enum => {
2367 putBackToken(&tok_it, &tree);
2350 prevToken(&tok_it, &tree);
23682351 stack.append(State{ .ContainerKind = ContainerKindCtx{
23692352 .opt_ctx = opt_ctx,
2370 .ltoken = token.index,
2371 .layout = ast.Node.ContainerDecl.Layout.Auto,
2353 .layout_token = null,
23722354 } }) catch unreachable;
23732355 continue;
23742356 },
......@@ -2466,7 +2448,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
24662448 },
24672449 else => {
24682450 if (!try parseBlockExpr(&stack, arena, opt_ctx, token.ptr, token.index)) {
2469 putBackToken(&tok_it, &tree);
2451 prevToken(&tok_it, &tree);
24702452 if (opt_ctx != OptionalCtx.Optional) {
24712453 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token.index } };
24722454 return tree;
......@@ -2502,7 +2484,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
25022484 const token_index = token.index;
25032485 const token_ptr = token.ptr;
25042486 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) ?? {
2505 putBackToken(&tok_it, &tree);
2487 prevToken(&tok_it, &tree);
25062488 if (opt_ctx != OptionalCtx.Optional) {
25072489 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token_index } };
25082490 return tree;
......@@ -2576,7 +2558,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
25762558 } };
25772559 return tree;
25782560 }
2579 (expect_token_save.ptr).* = token_index;
2561 expect_token_save.ptr.* = token_index;
25802562 continue;
25812563 },
25822564 State.IfToken => |token_id| {
......@@ -2645,8 +2627,7 @@ const ExternTypeCtx = struct {
26452627
26462628const ContainerKindCtx = struct {
26472629 opt_ctx: OptionalCtx,
2648 ltoken: TokenIndex,
2649 layout: ast.Node.ContainerDecl.Layout,
2630 layout_token: ?TokenIndex,
26502631};
26512632
26522633const ExpectTokenSave = struct {
......@@ -2808,9 +2789,9 @@ const State = union(enum) {
28082789 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
28092790 SwitchCaseOrEnd: ListSave(ast.Node.Switch.CaseList),
28102791 SwitchCaseCommaOrEnd: ListSave(ast.Node.Switch.CaseList),
2811 SwitchCaseFirstItem: &ast.Node.SwitchCase.ItemList,
2812 SwitchCaseItem: &ast.Node.SwitchCase.ItemList,
2813 SwitchCaseItemCommaOrEnd: &ast.Node.SwitchCase.ItemList,
2792 SwitchCaseFirstItem: &ast.Node.SwitchCase,
2793 SwitchCaseItem: &ast.Node.SwitchCase,
2794 SwitchCaseItemCommaOrEnd: &ast.Node.SwitchCase,
28142795
28152796 SuspendBody: &ast.Node.Suspend,
28162797 AsyncAllocator: &ast.Node.AsyncAttribute,
......@@ -2899,14 +2880,6 @@ fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, t
28992880 return result;
29002881}
29012882
2902fn eatLineComment(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) !?&ast.Node.LineComment {
2903 const token = eatToken(tok_it, tree, Token.Id.LineComment) ?? return null;
2904 return try arena.construct(ast.Node.LineComment{
2905 .base = ast.Node{ .id = ast.Node.Id.LineComment },
2906 .token = token,
2907 });
2908}
2909
29102883fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, token_ptr: &const Token, token_index: TokenIndex, tree: &ast.Tree) !?&ast.Node {
29112884 switch (token_ptr.id) {
29122885 Token.Id.StringLiteral => {
......@@ -2923,7 +2896,7 @@ fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterato
29232896 const multiline_str_index = multiline_str.index;
29242897 const multiline_str_ptr = multiline_str.ptr;
29252898 if (multiline_str_ptr.id != Token.Id.MultilineStringLiteralLine) {
2926 putBackToken(tok_it, tree);
2899 prevToken(tok_it, tree);
29272900 break;
29282901 }
29292902
......@@ -3176,11 +3149,12 @@ fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, compti
31763149}
31773150
31783151fn eatToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, id: @TagType(Token.Id)) ?TokenIndex {
3179 const token = nextToken(tok_it, tree);
3152 const token = ??tok_it.peek();
31803153
3181 if (token.ptr.id == id) return token.index;
3154 if (token.id == id) {
3155 return nextToken(tok_it, tree).index;
3156 }
31823157
3183 putBackToken(tok_it, tree);
31843158 return null;
31853159}
31863160
......@@ -3189,27 +3163,20 @@ fn nextToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) AnnotatedTok
31893163 .index = tok_it.index,
31903164 .ptr = ??tok_it.next(),
31913165 };
3192 // possibly skip a following same line token
3193 const token = tok_it.next() ?? return result;
3194 if (token.id != Token.Id.LineComment) {
3195 putBackToken(tok_it, tree);
3196 return result;
3197 }
3198 const loc = tree.tokenLocationPtr(result.ptr.end, token);
3199 if (loc.line != 0) {
3200 putBackToken(tok_it, tree);
3166 assert(result.ptr.id != Token.Id.LineComment);
3167
3168 while (true) {
3169 const next_tok = tok_it.peek() ?? return result;
3170 if (next_tok.id != Token.Id.LineComment) return result;
3171 _ = tok_it.next();
32013172 }
3202 return result;
32033173}
32043174
3205fn putBackToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) void {
3206 const prev_tok = ??tok_it.prev();
3207 if (prev_tok.id == Token.Id.LineComment) {
3208 const minus2_tok = tok_it.prev() ?? return;
3209 const loc = tree.tokenLocationPtr(minus2_tok.end, prev_tok);
3210 if (loc.line != 0) {
3211 _ = tok_it.next();
3212 }
3175fn prevToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) void {
3176 while (true) {
3177 const prev_tok = tok_it.prev() ?? return;
3178 if (prev_tok.id == Token.Id.LineComment) continue;
3179 return;
32133180 }
32143181}
32153182
std/zig/parser_test.zig+74-15
......@@ -1,3 +1,64 @@
1test "zig fmt: if-else end of comptime" {
2 try testCanonical(
3 \\comptime {
4 \\ if (a) {
5 \\ b();
6 \\ } else {
7 \\ b();
8 \\ }
9 \\}
10 \\
11 );
12}
13
14test "zig fmt: nested blocks" {
15 try testCanonical(
16 \\comptime {
17 \\ {
18 \\ {
19 \\ {
20 \\ a();
21 \\ }
22 \\ }
23 \\ }
24 \\}
25 \\
26 );
27}
28
29test "zig fmt: block with same line comment after end brace" {
30 try testCanonical(
31 \\comptime {
32 \\ {
33 \\ b();
34 \\ } // comment
35 \\}
36 \\
37 );
38}
39
40test "zig fmt: statements with comment between" {
41 try testCanonical(
42 \\comptime {
43 \\ a = b;
44 \\ // comment
45 \\ a = b;
46 \\}
47 \\
48 );
49}
50
51test "zig fmt: statements with empty line between" {
52 try testCanonical(
53 \\comptime {
54 \\ a = b;
55 \\
56 \\ a = b;
57 \\}
58 \\
59 );
60}
61
162test "zig fmt: ptr deref operator" {
263 try testCanonical(
364 \\const a = b.*;
......@@ -7,6 +68,13 @@ test "zig fmt: ptr deref operator" {
768
869test "zig fmt: comment after if before another if" {
970 try testCanonical(
71 \\test "aoeu" {
72 \\ // comment
73 \\ if (x) {
74 \\ bar();
75 \\ }
76 \\}
77 \\
1078 \\test "aoeu" {
1179 \\ if (x) {
1280 \\ foo();
......@@ -21,7 +89,7 @@ test "zig fmt: comment after if before another if" {
2189}
2290
2391test "zig fmt: line comment between if block and else keyword" {
24 try testTransform(
92 try testCanonical(
2593 \\test "aoeu" {
2694 \\ // cexp(finite|nan +- i inf|nan) = nan + i nan
2795 \\ if ((hx & 0x7fffffff) != 0x7f800000) {
......@@ -37,20 +105,6 @@ test "zig fmt: line comment between if block and else keyword" {
37105 \\ return Complex(f32).new(x, y - y);
38106 \\ }
39107 \\}
40 ,
41 \\test "aoeu" {
42 \\ // cexp(finite|nan +- i inf|nan) = nan + i nan
43 \\ if ((hx & 0x7fffffff) != 0x7f800000) {
44 \\ return Complex(f32).new(y - y, y - y);
45 \\ } // cexp(-inf +- i inf|nan) = 0 + i0
46 \\ else if (hx & 0x80000000 != 0) {
47 \\ return Complex(f32).new(0, 0);
48 \\ } // cexp(+inf +- i inf|nan) = inf + i nan
49 \\ // another comment
50 \\ else {
51 \\ return Complex(f32).new(x, y - y);
52 \\ }
53 \\}
54108 \\
55109 );
56110}
......@@ -652,6 +706,11 @@ test "zig fmt: multiline string" {
652706 \\ c\\two)
653707 \\ c\\three
654708 \\ ;
709 \\ const s3 = // hi
710 \\ \\one
711 \\ \\two)
712 \\ \\three
713 \\ ;
655714 \\}
656715 \\
657716 );
std/zig/render.zig+674-498
......@@ -19,17 +19,21 @@ pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) (@typeOf(
1919 while (it.next()) |decl| {
2020 try renderTopLevelDecl(allocator, stream, tree, 0, decl.*);
2121 if (it.peek()) |next_decl| {
22 const n = if (nodeLineOffset(tree, decl.*, next_decl.*) >= 2) u8(2) else u8(1);
23 try stream.writeByteNTimes('\n', n);
22 try renderExtraNewline(tree, stream, next_decl.*);
2423 }
2524 }
26 try stream.write("\n");
2725}
2826
29fn nodeLineOffset(tree: &ast.Tree, a: &ast.Node, b: &ast.Node) usize {
30 const a_last_token = tree.tokens.at(a.lastToken());
31 const loc = tree.tokenLocation(a_last_token.end, b.firstToken());
32 return loc.line;
27fn renderExtraNewline(tree: &ast.Tree, stream: var, node: &ast.Node) !void {
28 var first_token = node.firstToken();
29 while (tree.tokens.at(first_token - 1).id == Token.Id.DocComment) {
30 first_token -= 1;
31 }
32 const prev_token_end = tree.tokens.at(first_token - 1).end;
33 const loc = tree.tokenLocation(prev_token_end, first_token);
34 if (loc.line >= 2) {
35 try stream.writeByte('\n');
36 }
3337}
3438
3539fn renderTopLevelDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, decl: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
......@@ -37,119 +41,124 @@ fn renderTopLevelDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, i
3741 ast.Node.Id.FnProto => {
3842 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
3943
40 try renderComments(tree, stream, fn_proto, indent);
41 try renderExpression(allocator, stream, tree, indent, decl);
44 try renderDocComments(tree, stream, fn_proto, indent);
4245
4346 if (fn_proto.body_node) |body_node| {
44 try stream.write(" ");
45 try renderExpression(allocator, stream, tree, indent, body_node);
47 try renderExpression(allocator, stream, tree, indent, decl, Space.Space);
48 try renderExpression(allocator, stream, tree, indent, body_node, Space.Newline);
4649 } else {
47 try stream.write(";");
50 try renderExpression(allocator, stream, tree, indent, decl, Space.None);
51 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, Space.Newline);
4852 }
4953 },
54
5055 ast.Node.Id.Use => {
5156 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
5257
5358 if (use_decl.visib_token) |visib_token| {
54 try stream.print("{} ", tree.tokenSlice(visib_token));
59 try renderToken(tree, stream, visib_token, indent, Space.Space); // pub
5560 }
56 try stream.write("use ");
57 try renderExpression(allocator, stream, tree, indent, use_decl.expr);
58 try stream.write(";");
61 try renderToken(tree, stream, use_decl.use_token, indent, Space.Space); // use
62 try renderExpression(allocator, stream, tree, indent, use_decl.expr, Space.None);
63 try renderToken(tree, stream, use_decl.semicolon_token, indent, Space.Newline); // ;
5964 },
65
6066 ast.Node.Id.VarDecl => {
6167 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
6268
63 try renderComments(tree, stream, var_decl, indent);
69 try renderDocComments(tree, stream, var_decl, indent);
6470 try renderVarDecl(allocator, stream, tree, indent, var_decl);
6571 },
72
6673 ast.Node.Id.TestDecl => {
6774 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
6875
69 try renderComments(tree, stream, test_decl, indent);
70 try stream.write("test ");
71 try renderExpression(allocator, stream, tree, indent, test_decl.name);
72 try stream.write(" ");
73 try renderExpression(allocator, stream, tree, indent, test_decl.body_node);
76 try renderDocComments(tree, stream, test_decl, indent);
77 try renderToken(tree, stream, test_decl.test_token, indent, Space.Space);
78 try renderExpression(allocator, stream, tree, indent, test_decl.name, Space.Space);
79 try renderExpression(allocator, stream, tree, indent, test_decl.body_node, Space.Newline);
7480 },
81
7582 ast.Node.Id.StructField => {
7683 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
7784
78 try renderComments(tree, stream, field, indent);
85 try renderDocComments(tree, stream, field, indent);
7986 if (field.visib_token) |visib_token| {
80 try stream.print("{} ", tree.tokenSlice(visib_token));
87 try renderToken(tree, stream, visib_token, indent, Space.Space); // pub
8188 }
82 try stream.print("{}: ", tree.tokenSlice(field.name_token));
83 try renderExpression(allocator, stream, tree, indent, field.type_expr);
84 try renderToken(tree, stream, field.lastToken() + 1, indent, true, true);
89 try renderToken(tree, stream, field.name_token, indent, Space.None); // name
90 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, Space.Space); // :
91 try renderExpression(allocator, stream, tree, indent, field.type_expr, Space.None); // type
92 try renderToken(tree, stream, tree.nextToken(field.lastToken()), indent, Space.Newline); // ,
8593 },
94
8695 ast.Node.Id.UnionTag => {
8796 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
8897
89 try renderComments(tree, stream, tag, indent);
90 try stream.print("{}", tree.tokenSlice(tag.name_token));
98 try renderDocComments(tree, stream, tag, indent);
99
100 const name_space = if (tag.type_expr == null and tag.value_expr != null) Space.Space else Space.None;
101 try renderToken(tree, stream, tag.name_token, indent, name_space); // name
91102
92103 if (tag.type_expr) |type_expr| {
93 try stream.print(": ");
94 try renderExpression(allocator, stream, tree, indent, type_expr);
104 try renderToken(tree, stream, tree.nextToken(tag.name_token), indent, Space.Space); // :
105
106 const after_type_space = if (tag.value_expr == null) Space.None else Space.Space;
107 try renderExpression(allocator, stream, tree, indent, type_expr, after_type_space);
95108 }
96109
97110 if (tag.value_expr) |value_expr| {
98 try stream.print(" = ");
99 try renderExpression(allocator, stream, tree, indent, value_expr);
111 try renderToken(tree, stream, tree.prevToken(value_expr.firstToken()), indent, Space.Space); // =
112 try renderExpression(allocator, stream, tree, indent, value_expr, Space.None);
100113 }
101114
102 try stream.write(",");
115 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, Space.Newline); // ,
103116 },
117
104118 ast.Node.Id.EnumTag => {
105119 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
106120
107 try renderComments(tree, stream, tag, indent);
108 try stream.print("{}", tree.tokenSlice(tag.name_token));
121 try renderDocComments(tree, stream, tag, indent);
122
123 const after_name_space = if (tag.value == null) Space.None else Space.Space;
124 try renderToken(tree, stream, tag.name_token, indent, after_name_space); // name
109125
110126 if (tag.value) |value| {
111 try stream.print(" = ");
112 try renderExpression(allocator, stream, tree, indent, value);
127 try renderToken(tree, stream, tree.nextToken(tag.name_token), indent, Space.Space); // =
128 try renderExpression(allocator, stream, tree, indent, value, Space.None);
113129 }
114130
115 try stream.write(",");
131 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, Space.Newline); // ,
116132 },
117 ast.Node.Id.ErrorTag => {
118 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
119133
120 try renderComments(tree, stream, tag, indent);
121 try stream.print("{}", tree.tokenSlice(tag.name_token));
122 },
123134 ast.Node.Id.Comptime => {
124 try renderExpression(allocator, stream, tree, indent, decl);
125 try maybeRenderSemicolon(stream, tree, indent, decl);
126 },
127 ast.Node.Id.LineComment => {
128 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", decl);
129
130 try stream.write(tree.tokenSlice(line_comment_node.token));
135 assert(!decl.requireSemiColon());
136 try renderExpression(allocator, stream, tree, indent, decl, Space.Newline);
131137 },
132138 else => unreachable,
133139 }
134140}
135141
136fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
142fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node, space: Space) (@typeOf(stream).Child.Error || Error)!void {
137143 switch (base.id) {
138144 ast.Node.Id.Identifier => {
139145 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
140 try stream.print("{}", tree.tokenSlice(identifier.token));
146 try renderToken(tree, stream, identifier.token, indent, space);
141147 },
142148 ast.Node.Id.Block => {
143149 const block = @fieldParentPtr(ast.Node.Block, "base", base);
150
144151 if (block.label) |label| {
145 try stream.print("{}: ", tree.tokenSlice(label));
152 try renderToken(tree, stream, label, indent, Space.None);
153 try renderToken(tree, stream, tree.nextToken(label), indent, Space.Space);
146154 }
147155
148156 if (block.statements.len == 0) {
149 try stream.write("{}");
157 try renderToken(tree, stream, block.lbrace, indent + indent_delta, Space.None);
158 try renderToken(tree, stream, block.rbrace, indent, space);
150159 } else {
151 try stream.write("{\n");
152160 const block_indent = indent + indent_delta;
161 try renderToken(tree, stream, block.lbrace, block_indent, Space.Newline);
153162
154163 var it = block.statements.iterator(0);
155164 while (it.next()) |statement| {
......@@ -157,114 +166,85 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
157166 try renderStatement(allocator, stream, tree, block_indent, statement.*);
158167
159168 if (it.peek()) |next_statement| {
160 const n = if (nodeLineOffset(tree, statement.*, next_statement.*) >= 2) u8(2) else u8(1);
161 try stream.writeByteNTimes('\n', n);
169 try renderExtraNewline(tree, stream, next_statement.*);
162170 }
163171 }
164172
165 try stream.write("\n");
166173 try stream.writeByteNTimes(' ', indent);
167 try stream.write("}");
174 try renderToken(tree, stream, block.rbrace, indent, space);
168175 }
169176 },
170177 ast.Node.Id.Defer => {
171178 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
172 try stream.print("{} ", tree.tokenSlice(defer_node.defer_token));
173 try renderExpression(allocator, stream, tree, indent, defer_node.expr);
179
180 try renderToken(tree, stream, defer_node.defer_token, indent, Space.Space);
181 try renderExpression(allocator, stream, tree, indent, defer_node.expr, space);
174182 },
175183 ast.Node.Id.Comptime => {
176184 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
177 try stream.print("{} ", tree.tokenSlice(comptime_node.comptime_token));
178 try renderExpression(allocator, stream, tree, indent, comptime_node.expr);
185
186 try renderToken(tree, stream, comptime_node.comptime_token, indent, Space.Space);
187 try renderExpression(allocator, stream, tree, indent, comptime_node.expr, space);
179188 },
189
180190 ast.Node.Id.AsyncAttribute => {
181191 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
182 try stream.print("{}", tree.tokenSlice(async_attr.async_token));
183192
184193 if (async_attr.allocator_type) |allocator_type| {
185 try stream.write("<");
186 try renderExpression(allocator, stream, tree, indent, allocator_type);
187 try stream.write(">");
194 try renderToken(tree, stream, async_attr.async_token, indent, Space.None);
195
196 try renderToken(tree, stream, tree.nextToken(async_attr.async_token), indent, Space.None);
197 try renderExpression(allocator, stream, tree, indent, allocator_type, Space.None);
198 try renderToken(tree, stream, tree.nextToken(allocator_type.lastToken()), indent, space);
199 } else {
200 try renderToken(tree, stream, async_attr.async_token, indent, space);
188201 }
189202 },
203
190204 ast.Node.Id.Suspend => {
191205 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
206
192207 if (suspend_node.label) |label| {
193 try stream.print("{}: ", tree.tokenSlice(label));
208 try renderToken(tree, stream, label, indent, Space.None);
209 try renderToken(tree, stream, tree.nextToken(label), indent, Space.Space);
194210 }
195 try stream.print("{}", tree.tokenSlice(suspend_node.suspend_token));
196211
197212 if (suspend_node.payload) |payload| {
198 try stream.write(" ");
199 try renderExpression(allocator, stream, tree, indent, payload);
200 }
201
202 if (suspend_node.body) |body| {
203 try stream.write(" ");
204 try renderExpression(allocator, stream, tree, indent, body);
213 if (suspend_node.body) |body| {
214 try renderToken(tree, stream, suspend_node.suspend_token, indent, Space.Space);
215 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
216 try renderExpression(allocator, stream, tree, indent, body, space);
217 } else {
218 try renderToken(tree, stream, suspend_node.suspend_token, indent, Space.Space);
219 try renderExpression(allocator, stream, tree, indent, payload, space);
220 }
221 } else if (suspend_node.body) |body| {
222 try renderToken(tree, stream, suspend_node.suspend_token, indent, Space.Space);
223 try renderExpression(allocator, stream, tree, indent, body, space);
224 } else {
225 try renderToken(tree, stream, suspend_node.suspend_token, indent, space);
205226 }
206227 },
207228
208229 ast.Node.Id.InfixOp => {
209230 const infix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
210231
211 try renderExpression(allocator, stream, tree, indent, infix_op_node.lhs);
212
213 const text = switch (infix_op_node.op) {
214 ast.Node.InfixOp.Op.Add => " + ",
215 ast.Node.InfixOp.Op.AddWrap => " +% ",
216 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
217 ast.Node.InfixOp.Op.ArrayMult => " ** ",
218 ast.Node.InfixOp.Op.Assign => " = ",
219 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
220 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
221 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
222 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
223 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
224 ast.Node.InfixOp.Op.AssignDiv => " /= ",
225 ast.Node.InfixOp.Op.AssignMinus => " -= ",
226 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
227 ast.Node.InfixOp.Op.AssignMod => " %= ",
228 ast.Node.InfixOp.Op.AssignPlus => " += ",
229 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
230 ast.Node.InfixOp.Op.AssignTimes => " *= ",
231 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
232 ast.Node.InfixOp.Op.BangEqual => " != ",
233 ast.Node.InfixOp.Op.BitAnd => " & ",
234 ast.Node.InfixOp.Op.BitOr => " | ",
235 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
236 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
237 ast.Node.InfixOp.Op.BitXor => " ^ ",
238 ast.Node.InfixOp.Op.BoolAnd => " and ",
239 ast.Node.InfixOp.Op.BoolOr => " or ",
240 ast.Node.InfixOp.Op.Div => " / ",
241 ast.Node.InfixOp.Op.EqualEqual => " == ",
242 ast.Node.InfixOp.Op.ErrorUnion => "!",
243 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
244 ast.Node.InfixOp.Op.GreaterThan => " > ",
245 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
246 ast.Node.InfixOp.Op.LessThan => " < ",
247 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
248 ast.Node.InfixOp.Op.Mod => " % ",
249 ast.Node.InfixOp.Op.Mult => " * ",
250 ast.Node.InfixOp.Op.MultWrap => " *% ",
251 ast.Node.InfixOp.Op.Period => ".",
252 ast.Node.InfixOp.Op.Sub => " - ",
253 ast.Node.InfixOp.Op.SubWrap => " -% ",
254 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
255 ast.Node.InfixOp.Op.Range => " ... ",
256 ast.Node.InfixOp.Op.Catch => |maybe_payload| blk: {
257 try stream.write(" catch ");
258 if (maybe_payload) |payload| {
259 try renderExpression(allocator, stream, tree, indent, payload);
260 try stream.write(" ");
261 }
262 break :blk "";
263 },
232 const op_token = tree.tokens.at(infix_op_node.op_token);
233 const op_space = switch (infix_op_node.op) {
234 ast.Node.InfixOp.Op.Period, ast.Node.InfixOp.Op.ErrorUnion => Space.None,
235 else => Space.Space,
264236 };
237 try renderExpression(allocator, stream, tree, indent, infix_op_node.lhs, op_space);
238 try renderToken(tree, stream, infix_op_node.op_token, indent, op_space);
239
240 switch (infix_op_node.op) {
241 ast.Node.InfixOp.Op.Catch => |maybe_payload| if (maybe_payload) |payload| {
242 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
243 },
244 else => {},
245 }
265246
266 try stream.write(text);
267 try renderExpression(allocator, stream, tree, indent, infix_op_node.rhs);
247 try renderExpression(allocator, stream, tree, indent, infix_op_node.rhs, space);
268248 },
269249
270250 ast.Node.Id.PrefixOp => {
......@@ -272,52 +252,73 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
272252
273253 switch (prefix_op_node.op) {
274254 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
275 try stream.write("&");
255 try renderToken(tree, stream, prefix_op_node.op_token, indent, Space.None); // &
276256 if (addr_of_info.align_expr) |align_expr| {
277 try stream.write("align(");
278 try renderExpression(allocator, stream, tree, indent, align_expr);
279 try stream.write(") ");
257 const align_token = tree.nextToken(prefix_op_node.op_token);
258 try renderToken(tree, stream, align_token, indent, Space.None); // align
259
260 const lparen_token = tree.prevToken(align_expr.firstToken());
261 try renderToken(tree, stream, lparen_token, indent, Space.None); // (
262
263 try renderExpression(allocator, stream, tree, indent, align_expr, Space.None);
264
265 const rparen_token = tree.nextToken(align_expr.lastToken());
266 try renderToken(tree, stream, rparen_token, indent, Space.Space); // )
280267 }
281 if (addr_of_info.const_token != null) {
282 try stream.write("const ");
268 if (addr_of_info.const_token) |const_token| {
269 try renderToken(tree, stream, const_token, indent, Space.Space); // const
283270 }
284 if (addr_of_info.volatile_token != null) {
285 try stream.write("volatile ");
271 if (addr_of_info.volatile_token) |volatile_token| {
272 try renderToken(tree, stream, volatile_token, indent, Space.Space); // volatile
286273 }
287274 },
288275 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
289 try stream.write("[]");
276 try renderToken(tree, stream, prefix_op_node.op_token, indent, Space.None); // [
277 try renderToken(tree, stream, tree.nextToken(prefix_op_node.op_token), indent, Space.None); // ]
278
290279 if (addr_of_info.align_expr) |align_expr| {
291 try stream.print("align(");
292 try renderExpression(allocator, stream, tree, indent, align_expr);
293 try stream.print(") ");
280 const align_token = tree.nextToken(prefix_op_node.op_token);
281 try renderToken(tree, stream, align_token, indent, Space.None); // align
282
283 const lparen_token = tree.prevToken(align_expr.firstToken());
284 try renderToken(tree, stream, lparen_token, indent, Space.None); // (
285
286 try renderExpression(allocator, stream, tree, indent, align_expr, Space.None);
287
288 const rparen_token = tree.nextToken(align_expr.lastToken());
289 try renderToken(tree, stream, rparen_token, indent, Space.Space); // )
294290 }
295 if (addr_of_info.const_token != null) {
296 try stream.print("const ");
291 if (addr_of_info.const_token) |const_token| {
292 try renderToken(tree, stream, const_token, indent, Space.Space);
297293 }
298 if (addr_of_info.volatile_token != null) {
299 try stream.print("volatile ");
294 if (addr_of_info.volatile_token) |volatile_token| {
295 try renderToken(tree, stream, volatile_token, indent, Space.Space);
300296 }
301297 },
302298 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
303 try stream.print("[");
304 try renderExpression(allocator, stream, tree, indent, array_index);
305 try stream.print("]");
299 try renderToken(tree, stream, prefix_op_node.op_token, indent, Space.None); // [
300 try renderExpression(allocator, stream, tree, indent, array_index, Space.None);
301 try renderToken(tree, stream, tree.nextToken(array_index.lastToken()), indent, Space.None); // ]
302 },
303 ast.Node.PrefixOp.Op.BitNot,
304 ast.Node.PrefixOp.Op.BoolNot,
305 ast.Node.PrefixOp.Op.Negation,
306 ast.Node.PrefixOp.Op.NegationWrap,
307 ast.Node.PrefixOp.Op.UnwrapMaybe,
308 ast.Node.PrefixOp.Op.MaybeType,
309 ast.Node.PrefixOp.Op.PointerType => {
310 try renderToken(tree, stream, prefix_op_node.op_token, indent, Space.None);
306311 },
307 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
308 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
309 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
310 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
311 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
312 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
313 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
314 ast.Node.PrefixOp.Op.PointerType => try stream.write("*"),
315 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
316 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
317 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
318 }
319
320 try renderExpression(allocator, stream, tree, indent, prefix_op_node.rhs);
312
313 ast.Node.PrefixOp.Op.Try,
314 ast.Node.PrefixOp.Op.Await,
315 ast.Node.PrefixOp.Op.Cancel,
316 ast.Node.PrefixOp.Op.Resume => {
317 try renderToken(tree, stream, prefix_op_node.op_token, indent, Space.Space);
318 },
319 }
320
321 try renderExpression(allocator, stream, tree, indent, prefix_op_node.rhs, space);
321322 },
322323
323324 ast.Node.Id.SuffixOp => {
......@@ -326,123 +327,139 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
326327 switch (suffix_op.op) {
327328 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
328329 if (call_info.async_attr) |async_attr| {
329 try renderExpression(allocator, stream, tree, indent, &async_attr.base);
330 try stream.write(" ");
330 try renderExpression(allocator, stream, tree, indent, &async_attr.base, Space.Space);
331331 }
332332
333 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
334 try stream.write("(");
333 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
334
335 const lparen = tree.nextToken(suffix_op.lhs.lastToken());
336 try renderToken(tree, stream, lparen, indent, Space.None);
335337
336338 var it = call_info.params.iterator(0);
337339 while (it.next()) |param_node| {
338 try renderExpression(allocator, stream, tree, indent, param_node.*);
340 try renderExpression(allocator, stream, tree, indent, param_node.*, Space.None);
341
339342 if (it.peek() != null) {
340 try stream.write(", ");
343 const comma = tree.nextToken(param_node.*.lastToken());
344 try renderToken(tree, stream, comma, indent, Space.Space);
341345 }
342346 }
343347
344 try stream.write(")");
348 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
345349 },
346350
347351 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
348 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
349 try stream.write("[");
350 try renderExpression(allocator, stream, tree, indent, index_expr);
351 try stream.write("]");
352 const lbracket = tree.prevToken(index_expr.firstToken());
353 const rbracket = tree.nextToken(index_expr.lastToken());
354
355 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
356 try renderToken(tree, stream, lbracket, indent, Space.None); // [
357 try renderExpression(allocator, stream, tree, indent, index_expr, Space.None);
358 try renderToken(tree, stream, rbracket, indent, space); // ]
352359 },
353360
354361 ast.Node.SuffixOp.Op.Deref => {
355 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
356 try stream.write(".*");
362 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
363 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, Space.None); // .
364 try renderToken(tree, stream, suffix_op.rtoken, indent, space); // *
357365 },
358366
359367 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
360 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
361 try stream.write("[");
362 try renderExpression(allocator, stream, tree, indent, range.start);
363 try stream.write("..");
368 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
369
370 const lbracket = tree.prevToken(range.start.firstToken());
371 const dotdot = tree.nextToken(range.start.lastToken());
372
373 try renderToken(tree, stream, lbracket, indent, Space.None); // [
374 try renderExpression(allocator, stream, tree, indent, range.start, Space.None);
375 try renderToken(tree, stream, dotdot, indent, Space.None); // ..
364376 if (range.end) |end| {
365 try renderExpression(allocator, stream, tree, indent, end);
377 try renderExpression(allocator, stream, tree, indent, end, Space.None);
366378 }
367 try stream.write("]");
379 try renderToken(tree, stream, suffix_op.rtoken, indent, space); // ]
368380 },
369381
370382 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
383 const lbrace = tree.nextToken(suffix_op.lhs.lastToken());
384
371385 if (field_inits.len == 0) {
372 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
373 try stream.write("{}");
386 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
387 try renderToken(tree, stream, lbrace, indent, Space.None);
388 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
374389 return;
375390 }
376391
377392 if (field_inits.len == 1) {
378393 const field_init = field_inits.at(0).*;
379394
380 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
381 try stream.write("{ ");
382 try renderExpression(allocator, stream, tree, indent, field_init);
383 try stream.write(" }");
395 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
396 try renderToken(tree, stream, lbrace, indent, Space.Space);
397 try renderExpression(allocator, stream, tree, indent, field_init, Space.Space);
398 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
384399 return;
385400 }
386401
387 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
388 try stream.write("{\n");
402 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
403 try renderToken(tree, stream, lbrace, indent, Space.Newline);
389404
390405 const new_indent = indent + indent_delta;
391406
392407 var it = field_inits.iterator(0);
393408 while (it.next()) |field_init| {
394409 try stream.writeByteNTimes(' ', new_indent);
395 try renderExpression(allocator, stream, tree, new_indent, field_init.*);
396 if ((field_init.*).id != ast.Node.Id.LineComment) {
397 try stream.write(",");
398 }
410 try renderExpression(allocator, stream, tree, new_indent, field_init.*, Space.None);
411
412 const comma = tree.nextToken(field_init.*.lastToken());
413 try renderToken(tree, stream, comma, new_indent, Space.Newline);
414
399415 if (it.peek()) |next_field_init| {
400 const n = if (nodeLineOffset(tree, field_init.*, next_field_init.*) >= 2) u8(2) else u8(1);
401 try stream.writeByteNTimes('\n', n);
416 try renderExtraNewline(tree, stream, next_field_init.*);
402417 }
403418 }
404419
405 try stream.write("\n");
406420 try stream.writeByteNTimes(' ', indent);
407 try stream.write("}");
421 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
408422 },
409423
410424 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
425 const lbrace = tree.nextToken(suffix_op.lhs.lastToken());
426
411427 if (exprs.len == 0) {
412 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
413 try stream.write("{}");
428 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
429 try renderToken(tree, stream, lbrace, indent, Space.None);
430 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
414431 return;
415432 }
416433 if (exprs.len == 1) {
417434 const expr = exprs.at(0).*;
418435
419 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
420 try stream.write("{");
421 try renderExpression(allocator, stream, tree, indent, expr);
422 try stream.write("}");
436 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
437 try renderToken(tree, stream, lbrace, indent, Space.None);
438 try renderExpression(allocator, stream, tree, indent, expr, Space.None);
439 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
423440 return;
424441 }
425442
426 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
443 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
427444
428445 const new_indent = indent + indent_delta;
429 try stream.write("{\n");
446 try renderToken(tree, stream, lbrace, new_indent, Space.Newline);
430447
431448 var it = exprs.iterator(0);
432449 while (it.next()) |expr| {
433450 try stream.writeByteNTimes(' ', new_indent);
434 try renderExpression(allocator, stream, tree, new_indent, expr.*);
435 try stream.write(",");
451 try renderExpression(allocator, stream, tree, new_indent, expr.*, Space.None);
452
453 const comma = tree.nextToken(expr.*.lastToken());
454 try renderToken(tree, stream, comma, new_indent, Space.Newline); // ,
436455
437456 if (it.peek()) |next_expr| {
438 const n = if (nodeLineOffset(tree, expr.*, next_expr.*) >= 2) u8(2) else u8(1);
439 try stream.writeByteNTimes('\n', n);
457 try renderExtraNewline(tree, stream, next_expr.*);
440458 }
441459 }
442460
443 try stream.write("\n");
444461 try stream.writeByteNTimes(' ', indent);
445 try stream.write("}");
462 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
446463 },
447464 }
448465 },
......@@ -452,159 +469,182 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
452469
453470 switch (flow_expr.kind) {
454471 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
455 try stream.print("break");
472 const kw_space = if (maybe_label != null or flow_expr.rhs != null) Space.Space else space;
473 try renderToken(tree, stream, flow_expr.ltoken, indent, kw_space);
456474 if (maybe_label) |label| {
457 try stream.print(" :");
458 try renderExpression(allocator, stream, tree, indent, label);
475 const colon = tree.nextToken(flow_expr.ltoken);
476 try renderToken(tree, stream, colon, indent, Space.None);
477
478 const expr_space = if (flow_expr.rhs != null) Space.Space else space;
479 try renderExpression(allocator, stream, tree, indent, label, expr_space);
459480 }
460481 },
461482 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
462 try stream.print("continue");
483 const kw_space = if (maybe_label != null or flow_expr.rhs != null) Space.Space else space;
484 try renderToken(tree, stream, flow_expr.ltoken, indent, kw_space);
463485 if (maybe_label) |label| {
464 try stream.print(" :");
465 try renderExpression(allocator, stream, tree, indent, label);
486 const colon = tree.nextToken(flow_expr.ltoken);
487 try renderToken(tree, stream, colon, indent, Space.None);
488
489 const expr_space = if (flow_expr.rhs != null) Space.Space else space;
490 try renderExpression(allocator, stream, tree, indent, label, space);
466491 }
467492 },
468493 ast.Node.ControlFlowExpression.Kind.Return => {
469 try stream.print("return");
494 const kw_space = if (flow_expr.rhs != null) Space.Space else space;
495 try renderToken(tree, stream, flow_expr.ltoken, indent, kw_space);
470496 },
471497 }
472498
473499 if (flow_expr.rhs) |rhs| {
474 try stream.write(" ");
475 try renderExpression(allocator, stream, tree, indent, rhs);
500 try renderExpression(allocator, stream, tree, indent, rhs, space);
476501 }
477502 },
478503
479504 ast.Node.Id.Payload => {
480505 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
481506
482 try stream.write("|");
483 try renderExpression(allocator, stream, tree, indent, payload.error_symbol);
484 try stream.write("|");
507 try renderToken(tree, stream, payload.lpipe, indent, Space.None);
508 try renderExpression(allocator, stream, tree, indent, payload.error_symbol, Space.None);
509 try renderToken(tree, stream, payload.rpipe, indent, space);
485510 },
486511
487512 ast.Node.Id.PointerPayload => {
488513 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
489514
490 try stream.write("|");
515 try renderToken(tree, stream, payload.lpipe, indent, Space.None);
491516 if (payload.ptr_token) |ptr_token| {
492 try stream.write(tree.tokenSlice(ptr_token));
517 try renderToken(tree, stream, ptr_token, indent, Space.None);
493518 }
494 try renderExpression(allocator, stream, tree, indent, payload.value_symbol);
495 try stream.write("|");
519 try renderExpression(allocator, stream, tree, indent, payload.value_symbol, Space.None);
520 try renderToken(tree, stream, payload.rpipe, indent, space);
496521 },
497522
498523 ast.Node.Id.PointerIndexPayload => {
499524 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
500525
501 try stream.write("|");
526 try renderToken(tree, stream, payload.lpipe, indent, Space.None);
502527 if (payload.ptr_token) |ptr_token| {
503 try stream.write(tree.tokenSlice(ptr_token));
528 try renderToken(tree, stream, ptr_token, indent, Space.None);
504529 }
505 try renderExpression(allocator, stream, tree, indent, payload.value_symbol);
530 try renderExpression(allocator, stream, tree, indent, payload.value_symbol, Space.None);
506531
507532 if (payload.index_symbol) |index_symbol| {
508 try stream.write(", ");
509 try renderExpression(allocator, stream, tree, indent, index_symbol);
533 const comma = tree.nextToken(payload.value_symbol.lastToken());
534
535 try renderToken(tree, stream, comma, indent, Space.Space);
536 try renderExpression(allocator, stream, tree, indent, index_symbol, Space.None);
510537 }
511538
512 try stream.write("|");
539 try renderToken(tree, stream, payload.rpipe, indent, space);
513540 },
514541
515542 ast.Node.Id.GroupedExpression => {
516543 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
517544
518 try renderToken(tree, stream, grouped_expr.lparen, indent, false, false);
519 try renderExpression(allocator, stream, tree, indent, grouped_expr.expr);
520 try renderToken(tree, stream, grouped_expr.rparen, indent, false, false);
545 try renderToken(tree, stream, grouped_expr.lparen, indent, Space.None);
546 try renderExpression(allocator, stream, tree, indent, grouped_expr.expr, Space.None);
547 try renderToken(tree, stream, grouped_expr.rparen, indent, space);
521548 },
522549
523550 ast.Node.Id.FieldInitializer => {
524551 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
525552
526 try stream.print(".{} = ", tree.tokenSlice(field_init.name_token));
527 try renderExpression(allocator, stream, tree, indent, field_init.expr);
553 try renderToken(tree, stream, field_init.period_token, indent, Space.None); // .
554 try renderToken(tree, stream, field_init.name_token, indent, Space.Space); // name
555 try renderToken(tree, stream, tree.nextToken(field_init.name_token), indent, Space.Space); // =
556 try renderExpression(allocator, stream, tree, indent, field_init.expr, space);
528557 },
529558
530559 ast.Node.Id.IntegerLiteral => {
531560 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
532 try renderToken(tree, stream, integer_literal.token, indent, false, false);
561 try renderToken(tree, stream, integer_literal.token, indent, space);
533562 },
534563 ast.Node.Id.FloatLiteral => {
535564 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
536 try stream.print("{}", tree.tokenSlice(float_literal.token));
565 try renderToken(tree, stream, float_literal.token, indent, space);
537566 },
538567 ast.Node.Id.StringLiteral => {
539568 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
540 try renderToken(tree, stream, string_literal.token, indent, false, false);
569 try renderToken(tree, stream, string_literal.token, indent, space);
541570 },
542571 ast.Node.Id.CharLiteral => {
543572 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
544 try stream.print("{}", tree.tokenSlice(char_literal.token));
573 try renderToken(tree, stream, char_literal.token, indent, space);
545574 },
546575 ast.Node.Id.BoolLiteral => {
547576 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
548 try stream.print("{}", tree.tokenSlice(bool_literal.token));
577 try renderToken(tree, stream, bool_literal.token, indent, space);
549578 },
550579 ast.Node.Id.NullLiteral => {
551580 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
552 try stream.print("{}", tree.tokenSlice(null_literal.token));
581 try renderToken(tree, stream, null_literal.token, indent, space);
553582 },
554583 ast.Node.Id.ThisLiteral => {
555584 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
556 try stream.print("{}", tree.tokenSlice(this_literal.token));
585 try renderToken(tree, stream, this_literal.token, indent, space);
557586 },
558587 ast.Node.Id.Unreachable => {
559588 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
560 try stream.print("{}", tree.tokenSlice(unreachable_node.token));
589 try renderToken(tree, stream, unreachable_node.token, indent, space);
561590 },
562591 ast.Node.Id.ErrorType => {
563592 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
564 try stream.print("{}", tree.tokenSlice(error_type.token));
593 try renderToken(tree, stream, error_type.token, indent, space);
565594 },
566595 ast.Node.Id.VarType => {
567596 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
568 try stream.print("{}", tree.tokenSlice(var_type.token));
597 try renderToken(tree, stream, var_type.token, indent, space);
569598 },
570599 ast.Node.Id.ContainerDecl => {
571600 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
572601
573 switch (container_decl.layout) {
574 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
575 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
576 ast.Node.ContainerDecl.Layout.Auto => {},
577 }
578
579 switch (container_decl.kind) {
580 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
581 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
582 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
602 if (container_decl.layout_token) |layout_token| {
603 try renderToken(tree, stream, layout_token, indent, Space.Space);
583604 }
584605
585606 switch (container_decl.init_arg_expr) {
586 ast.Node.ContainerDecl.InitArg.None => try stream.write(" "),
607 ast.Node.ContainerDecl.InitArg.None => {
608 try renderToken(tree, stream, container_decl.kind_token, indent, Space.Space); // union
609 },
587610 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
611 try renderToken(tree, stream, container_decl.kind_token, indent, Space.None); // union
612
613 const lparen = tree.nextToken(container_decl.kind_token);
614 const enum_token = tree.nextToken(lparen);
615
616 try renderToken(tree, stream, lparen, indent, Space.None); // (
617 try renderToken(tree, stream, enum_token, indent, Space.None); // enum
618
588619 if (enum_tag_type) |expr| {
589 try stream.write("(enum(");
590 try renderExpression(allocator, stream, tree, indent, expr);
591 try stream.write(")) ");
620 try renderToken(tree, stream, tree.nextToken(enum_token), indent, Space.None); // (
621 try renderExpression(allocator, stream, tree, indent, expr, Space.None);
622
623 const rparen = tree.nextToken(expr.lastToken());
624 try renderToken(tree, stream, rparen, indent, Space.None); // )
625 try renderToken(tree, stream, tree.nextToken(rparen), indent, Space.Space); // )
592626 } else {
593 try stream.write("(enum) ");
627 try renderToken(tree, stream, tree.nextToken(enum_token), indent, Space.Space); // )
594628 }
595629 },
596630 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
597 try stream.write("(");
598 try renderExpression(allocator, stream, tree, indent, type_expr);
599 try stream.write(") ");
631 try renderToken(tree, stream, container_decl.kind_token, indent, Space.None); // union
632
633 const lparen = tree.nextToken(container_decl.kind_token);
634 const rparen = tree.nextToken(type_expr.lastToken());
635
636 try renderToken(tree, stream, lparen, indent, Space.None); // (
637 try renderExpression(allocator, stream, tree, indent, type_expr, Space.None);
638 try renderToken(tree, stream, rparen, indent, Space.Space); // )
600639 },
601640 }
602641
603642 if (container_decl.fields_and_decls.len == 0) {
604 try stream.write("{}");
643 try renderToken(tree, stream, container_decl.lbrace_token, indent + indent_delta, Space.None); // {
644 try renderToken(tree, stream, container_decl.rbrace_token, indent, space); // }
605645 } else {
606 try stream.write("{\n");
607646 const new_indent = indent + indent_delta;
647 try renderToken(tree, stream, container_decl.lbrace_token, new_indent, Space.Newline); // {
608648
609649 var it = container_decl.fields_and_decls.iterator(0);
610650 while (it.next()) |decl| {
......@@ -612,22 +652,24 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
612652 try renderTopLevelDecl(allocator, stream, tree, new_indent, decl.*);
613653
614654 if (it.peek()) |next_decl| {
615 const n = if (nodeLineOffset(tree, decl.*, next_decl.*) >= 2) u8(2) else u8(1);
616 try stream.writeByteNTimes('\n', n);
655 try renderExtraNewline(tree, stream, next_decl.*);
617656 }
618657 }
619658
620 try stream.write("\n");
621659 try stream.writeByteNTimes(' ', indent);
622 try stream.write("}");
660 try renderToken(tree, stream, container_decl.rbrace_token, indent, space); // }
623661 }
624662 },
625663
626664 ast.Node.Id.ErrorSetDecl => {
627665 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
628666
667 const lbrace = tree.nextToken(err_set_decl.error_token);
668
629669 if (err_set_decl.decls.len == 0) {
630 try stream.write("error{}");
670 try renderToken(tree, stream, err_set_decl.error_token, indent, Space.None);
671 try renderToken(tree, stream, lbrace, indent, Space.None);
672 try renderToken(tree, stream, err_set_decl.rbrace_token, indent, space);
631673 return;
632674 }
633675
......@@ -642,62 +684,80 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
642684 break :blk;
643685 }
644686
645 try stream.write("error{");
646 try renderTopLevelDecl(allocator, stream, tree, indent, node);
647 try stream.write("}");
687 try renderToken(tree, stream, err_set_decl.error_token, indent, Space.None); // error
688 try renderToken(tree, stream, lbrace, indent, Space.None); // {
689 try renderExpression(allocator, stream, tree, indent, node, Space.None);
690 try renderToken(tree, stream, err_set_decl.rbrace_token, indent, space); // }
648691 return;
649692 }
650693
651 try stream.write("error{\n");
694 try renderToken(tree, stream, err_set_decl.error_token, indent, Space.None); // error
695 try renderToken(tree, stream, lbrace, indent, Space.Newline); // {
652696 const new_indent = indent + indent_delta;
653697
654698 var it = err_set_decl.decls.iterator(0);
655699 while (it.next()) |node| {
656700 try stream.writeByteNTimes(' ', new_indent);
657 try renderTopLevelDecl(allocator, stream, tree, new_indent, node.*);
658 if ((node.*).id != ast.Node.Id.LineComment) {
659 try stream.write(",");
660 }
701 try renderExpression(allocator, stream, tree, new_indent, node.*, Space.None);
702 try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, Space.Newline); // ,
703
661704 if (it.peek()) |next_node| {
662 const n = if (nodeLineOffset(tree, node.*, next_node.*) >= 2) u8(2) else u8(1);
663 try stream.writeByteNTimes('\n', n);
705 try renderExtraNewline(tree, stream, next_node.*);
664706 }
665707 }
666708
667 try stream.write("\n");
668709 try stream.writeByteNTimes(' ', indent);
669 try stream.write("}");
710 try renderToken(tree, stream, err_set_decl.rbrace_token, indent, space); // }
711 },
712
713 ast.Node.Id.ErrorTag => {
714 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", base);
715
716 try renderDocComments(tree, stream, tag, indent);
717 try renderToken(tree, stream, tag.name_token, indent, space); // name
670718 },
671719
672720 ast.Node.Id.MultilineStringLiteral => {
673721 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
674 try stream.print("\n");
722
723 var skip_first_indent = true;
724 if (tree.tokens.at(multiline_str_literal.firstToken() - 1).id != Token.Id.LineComment) {
725 try stream.print("\n");
726 skip_first_indent = false;
727 }
675728
676729 var i: usize = 0;
677730 while (i < multiline_str_literal.lines.len) : (i += 1) {
678731 const t = multiline_str_literal.lines.at(i).*;
679 try stream.writeByteNTimes(' ', indent + indent_delta);
680 try stream.print("{}", tree.tokenSlice(t));
732 if (!skip_first_indent) {
733 try stream.writeByteNTimes(' ', indent + indent_delta);
734 }
735 try renderToken(tree, stream, t, indent, Space.None);
736 skip_first_indent = false;
681737 }
682738 try stream.writeByteNTimes(' ', indent);
683739 },
684740 ast.Node.Id.UndefinedLiteral => {
685741 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
686 try stream.print("{}", tree.tokenSlice(undefined_literal.token));
742 try renderToken(tree, stream, undefined_literal.token, indent, space);
687743 },
688744
689745 ast.Node.Id.BuiltinCall => {
690746 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
691 try stream.print("{}(", tree.tokenSlice(builtin_call.builtin_token));
747
748 try renderToken(tree, stream, builtin_call.builtin_token, indent, Space.None); // @name
749 try renderToken(tree, stream, tree.nextToken(builtin_call.builtin_token), indent, Space.None); // (
692750
693751 var it = builtin_call.params.iterator(0);
694752 while (it.next()) |param_node| {
695 try renderExpression(allocator, stream, tree, indent, param_node.*);
753 try renderExpression(allocator, stream, tree, indent, param_node.*, Space.None);
754
696755 if (it.peek() != null) {
697 try stream.write(", ");
756 const comma_token = tree.nextToken(param_node.*.lastToken());
757 try renderToken(tree, stream, comma_token, indent, Space.Space); // ,
698758 }
699759 }
700 try stream.write(")");
760 try renderToken(tree, stream, builtin_call.rparen_token, indent, space); // )
701761 },
702762
703763 ast.Node.Id.FnProto => {
......@@ -706,108 +766,123 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
706766 if (fn_proto.visib_token) |visib_token_index| {
707767 const visib_token = tree.tokens.at(visib_token_index);
708768 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
709 try stream.print("{} ", tree.tokenSlice(visib_token_index));
769
770 try renderToken(tree, stream, visib_token_index, indent, Space.Space); // pub
710771 }
711772
712773 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
713 try stream.print("{} ", tree.tokenSlice(extern_export_inline_token));
774 try renderToken(tree, stream, extern_export_inline_token, indent, Space.Space); // extern/export
714775 }
715776
716777 if (fn_proto.lib_name) |lib_name| {
717 try renderExpression(allocator, stream, tree, indent, lib_name);
718 try stream.write(" ");
778 try renderExpression(allocator, stream, tree, indent, lib_name, Space.Space);
719779 }
720780
721781 if (fn_proto.cc_token) |cc_token| {
722 try stream.print("{} ", tree.tokenSlice(cc_token));
782 try renderToken(tree, stream, cc_token, indent, Space.Space); // stdcallcc
723783 }
724784
725785 if (fn_proto.async_attr) |async_attr| {
726 try renderExpression(allocator, stream, tree, indent, &async_attr.base);
727 try stream.write(" ");
786 try renderExpression(allocator, stream, tree, indent, &async_attr.base, Space.Space);
728787 }
729788
730 try stream.write("fn");
731
732 if (fn_proto.name_token) |name_token| {
733 try stream.print(" {}", tree.tokenSlice(name_token));
789 if (fn_proto.name_token) |name_token| blk: {
790 try renderToken(tree, stream, fn_proto.fn_token, indent, Space.Space); // fn
791 try renderToken(tree, stream, name_token, indent, Space.None); // name
792 try renderToken(tree, stream, tree.nextToken(name_token), indent, Space.None); // (
793 } else blk: {
794 try renderToken(tree, stream, fn_proto.fn_token, indent, Space.None); // fn
795 try renderToken(tree, stream, tree.nextToken(fn_proto.fn_token), indent, Space.None); // (
734796 }
735797
736 try stream.write("(");
737
738798 var it = fn_proto.params.iterator(0);
739799 while (it.next()) |param_decl_node| {
740800 try renderParamDecl(allocator, stream, tree, indent, param_decl_node.*);
741801
742802 if (it.peek() != null) {
743 try stream.write(", ");
803 const comma = tree.nextToken(param_decl_node.*.lastToken());
804 try renderToken(tree, stream, comma, indent, Space.Space); // ,
744805 }
745806 }
746807
747 try stream.write(") ");
808 const rparen = tree.prevToken(switch (fn_proto.return_type) {
809 ast.Node.FnProto.ReturnType.Explicit => |node| node.firstToken(),
810 ast.Node.FnProto.ReturnType.InferErrorSet => |node| tree.prevToken(node.firstToken()),
811 });
812 try renderToken(tree, stream, rparen, indent, Space.Space); // )
748813
749814 if (fn_proto.align_expr) |align_expr| {
750 try stream.write("align(");
751 try renderExpression(allocator, stream, tree, indent, align_expr);
752 try stream.write(") ");
815 const align_rparen = tree.nextToken(align_expr.lastToken());
816 const align_lparen = tree.prevToken(align_expr.firstToken());
817 const align_kw = tree.prevToken(align_lparen);
818
819 try renderToken(tree, stream, align_kw, indent, Space.None); // align
820 try renderToken(tree, stream, align_lparen, indent, Space.None); // (
821 try renderExpression(allocator, stream, tree, indent, align_expr, Space.None);
822 try renderToken(tree, stream, align_rparen, indent, Space.Space); // )
753823 }
754824
755825 switch (fn_proto.return_type) {
756826 ast.Node.FnProto.ReturnType.Explicit => |node| {
757 try renderExpression(allocator, stream, tree, indent, node);
827 try renderExpression(allocator, stream, tree, indent, node, space);
758828 },
759829 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
760 try stream.write("!");
761 try renderExpression(allocator, stream, tree, indent, node);
830 try renderToken(tree, stream, tree.prevToken(node.firstToken()), indent, Space.None); // !
831 try renderExpression(allocator, stream, tree, indent, node, space);
762832 },
763833 }
764834 },
765835
766836 ast.Node.Id.PromiseType => {
767837 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
768 try stream.write(tree.tokenSlice(promise_type.promise_token));
838
769839 if (promise_type.result) |result| {
770 try stream.write(tree.tokenSlice(result.arrow_token));
771 try renderExpression(allocator, stream, tree, indent, result.return_type);
840 try renderToken(tree, stream, promise_type.promise_token, indent, Space.None); // promise
841 try renderToken(tree, stream, result.arrow_token, indent, Space.None); // ->
842 try renderExpression(allocator, stream, tree, indent, result.return_type, space);
843 } else {
844 try renderToken(tree, stream, promise_type.promise_token, indent, space); // promise
772845 }
773846 },
774847
775 ast.Node.Id.LineComment => {
776 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);
777 try stream.write(tree.tokenSlice(line_comment_node.token));
778 },
779
780848 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
781849
782850 ast.Node.Id.Switch => {
783851 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
784852
785 try stream.print("{} (", tree.tokenSlice(switch_node.switch_token));
853 try renderToken(tree, stream, switch_node.switch_token, indent, Space.Space); // switch
854 try renderToken(tree, stream, tree.nextToken(switch_node.switch_token), indent, Space.None); // (
855
856 const rparen = tree.nextToken(switch_node.expr.lastToken());
857 const lbrace = tree.nextToken(rparen);
858
786859 if (switch_node.cases.len == 0) {
787 try renderExpression(allocator, stream, tree, indent, switch_node.expr);
788 try stream.write(") {}");
860 try renderExpression(allocator, stream, tree, indent, switch_node.expr, Space.None);
861 try renderToken(tree, stream, rparen, indent, Space.Space); // )
862 try renderToken(tree, stream, lbrace, indent, Space.None); // {
863 try renderToken(tree, stream, switch_node.rbrace, indent, space); // }
789864 return;
790865 }
791866
792 try renderExpression(allocator, stream, tree, indent, switch_node.expr);
793 try stream.write(") {\n");
867 try renderExpression(allocator, stream, tree, indent, switch_node.expr, Space.None);
868
869 try renderToken(tree, stream, rparen, indent, Space.Space); // )
870 try renderToken(tree, stream, lbrace, indent, Space.Newline); // {
794871
795872 const new_indent = indent + indent_delta;
796873
797874 var it = switch_node.cases.iterator(0);
798875 while (it.next()) |node| {
799876 try stream.writeByteNTimes(' ', new_indent);
800 try renderExpression(allocator, stream, tree, new_indent, node.*);
877 try renderExpression(allocator, stream, tree, new_indent, node.*, Space.Newline);
801878
802879 if (it.peek()) |next_node| {
803 const n = if (nodeLineOffset(tree, node.*, next_node.*) >= 2) u8(2) else u8(1);
804 try stream.writeByteNTimes('\n', n);
880 try renderExtraNewline(tree, stream, next_node.*);
805881 }
806882 }
807883
808 try stream.write("\n");
809884 try stream.writeByteNTimes(' ', indent);
810 try stream.write("}");
885 try renderToken(tree, stream, switch_node.rbrace, indent, space); // }
811886 },
812887
813888 ast.Node.Id.SwitchCase => {
......@@ -815,54 +890,50 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
815890
816891 var it = switch_case.items.iterator(0);
817892 while (it.next()) |node| {
818 try renderExpression(allocator, stream, tree, indent, node.*);
893 if (it.peek()) |next_node| {
894 try renderExpression(allocator, stream, tree, indent, node.*, Space.None);
819895
820 if (it.peek() != null) {
821 try stream.write(",\n");
896 const comma_token = tree.nextToken(node.*.lastToken());
897 try renderToken(tree, stream, comma_token, indent, Space.Newline); // ,
898 try renderExtraNewline(tree, stream, next_node.*);
822899 try stream.writeByteNTimes(' ', indent);
900 } else {
901 try renderExpression(allocator, stream, tree, indent, node.*, Space.Space);
823902 }
824903 }
825904
826 try stream.write(" => ");
905 try renderToken(tree, stream, switch_case.arrow_token, indent, Space.Space); // =>
827906
828907 if (switch_case.payload) |payload| {
829 try renderExpression(allocator, stream, tree, indent, payload);
830 try stream.write(" ");
908 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
831909 }
832910
833 try renderExpression(allocator, stream, tree, indent, switch_case.expr);
834 {
835 // Handle missing comma after last switch case
836 var index = switch_case.lastToken() + 1;
837 switch (tree.tokens.at(index).id) {
838 Token.Id.RBrace => {
839 try stream.write(",");
840 },
841 Token.Id.LineComment => {
842 try stream.write(", ");
843 try renderToken(tree, stream, index, indent, true, true);
844 },
845 else => try renderToken(tree, stream, index, indent, true, true),
846 }
911 // add a trailing comma if necessary
912 const end_token = switch_case.lastToken() + 1;
913 switch (tree.tokens.at(end_token).id) {
914 Token.Id.Comma => {
915 try renderExpression(allocator, stream, tree, indent, switch_case.expr, Space.None);
916 try renderToken(tree, stream, end_token, indent, space); // ,
917 },
918 Token.Id.LineComment => {
919 try renderExpression(allocator, stream, tree, indent, switch_case.expr, Space.NoComment);
920 try stream.write(", ");
921 try renderToken(tree, stream, end_token, indent, space);
922 },
923 else => {
924 try renderExpression(allocator, stream, tree, indent, switch_case.expr, Space.None);
925 try stream.write(",\n");
926 assert(space == Space.Newline);
927 },
847928 }
848929 },
849930 ast.Node.Id.SwitchElse => {
850931 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
851 try stream.print("{}", tree.tokenSlice(switch_else.token));
932 try renderToken(tree, stream, switch_else.token, indent, space);
852933 },
853934 ast.Node.Id.Else => {
854935 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
855936
856 var prev_tok_index = else_node.else_token - 1;
857 while (tree.tokens.at(prev_tok_index).id == Token.Id.LineComment) : (prev_tok_index -= 1) { }
858 prev_tok_index += 1;
859 while (prev_tok_index < else_node.else_token) : (prev_tok_index += 1) {
860 try stream.print("{}\n", tree.tokenSlice(prev_tok_index));
861 try stream.writeByteNTimes(' ', indent);
862 }
863
864 try stream.print("{}", tree.tokenSlice(else_node.else_token));
865
866937 const block_body = switch (else_node.body.id) {
867938 ast.Node.Id.Block,
868939 ast.Node.Id.If,
......@@ -872,21 +943,19 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
872943 else => false,
873944 };
874945
875 if (block_body) {
876 try stream.write(" ");
877 }
946 const after_else_space = if (block_body or else_node.payload != null) Space.Space else Space.Newline;
947 try renderToken(tree, stream, else_node.else_token, indent, after_else_space);
878948
879949 if (else_node.payload) |payload| {
880 try renderExpression(allocator, stream, tree, indent, payload);
881 try stream.write(" ");
950 const payload_space = if (block_body) Space.Space else Space.Newline;
951 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
882952 }
883953
884954 if (block_body) {
885 try renderExpression(allocator, stream, tree, indent, else_node.body);
955 try renderExpression(allocator, stream, tree, indent, else_node.body, space);
886956 } else {
887 try stream.write("\n");
888957 try stream.writeByteNTimes(' ', indent + indent_delta);
889 try renderExpression(allocator, stream, tree, indent, else_node.body);
958 try renderExpression(allocator, stream, tree, indent, else_node.body, space);
890959 }
891960 },
892961
......@@ -894,103 +963,134 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
894963 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
895964
896965 if (while_node.label) |label| {
897 try stream.print("{}: ", tree.tokenSlice(label));
966 try renderToken(tree, stream, label, indent, Space.None); // label
967 try renderToken(tree, stream, tree.nextToken(label), indent, Space.Space); // :
898968 }
899969
900970 if (while_node.inline_token) |inline_token| {
901 try stream.print("{} ", tree.tokenSlice(inline_token));
971 try renderToken(tree, stream, inline_token, indent, Space.Space); // inline
902972 }
903973
904 try stream.print("{} (", tree.tokenSlice(while_node.while_token));
905 try renderExpression(allocator, stream, tree, indent, while_node.condition);
906 try stream.write(")");
974 try renderToken(tree, stream, while_node.while_token, indent, Space.Space); // while
975 try renderToken(tree, stream, tree.nextToken(while_node.while_token), indent, Space.None); // (
976 try renderExpression(allocator, stream, tree, indent, while_node.condition, Space.None);
977
978 {
979 const rparen = tree.nextToken(while_node.condition.lastToken());
980 const rparen_space = if (while_node.payload != null or while_node.continue_expr != null or
981 while_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
982 try renderToken(tree, stream, rparen, indent, rparen_space); // )
983 }
907984
908985 if (while_node.payload) |payload| {
909 try stream.write(" ");
910 try renderExpression(allocator, stream, tree, indent, payload);
986 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
911987 }
912988
913989 if (while_node.continue_expr) |continue_expr| {
914 try stream.write(" : (");
915 try renderExpression(allocator, stream, tree, indent, continue_expr);
916 try stream.write(")");
990 const rparen = tree.nextToken(continue_expr.lastToken());
991 const lparen = tree.prevToken(continue_expr.firstToken());
992 const colon = tree.prevToken(lparen);
993
994 try renderToken(tree, stream, colon, indent, Space.Space); // :
995 try renderToken(tree, stream, lparen, indent, Space.None); // (
996
997 try renderExpression(allocator, stream, tree, indent, continue_expr, Space.None);
998
999 const rparen_space = if (while_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
1000 try renderToken(tree, stream, rparen, indent, rparen_space); // )
9171001 }
9181002
1003 const body_space = blk: {
1004 if (while_node.@"else" != null) {
1005 break :blk if (while_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
1006 } else {
1007 break :blk space;
1008 }
1009 };
1010
9191011 if (while_node.body.id == ast.Node.Id.Block) {
920 try stream.write(" ");
921 try renderExpression(allocator, stream, tree, indent, while_node.body);
1012 try renderExpression(allocator, stream, tree, indent, while_node.body, body_space);
9221013 } else {
923 try stream.write("\n");
9241014 try stream.writeByteNTimes(' ', indent + indent_delta);
925 try renderExpression(allocator, stream, tree, indent, while_node.body);
1015 try renderExpression(allocator, stream, tree, indent, while_node.body, body_space);
9261016 }
9271017
9281018 if (while_node.@"else") |@"else"| {
9291019 if (while_node.body.id == ast.Node.Id.Block) {
930 try stream.write(" ");
9311020 } else {
932 try stream.write("\n");
9331021 try stream.writeByteNTimes(' ', indent);
9341022 }
9351023
936 try renderExpression(allocator, stream, tree, indent, &@"else".base);
1024 try renderExpression(allocator, stream, tree, indent, &@"else".base, space);
9371025 }
9381026 },
9391027
9401028 ast.Node.Id.For => {
9411029 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
1030
9421031 if (for_node.label) |label| {
943 try stream.print("{}: ", tree.tokenSlice(label));
1032 try renderToken(tree, stream, label, indent, Space.None); // label
1033 try renderToken(tree, stream, tree.nextToken(label), indent, Space.Space); // :
9441034 }
9451035
9461036 if (for_node.inline_token) |inline_token| {
947 try stream.print("{} ", tree.tokenSlice(inline_token));
1037 try renderToken(tree, stream, inline_token, indent, Space.Space); // inline
9481038 }
9491039
950 try stream.print("{} (", tree.tokenSlice(for_node.for_token));
951 try renderExpression(allocator, stream, tree, indent, for_node.array_expr);
952 try stream.write(")");
1040 try renderToken(tree, stream, for_node.for_token, indent, Space.Space); // for
1041 try renderToken(tree, stream, tree.nextToken(for_node.for_token), indent, Space.None); // (
1042 try renderExpression(allocator, stream, tree, indent, for_node.array_expr, Space.None);
1043
1044 const rparen = tree.nextToken(for_node.array_expr.lastToken());
1045 const rparen_space = if (for_node.payload != null or
1046 for_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
1047 try renderToken(tree, stream, rparen, indent, rparen_space); // )
9531048
9541049 if (for_node.payload) |payload| {
955 try stream.write(" ");
956 try renderExpression(allocator, stream, tree, indent, payload);
1050 const payload_space = if (for_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
1051 try renderExpression(allocator, stream, tree, indent, payload, payload_space);
9571052 }
9581053
1054 const body_space = blk: {
1055 if (for_node.@"else" != null) {
1056 if (for_node.body.id == ast.Node.Id.Block) {
1057 break :blk Space.Space;
1058 } else {
1059 break :blk Space.Newline;
1060 }
1061 } else {
1062 break :blk space;
1063 }
1064 };
9591065 if (for_node.body.id == ast.Node.Id.Block) {
960 try stream.write(" ");
961 try renderExpression(allocator, stream, tree, indent, for_node.body);
1066 try renderExpression(allocator, stream, tree, indent, for_node.body, body_space);
9621067 } else {
963 try stream.write("\n");
9641068 try stream.writeByteNTimes(' ', indent + indent_delta);
965 try renderExpression(allocator, stream, tree, indent, for_node.body);
1069 try renderExpression(allocator, stream, tree, indent, for_node.body, body_space);
9661070 }
9671071
9681072 if (for_node.@"else") |@"else"| {
969 if (for_node.body.id == ast.Node.Id.Block) {
970 try stream.write(" ");
971 } else {
972 try stream.write("\n");
1073 if (for_node.body.id != ast.Node.Id.Block) {
9731074 try stream.writeByteNTimes(' ', indent);
9741075 }
9751076
976 try renderExpression(allocator, stream, tree, indent, &@"else".base);
1077 try renderExpression(allocator, stream, tree, indent, &@"else".base, space);
9771078 }
9781079 },
9791080
9801081 ast.Node.Id.If => {
9811082 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
982 try stream.print("{} (", tree.tokenSlice(if_node.if_token));
9831083
984 try renderExpression(allocator, stream, tree, indent, if_node.condition);
985 try renderToken(tree, stream, if_node.condition.lastToken() + 1, indent, false, true);
1084 try renderToken(tree, stream, if_node.if_token, indent, Space.Space);
1085 try renderToken(tree, stream, tree.prevToken(if_node.condition.firstToken()), indent, Space.None);
1086
1087 try renderExpression(allocator, stream, tree, indent, if_node.condition, Space.None);
1088 try renderToken(tree, stream, tree.nextToken(if_node.condition.lastToken()), indent, Space.Space);
9861089
9871090 if (if_node.payload) |payload| {
988 try renderExpression(allocator, stream, tree, indent, payload);
989 try stream.write(" ");
1091 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
9901092 }
9911093
992 try renderExpression(allocator, stream, tree, indent, if_node.body);
993
9941094 switch (if_node.body.id) {
9951095 ast.Node.Id.Block,
9961096 ast.Node.Id.If,
......@@ -999,25 +1099,29 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
9991099 ast.Node.Id.Switch => {
10001100 if (if_node.@"else") |@"else"| {
10011101 if (if_node.body.id == ast.Node.Id.Block) {
1002 try stream.write(" ");
1102 try renderExpression(allocator, stream, tree, indent, if_node.body, Space.Space);
10031103 } else {
1004 try stream.write("\n");
1104 try renderExpression(allocator, stream, tree, indent, if_node.body, Space.Newline);
10051105 try stream.writeByteNTimes(' ', indent);
10061106 }
10071107
1008 try renderExpression(allocator, stream, tree, indent, &@"else".base);
1108 try renderExpression(allocator, stream, tree, indent, &@"else".base, space);
1109 } else {
1110 try renderExpression(allocator, stream, tree, indent, if_node.body, space);
10091111 }
10101112 },
10111113 else => {
10121114 if (if_node.@"else") |@"else"| {
1013 try stream.print(" {} ", tree.tokenSlice(@"else".else_token));
1115 try renderExpression(allocator, stream, tree, indent, if_node.body, Space.Space);
1116 try renderToken(tree, stream, @"else".else_token, indent, Space.Space);
10141117
10151118 if (@"else".payload) |payload| {
1016 try renderExpression(allocator, stream, tree, indent, payload);
1017 try stream.write(" ");
1119 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
10181120 }
10191121
1020 try renderExpression(allocator, stream, tree, indent, @"else".body);
1122 try renderExpression(allocator, stream, tree, indent, @"else".body, space);
1123 } else {
1124 try renderExpression(allocator, stream, tree, indent, if_node.body, space);
10211125 }
10221126 },
10231127 }
......@@ -1025,15 +1129,17 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
10251129
10261130 ast.Node.Id.Asm => {
10271131 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
1028 try stream.print("{} ", tree.tokenSlice(asm_node.asm_token));
1132
1133 try renderToken(tree, stream, asm_node.asm_token, indent, Space.Space); // asm
10291134
10301135 if (asm_node.volatile_token) |volatile_token| {
1031 try stream.print("{} ", tree.tokenSlice(volatile_token));
1136 try renderToken(tree, stream, volatile_token, indent, Space.Space); // volatile
1137 try renderToken(tree, stream, tree.nextToken(volatile_token), indent, Space.None); // (
1138 } else {
1139 try renderToken(tree, stream, tree.nextToken(asm_node.asm_token), indent, Space.None); // (
10321140 }
10331141
1034 try stream.print("(");
1035 try renderExpression(allocator, stream, tree, indent, asm_node.template);
1036 try stream.print("\n");
1142 try renderExpression(allocator, stream, tree, indent, asm_node.template, Space.Newline);
10371143 const indent_once = indent + indent_delta;
10381144 try stream.writeByteNTimes(' ', indent_once);
10391145 try stream.print(": ");
......@@ -1043,13 +1149,15 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
10431149 var it = asm_node.outputs.iterator(0);
10441150 while (it.next()) |asm_output| {
10451151 const node = &(asm_output.*).base;
1046 try renderExpression(allocator, stream, tree, indent_extra, node);
1152 try renderExpression(allocator, stream, tree, indent_extra, node, Space.None);
10471153
10481154 if (it.peek()) |next_asm_output| {
10491155 const next_node = &(next_asm_output.*).base;
1050 const n = if (nodeLineOffset(tree, node, next_node) >= 2) u8(2) else u8(1);
1051 try stream.writeByte(',');
1052 try stream.writeByteNTimes('\n', n);
1156
1157 const comma = tree.prevToken(next_asm_output.*.firstToken());
1158 try renderToken(tree, stream, comma, indent_extra, Space.Newline); // ,
1159 try renderExtraNewline(tree, stream, next_node);
1160
10531161 try stream.writeByteNTimes(' ', indent_extra);
10541162 }
10551163 }
......@@ -1063,13 +1171,15 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
10631171 var it = asm_node.inputs.iterator(0);
10641172 while (it.next()) |asm_input| {
10651173 const node = &(asm_input.*).base;
1066 try renderExpression(allocator, stream, tree, indent_extra, node);
1174 try renderExpression(allocator, stream, tree, indent_extra, node, Space.None);
10671175
10681176 if (it.peek()) |next_asm_input| {
10691177 const next_node = &(next_asm_input.*).base;
1070 const n = if (nodeLineOffset(tree, node, next_node) >= 2) u8(2) else u8(1);
1071 try stream.writeByte(',');
1072 try stream.writeByteNTimes('\n', n);
1178
1179 const comma = tree.prevToken(next_asm_input.*.firstToken());
1180 try renderToken(tree, stream, comma, indent_extra, Space.Newline); // ,
1181 try renderExtraNewline(tree, stream, next_node);
1182
10731183 try stream.writeByteNTimes(' ', indent_extra);
10741184 }
10751185 }
......@@ -1082,7 +1192,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
10821192 {
10831193 var it = asm_node.clobbers.iterator(0);
10841194 while (it.next()) |node| {
1085 try renderExpression(allocator, stream, tree, indent_once, node.*);
1195 try renderExpression(allocator, stream, tree, indent_once, node.*, Space.None);
10861196
10871197 if (it.peek() != null) {
10881198 try stream.write(", ");
......@@ -1090,47 +1200,46 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
10901200 }
10911201 }
10921202
1093 try stream.write(")");
1203 try renderToken(tree, stream, asm_node.rparen, indent, space);
10941204 },
10951205
10961206 ast.Node.Id.AsmInput => {
10971207 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
10981208
10991209 try stream.write("[");
1100 try renderExpression(allocator, stream, tree, indent, asm_input.symbolic_name);
1210 try renderExpression(allocator, stream, tree, indent, asm_input.symbolic_name, Space.None);
11011211 try stream.write("] ");
1102 try renderExpression(allocator, stream, tree, indent, asm_input.constraint);
1212 try renderExpression(allocator, stream, tree, indent, asm_input.constraint, Space.None);
11031213 try stream.write(" (");
1104 try renderExpression(allocator, stream, tree, indent, asm_input.expr);
1105 try stream.write(")");
1214 try renderExpression(allocator, stream, tree, indent, asm_input.expr, Space.None);
1215 try renderToken(tree, stream, asm_input.lastToken(), indent, space); // )
11061216 },
11071217
11081218 ast.Node.Id.AsmOutput => {
11091219 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
11101220
11111221 try stream.write("[");
1112 try renderExpression(allocator, stream, tree, indent, asm_output.symbolic_name);
1222 try renderExpression(allocator, stream, tree, indent, asm_output.symbolic_name, Space.None);
11131223 try stream.write("] ");
1114 try renderExpression(allocator, stream, tree, indent, asm_output.constraint);
1224 try renderExpression(allocator, stream, tree, indent, asm_output.constraint, Space.None);
11151225 try stream.write(" (");
11161226
11171227 switch (asm_output.kind) {
11181228 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
1119 try renderExpression(allocator, stream, tree, indent, &variable_name.base);
1229 try renderExpression(allocator, stream, tree, indent, &variable_name.base, Space.None);
11201230 },
11211231 ast.Node.AsmOutput.Kind.Return => |return_type| {
11221232 try stream.write("-> ");
1123 try renderExpression(allocator, stream, tree, indent, return_type);
1233 try renderExpression(allocator, stream, tree, indent, return_type, Space.None);
11241234 },
11251235 }
11261236
1127 try stream.write(")");
1237 try renderToken(tree, stream, asm_output.lastToken(), indent, space); // )
11281238 },
11291239
11301240 ast.Node.Id.StructField,
11311241 ast.Node.Id.UnionTag,
11321242 ast.Node.Id.EnumTag,
1133 ast.Node.Id.ErrorTag,
11341243 ast.Node.Id.Root,
11351244 ast.Node.Id.VarDecl,
11361245 ast.Node.Id.Use,
......@@ -1139,70 +1248,74 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
11391248 }
11401249}
11411250
1142fn renderVarDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, var_decl: &ast.Node.VarDecl) (@typeOf(stream).Child.Error || Error)!void {
1251fn renderVarDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize,
1252 var_decl: &ast.Node.VarDecl) (@typeOf(stream).Child.Error || Error)!void
1253{
11431254 if (var_decl.visib_token) |visib_token| {
1144 try renderToken(tree, stream, visib_token, indent, false, true);
1255 try renderToken(tree, stream, visib_token, indent, Space.Space); // pub
11451256 }
11461257
11471258 if (var_decl.extern_export_token) |extern_export_token| {
1148 try renderToken(tree, stream, extern_export_token, indent, false, true);
1259 try renderToken(tree, stream, extern_export_token, indent, Space.Space); // extern
11491260
11501261 if (var_decl.lib_name) |lib_name| {
1151 try renderExpression(allocator, stream, tree, indent, lib_name);
1152 try stream.write(" ");
1262 try renderExpression(allocator, stream, tree, indent, lib_name, Space.Space); // "lib"
11531263 }
11541264 }
11551265
11561266 if (var_decl.comptime_token) |comptime_token| {
1157 try renderToken(tree, stream, comptime_token, indent, false, true);
1267 try renderToken(tree, stream, comptime_token, indent, Space.Space); // comptime
11581268 }
11591269
1160 try renderToken(tree, stream, var_decl.mut_token, indent, false, true);
1161 try renderToken(tree, stream, var_decl.name_token, indent, false, false);
1270 try renderToken(tree, stream, var_decl.mut_token, indent, Space.Space); // var
1271
1272 const name_space = if (var_decl.type_node == null and (var_decl.align_node != null or
1273 var_decl.init_node != null)) Space.Space else Space.None;
1274 try renderToken(tree, stream, var_decl.name_token, indent, name_space);
11621275
11631276 if (var_decl.type_node) |type_node| {
1164 try stream.write(": ");
1165 try renderExpression(allocator, stream, tree, indent, type_node);
1277 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, Space.Space);
1278 const s = if (var_decl.align_node != null or var_decl.init_node != null) Space.Space else Space.None;
1279 try renderExpression(allocator, stream, tree, indent, type_node, s);
11661280 }
11671281
11681282 if (var_decl.align_node) |align_node| {
1169 try stream.write(" align(");
1170 try renderExpression(allocator, stream, tree, indent, align_node);
1171 try stream.write(")");
1283 const lparen = tree.prevToken(align_node.firstToken());
1284 const align_kw = tree.prevToken(lparen);
1285 const rparen = tree.nextToken(align_node.lastToken());
1286 try renderToken(tree, stream, align_kw, indent, Space.None); // align
1287 try renderToken(tree, stream, lparen, indent, Space.None); // (
1288 try renderExpression(allocator, stream, tree, indent, align_node, Space.None);
1289 const s = if (var_decl.init_node != null) Space.Space else Space.None;
1290 try renderToken(tree, stream, rparen, indent, s); // )
11721291 }
11731292
11741293 if (var_decl.init_node) |init_node| {
1175 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
1176 try stream.write(text);
1177 try renderExpression(allocator, stream, tree, indent, init_node);
1294 const s = if (init_node.id == ast.Node.Id.MultilineStringLiteral) Space.None else Space.Space;
1295 try renderToken(tree, stream, var_decl.eq_token, indent, s); // =
1296 try renderExpression(allocator, stream, tree, indent, init_node, Space.None);
11781297 }
11791298
1180 try renderToken(tree, stream, var_decl.semicolon_token, indent, true, false);
1181}
1182
1183fn maybeRenderSemicolon(stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
1184 if (base.requireSemiColon()) {
1185 const semicolon_index = base.lastToken() + 1;
1186 assert(tree.tokens.at(semicolon_index).id == Token.Id.Semicolon);
1187 try renderToken(tree, stream, semicolon_index, indent, true, true);
1188 }
1299 try renderToken(tree, stream, var_decl.semicolon_token, indent, Space.Newline);
11891300}
11901301
11911302fn renderParamDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
11921303 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
1304
11931305 if (param_decl.comptime_token) |comptime_token| {
1194 try stream.print("{} ", tree.tokenSlice(comptime_token));
1306 try renderToken(tree, stream, comptime_token, indent, Space.Space);
11951307 }
11961308 if (param_decl.noalias_token) |noalias_token| {
1197 try stream.print("{} ", tree.tokenSlice(noalias_token));
1309 try renderToken(tree, stream, noalias_token, indent, Space.Space);
11981310 }
11991311 if (param_decl.name_token) |name_token| {
1200 try stream.print("{}: ", tree.tokenSlice(name_token));
1312 try renderToken(tree, stream, name_token, indent, Space.None);
1313 try renderToken(tree, stream, tree.nextToken(name_token), indent, Space.Space); // :
12011314 }
12021315 if (param_decl.var_args_token) |var_args_token| {
1203 try stream.print("{}", tree.tokenSlice(var_args_token));
1316 try renderToken(tree, stream, var_args_token, indent, Space.None);
12041317 } else {
1205 try renderExpression(allocator, stream, tree, indent, param_decl.type_node);
1318 try renderExpression(allocator, stream, tree, indent, param_decl.type_node, Space.None);
12061319 }
12071320}
12081321
......@@ -1213,41 +1326,104 @@ fn renderStatement(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, inde
12131326 try renderVarDecl(allocator, stream, tree, indent, var_decl);
12141327 },
12151328 else => {
1216 try renderExpression(allocator, stream, tree, indent, base);
1217 try maybeRenderSemicolon(stream, tree, indent, base);
1329 if (base.requireSemiColon()) {
1330 try renderExpression(allocator, stream, tree, indent, base, Space.None);
1331
1332 const semicolon_index = tree.nextToken(base.lastToken());
1333 assert(tree.tokens.at(semicolon_index).id == Token.Id.Semicolon);
1334 try renderToken(tree, stream, semicolon_index, indent, Space.Newline);
1335 } else {
1336 try renderExpression(allocator, stream, tree, indent, base, Space.Newline);
1337 }
12181338 },
12191339 }
12201340}
12211341
1222fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent: usize, line_break: bool, space: bool) (@typeOf(stream).Child.Error || Error)!void {
1223 const token = tree.tokens.at(token_index);
1342const Space = enum {
1343 None,
1344 Newline,
1345 Space,
1346 NoNewline,
1347 NoIndent,
1348 NoComment,
1349};
1350
1351fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent: usize, space: Space) (@typeOf(stream).Child.Error || Error)!void {
1352 var token = tree.tokens.at(token_index);
12241353 try stream.write(tree.tokenSlicePtr(token));
12251354
1226 const next_token = tree.tokens.at(token_index + 1);
1227 if (next_token.id == Token.Id.LineComment) {
1228 const loc = tree.tokenLocationPtr(token.end, next_token);
1229 if (loc.line == 0) {
1230 try stream.print(" {}", tree.tokenSlicePtr(next_token));
1231 if (!line_break) {
1232 try stream.write("\n");
1233
1234 const after_comment_token = tree.tokens.at(token_index + 2);
1235 const next_line_indent = switch (after_comment_token.id) {
1236 Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => indent,
1237 else => indent + indent_delta,
1238 };
1239 try stream.writeByteNTimes(' ', next_line_indent);
1240 return;
1355 if (space == Space.NoComment) return;
1356
1357 var next_token = tree.tokens.at(token_index + 1);
1358 if (next_token.id != Token.Id.LineComment) {
1359 switch (space) {
1360 Space.None, Space.NoNewline, Space.NoIndent => return,
1361 Space.Newline => return stream.write("\n"),
1362 Space.Space => return stream.writeByte(' '),
1363 Space.NoComment => unreachable,
1364 }
1365 }
1366
1367 var loc = tree.tokenLocationPtr(token.end, next_token);
1368 var offset: usize = 1;
1369 if (loc.line == 0) {
1370 try stream.print(" {}", tree.tokenSlicePtr(next_token));
1371 offset = 2;
1372 token = next_token;
1373 next_token = tree.tokens.at(token_index + offset);
1374 if (next_token.id != Token.Id.LineComment) {
1375 switch (space) {
1376 Space.None, Space.Space => {
1377 try stream.writeByte('\n');
1378 const after_comment_token = tree.tokens.at(token_index + offset);
1379 const next_line_indent = switch (after_comment_token.id) {
1380 Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => indent,
1381 else => indent + indent_delta,
1382 };
1383 try stream.writeByteNTimes(' ', next_line_indent);
1384 },
1385 Space.Newline, Space.NoIndent => try stream.write("\n"),
1386 Space.NoNewline => {},
1387 Space.NoComment => unreachable,
12411388 }
1389 return;
12421390 }
1391 loc = tree.tokenLocationPtr(token.end, next_token);
12431392 }
12441393
1245 if (!line_break and space) {
1246 try stream.writeByte(' ');
1394 while (true) {
1395 assert(loc.line != 0);
1396 const newline_count = if (loc.line == 1) u8(1) else u8(2);
1397 try stream.writeByteNTimes('\n', newline_count);
1398 try stream.writeByteNTimes(' ', indent);
1399 try stream.write(tree.tokenSlicePtr(next_token));
1400
1401 offset += 1;
1402 token = next_token;
1403 next_token = tree.tokens.at(token_index + offset);
1404 if (next_token.id != Token.Id.LineComment) {
1405 switch (space) {
1406 Space.Newline, Space.NoIndent => try stream.writeByte('\n'),
1407 Space.None, Space.Space => {
1408 try stream.writeByte('\n');
1409
1410 const after_comment_token = tree.tokens.at(token_index + offset);
1411 const next_line_indent = switch (after_comment_token.id) {
1412 Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => indent,
1413 else => indent,
1414 };
1415 try stream.writeByteNTimes(' ', next_line_indent);
1416 },
1417 Space.NoNewline => {},
1418 Space.NoComment => unreachable,
1419 }
1420 return;
1421 }
1422 loc = tree.tokenLocationPtr(token.end, next_token);
12471423 }
12481424}
12491425
1250fn renderComments(tree: &ast.Tree, stream: var, node: var, indent: usize) (@typeOf(stream).Child.Error || Error)!void {
1426fn renderDocComments(tree: &ast.Tree, stream: var, node: var, indent: usize) (@typeOf(stream).Child.Error || Error)!void {
12511427 const comment = node.doc_comments ?? return;
12521428 var it = comment.lines.iterator(0);
12531429 while (it.next()) |line_token_index| {