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....@@ -182,6 +182,9 @@ binary.
182182
183This is the actual compiler binary that we will install to the system.183This 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
185#### Debug / Development Build188#### Debug / Development Build
186189
187```190```
std/zig/ast.zig+37-44
...@@ -71,6 +71,24 @@ pub const Tree = struct {...@@ -71,6 +71,24 @@ pub const Tree = struct {
71 pub fn dump(self: &Tree) void {71 pub fn dump(self: &Tree) void {
72 self.root_node.base.dump(0);72 self.root_node.base.dump(0);
73 }73 }
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 }
74};92};
7593
76pub const Error = union(enum) {94pub const Error = union(enum) {
...@@ -272,7 +290,6 @@ pub const Node = struct {...@@ -272,7 +290,6 @@ pub const Node = struct {
272 Block,290 Block,
273291
274 // Misc292 // Misc
275 LineComment,
276 DocComment,293 DocComment,
277 SwitchCase,294 SwitchCase,
278 SwitchElse,295 SwitchElse,
...@@ -359,7 +376,6 @@ pub const Node = struct {...@@ -359,7 +376,6 @@ pub const Node = struct {
359 Id.SwitchElse,376 Id.SwitchElse,
360 Id.FieldInitializer,377 Id.FieldInitializer,
361 Id.DocComment,378 Id.DocComment,
362 Id.LineComment,
363 Id.TestDecl => return false,379 Id.TestDecl => return false,
364 Id.While => {380 Id.While => {
365 const while_node = @fieldParentPtr(While, "base", n);381 const while_node = @fieldParentPtr(While, "base", n);
...@@ -506,6 +522,7 @@ pub const Node = struct {...@@ -506,6 +522,7 @@ pub const Node = struct {
506 base: Node,522 base: Node,
507 doc_comments: ?&DocComment,523 doc_comments: ?&DocComment,
508 visib_token: ?TokenIndex,524 visib_token: ?TokenIndex,
525 use_token: TokenIndex,
509 expr: &Node,526 expr: &Node,
510 semicolon_token: TokenIndex,527 semicolon_token: TokenIndex,
511528
...@@ -520,7 +537,7 @@ pub const Node = struct {...@@ -520,7 +537,7 @@ pub const Node = struct {
520537
521 pub fn firstToken(self: &Use) TokenIndex {538 pub fn firstToken(self: &Use) TokenIndex {
522 if (self.visib_token) |visib_token| return visib_token;539 if (self.visib_token) |visib_token| return visib_token;
523 return self.expr.firstToken();540 return self.use_token;
524 }541 }
525542
526 pub fn lastToken(self: &Use) TokenIndex {543 pub fn lastToken(self: &Use) TokenIndex {
...@@ -556,27 +573,15 @@ pub const Node = struct {...@@ -556,27 +573,15 @@ pub const Node = struct {
556573
557 pub const ContainerDecl = struct {574 pub const ContainerDecl = struct {
558 base: Node,575 base: Node,
559 ltoken: TokenIndex,576 layout_token: ?TokenIndex,
560 layout: Layout,577 kind_token: TokenIndex,
561 kind: Kind,
562 init_arg_expr: InitArg,578 init_arg_expr: InitArg,
563 fields_and_decls: DeclList,579 fields_and_decls: DeclList,
580 lbrace_token: TokenIndex,
564 rbrace_token: TokenIndex,581 rbrace_token: TokenIndex,
565582
566 pub const DeclList = Root.DeclList;583 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
580 const InitArg = union(enum) {585 const InitArg = union(enum) {
581 None,586 None,
582 Enum: ?&Node,587 Enum: ?&Node,
...@@ -602,7 +607,10 @@ pub const Node = struct {...@@ -602,7 +607,10 @@ pub const Node = struct {
602 }607 }
603608
604 pub fn firstToken(self: &ContainerDecl) TokenIndex {609 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;
606 }614 }
607615
608 pub fn lastToken(self: &ContainerDecl) TokenIndex {616 pub fn lastToken(self: &ContainerDecl) TokenIndex {
...@@ -1113,7 +1121,7 @@ pub const Node = struct {...@@ -1113,7 +1121,7 @@ pub const Node = struct {
1113 switch_token: TokenIndex,1121 switch_token: TokenIndex,
1114 expr: &Node,1122 expr: &Node,
11151123
1116 /// these can be SwitchCase nodes or LineComment nodes1124 /// these must be SwitchCase nodes
1117 cases: CaseList,1125 cases: CaseList,
1118 rbrace: TokenIndex,1126 rbrace: TokenIndex,
11191127
...@@ -1143,6 +1151,7 @@ pub const Node = struct {...@@ -1143,6 +1151,7 @@ pub const Node = struct {
1143 pub const SwitchCase = struct {1151 pub const SwitchCase = struct {
1144 base: Node,1152 base: Node,
1145 items: ItemList,1153 items: ItemList,
1154 arrow_token: TokenIndex,
1146 payload: ?&Node,1155 payload: ?&Node,
1147 expr: &Node,1156 expr: &Node,
11481157
...@@ -1963,9 +1972,11 @@ pub const Node = struct {...@@ -1963,9 +1972,11 @@ pub const Node = struct {
19631972
1964 pub const AsmOutput = struct {1973 pub const AsmOutput = struct {
1965 base: Node,1974 base: Node,
1975 lbracket: TokenIndex,
1966 symbolic_name: &Node,1976 symbolic_name: &Node,
1967 constraint: &Node,1977 constraint: &Node,
1968 kind: Kind,1978 kind: Kind,
1979 rparen: TokenIndex,
19691980
1970 const Kind = union(enum) {1981 const Kind = union(enum) {
1971 Variable: &Identifier,1982 Variable: &Identifier,
...@@ -1996,22 +2007,21 @@ pub const Node = struct {...@@ -1996,22 +2007,21 @@ pub const Node = struct {
1996 }2007 }
19972008
1998 pub fn firstToken(self: &AsmOutput) TokenIndex {2009 pub fn firstToken(self: &AsmOutput) TokenIndex {
1999 return self.symbolic_name.firstToken();2010 return self.lbracket;
2000 }2011 }
20012012
2002 pub fn lastToken(self: &AsmOutput) TokenIndex {2013 pub fn lastToken(self: &AsmOutput) TokenIndex {
2003 return switch (self.kind) {2014 return self.rparen;
2004 Kind.Variable => |variable_name| variable_name.lastToken(),
2005 Kind.Return => |return_type| return_type.lastToken(),
2006 };
2007 }2015 }
2008 };2016 };
20092017
2010 pub const AsmInput = struct {2018 pub const AsmInput = struct {
2011 base: Node,2019 base: Node,
2020 lbracket: TokenIndex,
2012 symbolic_name: &Node,2021 symbolic_name: &Node,
2013 constraint: &Node,2022 constraint: &Node,
2014 expr: &Node,2023 expr: &Node,
2024 rparen: TokenIndex,
20152025
2016 pub fn iterate(self: &AsmInput, index: usize) ?&Node {2026 pub fn iterate(self: &AsmInput, index: usize) ?&Node {
2017 var i = index;2027 var i = index;
...@@ -2029,11 +2039,11 @@ pub const Node = struct {...@@ -2029,11 +2039,11 @@ pub const Node = struct {
2029 }2039 }
20302040
2031 pub fn firstToken(self: &AsmInput) TokenIndex {2041 pub fn firstToken(self: &AsmInput) TokenIndex {
2032 return self.symbolic_name.firstToken();2042 return self.lbracket;
2033 }2043 }
20342044
2035 pub fn lastToken(self: &AsmInput) TokenIndex {2045 pub fn lastToken(self: &AsmInput) TokenIndex {
2036 return self.expr.lastToken();2046 return self.rparen;
2037 }2047 }
2038 };2048 };
20392049
...@@ -2126,23 +2136,6 @@ pub const Node = struct {...@@ -2126,23 +2136,6 @@ pub const Node = struct {
2126 }2136 }
2127 };2137 };
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
2146 pub const DocComment = struct {2139 pub const DocComment = struct {
2147 base: Node,2140 base: Node,
2148 lines: LineList,2141 lines: LineList,
std/zig/parse.zig+111-144
...@@ -49,10 +49,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -49,10 +49,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
4949
50 switch (state) {50 switch (state) {
51 State.TopLevel => {51 State.TopLevel => {
52 while (try eatLineComment(arena, &tok_it, &tree)) |line_comment| {
53 try root_node.decls.push(&line_comment.base);
54 }
55
56 const comments = try eatDocComments(arena, &tok_it, &tree);52 const comments = try eatDocComments(arena, &tok_it, &tree);
5753
58 const token = nextToken(&tok_it, &tree);54 const token = nextToken(&tok_it, &tree);
...@@ -80,7 +76,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -80,7 +76,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
80 try stack.append(State{ .Block = block });76 try stack.append(State{ .Block = block });
81 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{77 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
82 .id = Token.Id.LBrace,78 .id = Token.Id.LBrace,
83 .ptr = &block.rbrace,79 .ptr = &block.lbrace,
84 } });80 } });
85 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &test_node.name } });81 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &test_node.name } });
86 continue;82 continue;
...@@ -121,12 +117,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -121,12 +117,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
121 try stack.append(State{ .Block = block });117 try stack.append(State{ .Block = block });
122 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{118 try stack.append(State{ .ExpectTokenSave = ExpectTokenSave{
123 .id = Token.Id.LBrace,119 .id = Token.Id.LBrace,
124 .ptr = &block.rbrace,120 .ptr = &block.lbrace,
125 } });121 } });
126 continue;122 continue;
127 },123 },
128 else => {124 else => {
129 putBackToken(&tok_it, &tree);125 prevToken(&tok_it, &tree);
130 stack.append(State.TopLevel) catch unreachable;126 stack.append(State.TopLevel) catch unreachable;
131 try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{127 try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{
132 .decls = &root_node.decls,128 .decls = &root_node.decls,
...@@ -172,7 +168,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -172,7 +168,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
172 continue;168 continue;
173 },169 },
174 else => {170 else => {
175 putBackToken(&tok_it, &tree);171 prevToken(&tok_it, &tree);
176 stack.append(State{ .TopLevelDecl = ctx }) catch unreachable;172 stack.append(State{ .TopLevelDecl = ctx }) catch unreachable;
177 continue;173 continue;
178 },174 },
...@@ -184,7 +180,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -184,7 +180,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
184 const lib_name_token_index = lib_name_token.index;180 const lib_name_token_index = lib_name_token.index;
185 const lib_name_token_ptr = lib_name_token.ptr;181 const lib_name_token_ptr = lib_name_token.ptr;
186 break :blk (try parseStringLiteral(arena, &tok_it, lib_name_token_ptr, lib_name_token_index, &tree)) ?? {182 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);
188 break :blk null;184 break :blk null;
189 };185 };
190 };186 };
...@@ -211,6 +207,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -211,6 +207,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
211207
212 const node = try arena.construct(ast.Node.Use{208 const node = try arena.construct(ast.Node.Use{
213 .base = ast.Node{ .id = ast.Node.Id.Use },209 .base = ast.Node{ .id = ast.Node.Id.Use },
210 .use_token = token_index,
214 .visib_token = ctx.visib_token,211 .visib_token = ctx.visib_token,
215 .expr = undefined,212 .expr = undefined,
216 .semicolon_token = undefined,213 .semicolon_token = undefined,
...@@ -310,7 +307,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -310,7 +307,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
310 },307 },
311 State.TopLevelExternOrField => |ctx| {308 State.TopLevelExternOrField => |ctx| {
312 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| {309 if (eatToken(&tok_it, &tree, Token.Id.Identifier)) |identifier| {
313 std.debug.assert(ctx.container_decl.kind == ast.Node.ContainerDecl.Kind.Struct);
314 const node = try arena.construct(ast.Node.StructField{310 const node = try arena.construct(ast.Node.StructField{
315 .base = ast.Node{ .id = ast.Node.Id.StructField },311 .base = ast.Node{ .id = ast.Node.Id.StructField },
316 .doc_comments = ctx.comments,312 .doc_comments = ctx.comments,
...@@ -343,7 +339,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -343,7 +339,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
343 const eq_tok_index = eq_tok.index;339 const eq_tok_index = eq_tok.index;
344 const eq_tok_ptr = eq_tok.ptr;340 const eq_tok_ptr = eq_tok.ptr;
345 if (eq_tok_ptr.id != Token.Id.Equal) {341 if (eq_tok_ptr.id != Token.Id.Equal) {
346 putBackToken(&tok_it, &tree);342 prevToken(&tok_it, &tree);
347 continue;343 continue;
348 }344 }
349 stack.append(State{ .Expression = ctx }) catch unreachable;345 stack.append(State{ .Expression = ctx }) catch unreachable;
...@@ -356,12 +352,11 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -356,12 +352,11 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
356 const token_ptr = token.ptr;352 const token_ptr = token.ptr;
357 const node = try arena.construct(ast.Node.ContainerDecl{353 const node = try arena.construct(ast.Node.ContainerDecl{
358 .base = ast.Node{ .id = ast.Node.Id.ContainerDecl },354 .base = ast.Node{ .id = ast.Node.Id.ContainerDecl },
359 .ltoken = ctx.ltoken,355 .layout_token = ctx.layout_token,
360 .layout = ctx.layout,356 .kind_token = switch (token_ptr.id) {
361 .kind = switch (token_ptr.id) {357 Token.Id.Keyword_struct,
362 Token.Id.Keyword_struct => ast.Node.ContainerDecl.Kind.Struct,358 Token.Id.Keyword_union,
363 Token.Id.Keyword_union => ast.Node.ContainerDecl.Kind.Union,359 Token.Id.Keyword_enum => token_index,
364 Token.Id.Keyword_enum => ast.Node.ContainerDecl.Kind.Enum,
365 else => {360 else => {
366 ((try tree.errors.addOne())).* = Error{ .ExpectedAggregateKw = Error.ExpectedAggregateKw{ .token = token_index } };361 ((try tree.errors.addOne())).* = Error{ .ExpectedAggregateKw = Error.ExpectedAggregateKw{ .token = token_index } };
367 return tree;362 return tree;
...@@ -369,12 +364,16 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -369,12 +364,16 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
369 },364 },
370 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,365 .init_arg_expr = ast.Node.ContainerDecl.InitArg.None,
371 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),366 .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(arena),
367 .lbrace_token = undefined,
372 .rbrace_token = undefined,368 .rbrace_token = undefined,
373 });369 });
374 ctx.opt_ctx.store(&node.base);370 ctx.opt_ctx.store(&node.base);
375371
376 stack.append(State{ .ContainerDecl = node }) catch unreachable;372 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 } });
378 try stack.append(State{ .ContainerInitArgStart = node });377 try stack.append(State{ .ContainerInitArgStart = node });
379 continue;378 continue;
380 },379 },
...@@ -403,11 +402,11 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -403,11 +402,11 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
403 try stack.append(State{ .ExpectToken = Token.Id.RParen });402 try stack.append(State{ .ExpectToken = Token.Id.RParen });
404 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &container_decl.init_arg_expr.Enum } });403 try stack.append(State{ .Expression = OptionalCtx{ .RequiredNull = &container_decl.init_arg_expr.Enum } });
405 } else {404 } else {
406 putBackToken(&tok_it, &tree);405 prevToken(&tok_it, &tree);
407 }406 }
408 },407 },
409 else => {408 else => {
410 putBackToken(&tok_it, &tree);409 prevToken(&tok_it, &tree);
411 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg{ .Type = undefined };410 container_decl.init_arg_expr = ast.Node.ContainerDecl.InitArg{ .Type = undefined };
412 stack.append(State{ .Expression = OptionalCtx{ .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;411 stack.append(State{ .Expression = OptionalCtx{ .Required = &container_decl.init_arg_expr.Type } }) catch unreachable;
413 },412 },
...@@ -416,18 +415,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -416,18 +415,14 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
416 },415 },
417416
418 State.ContainerDecl => |container_decl| {417 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
423 const comments = try eatDocComments(arena, &tok_it, &tree);418 const comments = try eatDocComments(arena, &tok_it, &tree);
424 const token = nextToken(&tok_it, &tree);419 const token = nextToken(&tok_it, &tree);
425 const token_index = token.index;420 const token_index = token.index;
426 const token_ptr = token.ptr;421 const token_ptr = token.ptr;
427 switch (token_ptr.id) {422 switch (token_ptr.id) {
428 Token.Id.Identifier => {423 Token.Id.Identifier => {
429 switch (container_decl.kind) {424 switch (tree.tokens.at(container_decl.kind_token).id) {
430 ast.Node.ContainerDecl.Kind.Struct => {425 Token.Id.Keyword_struct => {
431 const node = try arena.construct(ast.Node.StructField{426 const node = try arena.construct(ast.Node.StructField{
432 .base = ast.Node{ .id = ast.Node.Id.StructField },427 .base = ast.Node{ .id = ast.Node.Id.StructField },
433 .doc_comments = comments,428 .doc_comments = comments,
...@@ -443,7 +438,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -443,7 +438,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
443 try stack.append(State{ .ExpectToken = Token.Id.Colon });438 try stack.append(State{ .ExpectToken = Token.Id.Colon });
444 continue;439 continue;
445 },440 },
446 ast.Node.ContainerDecl.Kind.Union => {441 Token.Id.Keyword_union => {
447 const node = try arena.construct(ast.Node.UnionTag{442 const node = try arena.construct(ast.Node.UnionTag{
448 .base = ast.Node{ .id = ast.Node.Id.UnionTag },443 .base = ast.Node{ .id = ast.Node.Id.UnionTag },
449 .name_token = token_index,444 .name_token = token_index,
...@@ -459,7 +454,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -459,7 +454,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
459 try stack.append(State{ .IfToken = Token.Id.Colon });454 try stack.append(State{ .IfToken = Token.Id.Colon });
460 continue;455 continue;
461 },456 },
462 ast.Node.ContainerDecl.Kind.Enum => {457 Token.Id.Keyword_enum => {
463 const node = try arena.construct(ast.Node.EnumTag{458 const node = try arena.construct(ast.Node.EnumTag{
464 .base = ast.Node{ .id = ast.Node.Id.EnumTag },459 .base = ast.Node{ .id = ast.Node.Id.EnumTag },
465 .name_token = token_index,460 .name_token = token_index,
...@@ -473,11 +468,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -473,11 +468,12 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
473 try stack.append(State{ .IfToken = Token.Id.Equal });468 try stack.append(State{ .IfToken = Token.Id.Equal });
474 continue;469 continue;
475 },470 },
471 else => unreachable,
476 }472 }
477 },473 },
478 Token.Id.Keyword_pub => {474 Token.Id.Keyword_pub => {
479 switch (container_decl.kind) {475 switch (tree.tokens.at(container_decl.kind_token).id) {
480 ast.Node.ContainerDecl.Kind.Struct => {476 Token.Id.Keyword_struct => {
481 try stack.append(State{ .TopLevelExternOrField = TopLevelExternOrFieldCtx{477 try stack.append(State{ .TopLevelExternOrField = TopLevelExternOrFieldCtx{
482 .visib_token = token_index,478 .visib_token = token_index,
483 .container_decl = container_decl,479 .container_decl = container_decl,
...@@ -518,7 +514,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -518,7 +514,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
518 continue;514 continue;
519 },515 },
520 else => {516 else => {
521 putBackToken(&tok_it, &tree);517 prevToken(&tok_it, &tree);
522 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;518 stack.append(State{ .ContainerDecl = container_decl }) catch unreachable;
523 try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{519 try stack.append(State{ .TopLevelExtern = TopLevelDeclCtx{
524 .decls = &container_decl.fields_and_decls,520 .decls = &container_decl.fields_and_decls,
...@@ -573,7 +569,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -573,7 +569,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
573 continue;569 continue;
574 }570 }
575571
576 putBackToken(&tok_it, &tree);572 prevToken(&tok_it, &tree);
577 continue;573 continue;
578 },574 },
579 State.VarDeclEq => |var_decl| {575 State.VarDeclEq => |var_decl| {
...@@ -616,7 +612,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -616,7 +612,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
616 if (loc.line == 0) {612 if (loc.line == 0) {
617 try pushDocComment(arena, doc_comment_token, &var_decl.doc_comments);613 try pushDocComment(arena, doc_comment_token, &var_decl.doc_comments);
618 } else {614 } else {
619 putBackToken(&tok_it, &tree);615 prevToken(&tok_it, &tree);
620 }616 }
621 }617 }
622 },618 },
...@@ -688,7 +684,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -688,7 +684,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
688 }684 }
689 }685 }
690686
691 putBackToken(&tok_it, &tree);687 prevToken(&tok_it, &tree);
692 fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = undefined };688 fn_proto.return_type = ast.Node.FnProto.ReturnType{ .Explicit = undefined };
693 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &fn_proto.return_type.Explicit } }) catch unreachable;689 stack.append(State{ .TypeExprBegin = OptionalCtx{ .Required = &fn_proto.return_type.Explicit } }) catch unreachable;
694 continue;690 continue;
...@@ -733,7 +729,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -733,7 +729,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
733 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {729 if (eatToken(&tok_it, &tree, Token.Id.Colon)) |_| {
734 param_decl.name_token = ident_token;730 param_decl.name_token = ident_token;
735 } else {731 } else {
736 putBackToken(&tok_it, &tree);732 prevToken(&tok_it, &tree);
737 }733 }
738 }734 }
739 continue;735 continue;
...@@ -838,7 +834,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -838,7 +834,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
838 return tree;834 return tree;
839 }835 }
840836
841 putBackToken(&tok_it, &tree);837 prevToken(&tok_it, &tree);
842 continue;838 continue;
843 },839 },
844 }840 }
...@@ -872,7 +868,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -872,7 +868,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
872 return tree;868 return tree;
873 }869 }
874870
875 putBackToken(&tok_it, &tree);871 prevToken(&tok_it, &tree);
876 continue;872 continue;
877 },873 },
878 }874 }
...@@ -927,11 +923,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -927,11 +923,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
927 continue;923 continue;
928 },924 },
929 State.Else => |dest| {925 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 }
935 if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| {926 if (eatToken(&tok_it, &tree, Token.Id.Keyword_else)) |else_token| {
936 const node = try arena.construct(ast.Node.Else{927 const node = try arena.construct(ast.Node.Else{
937 .base = ast.Node{ .id = ast.Node.Id.Else },928 .base = ast.Node{ .id = ast.Node.Id.Else },
...@@ -945,9 +936,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -945,9 +936,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
945 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });936 try stack.append(State{ .Payload = OptionalCtx{ .Optional = &node.payload } });
946 continue;937 continue;
947 } else {938 } else {
948 if (need_index_restore) {
949 tok_it.set(old_index);
950 }
951 continue;939 continue;
952 }940 }
953 },941 },
...@@ -962,16 +950,9 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -962,16 +950,9 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
962 continue;950 continue;
963 },951 },
964 else => {952 else => {
965 putBackToken(&tok_it, &tree);953 prevToken(&tok_it, &tree);
966 stack.append(State{ .Block = block }) catch unreachable;954 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
975 try stack.append(State{ .Statement = block });956 try stack.append(State{ .Statement = block });
976 continue;957 continue;
977 },958 },
...@@ -1035,7 +1016,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1035,7 +1016,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1035 continue;1016 continue;
1036 },1017 },
1037 else => {1018 else => {
1038 putBackToken(&tok_it, &tree);1019 prevToken(&tok_it, &tree);
1039 const statement = try block.statements.addOne();1020 const statement = try block.statements.addOne();
1040 try stack.append(State{ .Semicolon = statement });1021 try stack.append(State{ .Semicolon = statement });
1041 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });1022 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = statement } });
...@@ -1062,8 +1043,8 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1062,8 +1043,8 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1062 continue;1043 continue;
1063 },1044 },
1064 else => {1045 else => {
1065 putBackToken(&tok_it, &tree);1046 prevToken(&tok_it, &tree);
1066 putBackToken(&tok_it, &tree);1047 prevToken(&tok_it, &tree);
1067 const statement = try ctx.block.statements.addOne();1048 const statement = try ctx.block.statements.addOne();
1068 try stack.append(State{ .Semicolon = statement });1049 try stack.append(State{ .Semicolon = statement });
1069 try stack.append(State{ .Expression = OptionalCtx{ .Required = statement } });1050 try stack.append(State{ .Expression = OptionalCtx{ .Required = statement } });
...@@ -1085,21 +1066,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1085,21 +1066,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1085 const lbracket_index = lbracket.index;1066 const lbracket_index = lbracket.index;
1086 const lbracket_ptr = lbracket.ptr;1067 const lbracket_ptr = lbracket.ptr;
1087 if (lbracket_ptr.id != Token.Id.LBracket) {1068 if (lbracket_ptr.id != Token.Id.LBracket) {
1088 putBackToken(&tok_it, &tree);1069 prevToken(&tok_it, &tree);
1089 continue;1070 continue;
1090 }1071 }
10911072
1092 const node = try arena.construct(ast.Node.AsmOutput{1073 const node = try arena.construct(ast.Node.AsmOutput{
1093 .base = ast.Node{ .id = ast.Node.Id.AsmOutput },1074 .base = ast.Node{ .id = ast.Node.Id.AsmOutput },
1075 .lbracket = lbracket_index,
1094 .symbolic_name = undefined,1076 .symbolic_name = undefined,
1095 .constraint = undefined,1077 .constraint = undefined,
1096 .kind = undefined,1078 .kind = undefined,
1079 .rparen = undefined,
1097 });1080 });
1098 try items.push(node);1081 try items.push(node);
10991082
1100 stack.append(State{ .AsmOutputItems = items }) catch unreachable;1083 stack.append(State{ .AsmOutputItems = items }) catch unreachable;
1101 try stack.append(State{ .IfToken = Token.Id.Comma });1084 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 } });
1103 try stack.append(State{ .AsmOutputReturnOrType = node });1089 try stack.append(State{ .AsmOutputReturnOrType = node });
1104 try stack.append(State{ .ExpectToken = Token.Id.LParen });1090 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1105 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.constraint } });1091 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.constraint } });
...@@ -1132,21 +1118,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1132,21 +1118,26 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1132 const lbracket_index = lbracket.index;1118 const lbracket_index = lbracket.index;
1133 const lbracket_ptr = lbracket.ptr;1119 const lbracket_ptr = lbracket.ptr;
1134 if (lbracket_ptr.id != Token.Id.LBracket) {1120 if (lbracket_ptr.id != Token.Id.LBracket) {
1135 putBackToken(&tok_it, &tree);1121 prevToken(&tok_it, &tree);
1136 continue;1122 continue;
1137 }1123 }
11381124
1139 const node = try arena.construct(ast.Node.AsmInput{1125 const node = try arena.construct(ast.Node.AsmInput{
1140 .base = ast.Node{ .id = ast.Node.Id.AsmInput },1126 .base = ast.Node{ .id = ast.Node.Id.AsmInput },
1127 .lbracket = lbracket_index,
1141 .symbolic_name = undefined,1128 .symbolic_name = undefined,
1142 .constraint = undefined,1129 .constraint = undefined,
1143 .expr = undefined,1130 .expr = undefined,
1131 .rparen = undefined,
1144 });1132 });
1145 try items.push(node);1133 try items.push(node);
11461134
1147 stack.append(State{ .AsmInputItems = items }) catch unreachable;1135 stack.append(State{ .AsmInputItems = items }) catch unreachable;
1148 try stack.append(State{ .IfToken = Token.Id.Comma });1136 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 } });
1150 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });1141 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.expr } });
1151 try stack.append(State{ .ExpectToken = Token.Id.LParen });1142 try stack.append(State{ .ExpectToken = Token.Id.LParen });
1152 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.constraint } });1143 try stack.append(State{ .StringLiteral = OptionalCtx{ .Required = &node.constraint } });
...@@ -1187,10 +1178,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1187,10 +1178,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1187 }1178 }
1188 },1179 },
1189 State.FieldInitListItemOrEnd => |list_state| {1180 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
1194 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {1181 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1195 (list_state.ptr).* = rbrace;1182 (list_state.ptr).* = rbrace;
1196 continue;1183 continue;
...@@ -1248,10 +1235,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1248,10 +1235,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1248 }1235 }
1249 },1236 },
1250 State.ErrorTagListItemOrEnd => |list_state| {1237 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
1255 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {1238 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1256 (list_state.ptr).* = rbrace;1239 (list_state.ptr).* = rbrace;
1257 continue;1240 continue;
...@@ -1279,10 +1262,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1279,10 +1262,6 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1279 }1262 }
1280 },1263 },
1281 State.SwitchCaseOrEnd => |list_state| {1264 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
1286 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {1265 if (eatToken(&tok_it, &tree, Token.Id.RBrace)) |rbrace| {
1287 (list_state.ptr).* = rbrace;1266 (list_state.ptr).* = rbrace;
1288 continue;1267 continue;
...@@ -1294,12 +1273,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1294,12 +1273,13 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1294 .items = ast.Node.SwitchCase.ItemList.init(arena),1273 .items = ast.Node.SwitchCase.ItemList.init(arena),
1295 .payload = null,1274 .payload = null,
1296 .expr = undefined,1275 .expr = undefined,
1276 .arrow_token = undefined,
1297 });1277 });
1298 try list_state.list.push(&node.base);1278 try list_state.list.push(&node.base);
1299 try stack.append(State{ .SwitchCaseCommaOrEnd = list_state });1279 try stack.append(State{ .SwitchCaseCommaOrEnd = list_state });
1300 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });1280 try stack.append(State{ .AssignmentExpressionBegin = OptionalCtx{ .Required = &node.expr } });
1301 try stack.append(State{ .PointerPayload = OptionalCtx{ .Optional = &node.payload } });1281 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
1304 continue;1284 continue;
1305 },1285 },
...@@ -1320,7 +1300,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1320,7 +1300,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1320 }1300 }
1321 },1301 },
13221302
1323 State.SwitchCaseFirstItem => |case_items| {1303 State.SwitchCaseFirstItem => |switch_case| {
1324 const token = nextToken(&tok_it, &tree);1304 const token = nextToken(&tok_it, &tree);
1325 const token_index = token.index;1305 const token_index = token.index;
1326 const token_ptr = token.ptr;1306 const token_ptr = token.ptr;
...@@ -1329,25 +1309,30 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1329,25 +1309,30 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1329 .base = ast.Node{ .id = ast.Node.Id.SwitchElse },1309 .base = ast.Node{ .id = ast.Node.Id.SwitchElse },
1330 .token = token_index,1310 .token = token_index,
1331 });1311 });
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 } });
1335 continue;1318 continue;
1336 } else {1319 } else {
1337 putBackToken(&tok_it, &tree);1320 prevToken(&tok_it, &tree);
1338 try stack.append(State{ .SwitchCaseItem = case_items });1321 try stack.append(State{ .SwitchCaseItem = switch_case });
1339 continue;1322 continue;
1340 }1323 }
1341 },1324 },
1342 State.SwitchCaseItem => |case_items| {1325 State.SwitchCaseItem => |node| {
1343 stack.append(State{ .SwitchCaseItemCommaOrEnd = case_items }) catch unreachable;1326 stack.append(State{ .SwitchCaseItemCommaOrEnd = node }) catch unreachable;
1344 try stack.append(State{ .RangeExpressionBegin = OptionalCtx{ .Required = try case_items.addOne() } });1327 try stack.append(State{ .RangeExpressionBegin = OptionalCtx{ .Required = try node.items.addOne() } });
1345 },1328 },
1346 State.SwitchCaseItemCommaOrEnd => |case_items| {1329 State.SwitchCaseItemCommaOrEnd => |node| {
1347 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.EqualAngleBracketRight)) {1330 switch (expectCommaOrEnd(&tok_it, &tree, Token.Id.EqualAngleBracketRight)) {
1348 ExpectCommaOrEndResult.end_token => |t| {1331 ExpectCommaOrEndResult.end_token => |end_token| {
1349 if (t == null) {1332 if (end_token) |t| {
1350 stack.append(State{ .SwitchCaseItem = case_items }) catch unreachable;1333 node.arrow_token = t;
1334 } else {
1335 stack.append(State{ .SwitchCaseItem = node }) catch unreachable;
1351 }1336 }
1352 continue;1337 continue;
1353 },1338 },
...@@ -1429,8 +1414,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1429,8 +1414,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
14291414
1430 stack.append(State{ .ContainerKind = ContainerKindCtx{1415 stack.append(State{ .ContainerKind = ContainerKindCtx{
1431 .opt_ctx = ctx.opt_ctx,1416 .opt_ctx = ctx.opt_ctx,
1432 .ltoken = ctx.extern_token,1417 .layout_token = ctx.extern_token,
1433 .layout = ast.Node.ContainerDecl.Layout.Extern,
1434 } }) catch unreachable;1418 } }) catch unreachable;
1435 continue;1419 continue;
1436 },1420 },
...@@ -1518,7 +1502,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1518,7 +1502,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1518 continue;1502 continue;
1519 },1503 },
1520 else => {1504 else => {
1521 putBackToken(&tok_it, &tree);1505 prevToken(&tok_it, &tree);
1522 continue;1506 continue;
1523 },1507 },
1524 }1508 }
...@@ -1537,7 +1521,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1537,7 +1521,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1537 return tree;1521 return tree;
1538 }1522 }
15391523
1540 putBackToken(&tok_it, &tree);1524 prevToken(&tok_it, &tree);
1541 continue;1525 continue;
1542 }1526 }
15431527
...@@ -1569,7 +1553,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1569,7 +1553,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1569 return tree;1553 return tree;
1570 }1554 }
15711555
1572 putBackToken(&tok_it, &tree);1556 prevToken(&tok_it, &tree);
1573 continue;1557 continue;
1574 }1558 }
15751559
...@@ -1606,7 +1590,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1606,7 +1590,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1606 return tree;1590 return tree;
1607 }1591 }
16081592
1609 putBackToken(&tok_it, &tree);1593 prevToken(&tok_it, &tree);
1610 continue;1594 continue;
1611 }1595 }
16121596
...@@ -1691,7 +1675,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1691,7 +1675,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1691 },1675 },
1692 else => {1676 else => {
1693 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {1677 if (!try parseBlockExpr(&stack, arena, opt_ctx, token_ptr, token_index)) {
1694 putBackToken(&tok_it, &tree);1678 prevToken(&tok_it, &tree);
1695 stack.append(State{ .UnwrapExpressionBegin = opt_ctx }) catch unreachable;1679 stack.append(State{ .UnwrapExpressionBegin = opt_ctx }) catch unreachable;
1696 }1680 }
1697 continue;1681 continue;
...@@ -1744,7 +1728,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1744,7 +1728,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1744 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } });1728 try stack.append(State{ .Expression = OptionalCtx{ .Required = &node.rhs } });
1745 continue;1729 continue;
1746 } else {1730 } else {
1747 putBackToken(&tok_it, &tree);1731 prevToken(&tok_it, &tree);
1748 continue;1732 continue;
1749 }1733 }
1750 },1734 },
...@@ -1779,7 +1763,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1779,7 +1763,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1779 }1763 }
1780 continue;1764 continue;
1781 } else {1765 } else {
1782 putBackToken(&tok_it, &tree);1766 prevToken(&tok_it, &tree);
1783 continue;1767 continue;
1784 }1768 }
1785 },1769 },
...@@ -1857,7 +1841,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1857,7 +1841,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1857 try stack.append(State{ .BinaryOrExpressionBegin = OptionalCtx{ .Required = &node.rhs } });1841 try stack.append(State{ .BinaryOrExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
1858 continue;1842 continue;
1859 } else {1843 } else {
1860 putBackToken(&tok_it, &tree);1844 prevToken(&tok_it, &tree);
1861 continue;1845 continue;
1862 }1846 }
1863 },1847 },
...@@ -1959,7 +1943,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1959,7 +1943,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1959 try stack.append(State{ .AdditionExpressionBegin = OptionalCtx{ .Required = &node.rhs } });1943 try stack.append(State{ .AdditionExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
1960 continue;1944 continue;
1961 } else {1945 } else {
1962 putBackToken(&tok_it, &tree);1946 prevToken(&tok_it, &tree);
1963 continue;1947 continue;
1964 }1948 }
1965 },1949 },
...@@ -1989,7 +1973,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -1989,7 +1973,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
1989 try stack.append(State{ .MultiplyExpressionBegin = OptionalCtx{ .Required = &node.rhs } });1973 try stack.append(State{ .MultiplyExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
1990 continue;1974 continue;
1991 } else {1975 } else {
1992 putBackToken(&tok_it, &tree);1976 prevToken(&tok_it, &tree);
1993 continue;1977 continue;
1994 }1978 }
1995 },1979 },
...@@ -2019,7 +2003,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2019,7 +2003,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2019 try stack.append(State{ .CurlySuffixExpressionBegin = OptionalCtx{ .Required = &node.rhs } });2003 try stack.append(State{ .CurlySuffixExpressionBegin = OptionalCtx{ .Required = &node.rhs } });
2020 continue;2004 continue;
2021 } else {2005 } else {
2022 putBackToken(&tok_it, &tree);2006 prevToken(&tok_it, &tree);
2023 continue;2007 continue;
2024 }2008 }
2025 },2009 },
...@@ -2124,7 +2108,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2124,7 +2108,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2124 }2108 }
2125 continue;2109 continue;
2126 } else {2110 } else {
2127 putBackToken(&tok_it, &tree);2111 prevToken(&tok_it, &tree);
2128 stack.append(State{ .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;2112 stack.append(State{ .SuffixOpExpressionBegin = opt_ctx }) catch unreachable;
2129 continue;2113 continue;
2130 }2114 }
...@@ -2220,7 +2204,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2220,7 +2204,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2220 continue;2204 continue;
2221 },2205 },
2222 else => {2206 else => {
2223 putBackToken(&tok_it, &tree);2207 prevToken(&tok_it, &tree);
2224 continue;2208 continue;
2225 },2209 },
2226 }2210 }
...@@ -2277,7 +2261,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2277,7 +2261,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2277 const next_token_index = next_token.index;2261 const next_token_index = next_token.index;
2278 const next_token_ptr = next_token.ptr;2262 const next_token_ptr = next_token.ptr;
2279 if (next_token_ptr.id != Token.Id.Arrow) {2263 if (next_token_ptr.id != Token.Id.Arrow) {
2280 putBackToken(&tok_it, &tree);2264 prevToken(&tok_it, &tree);
2281 continue;2265 continue;
2282 }2266 }
2283 node.result = ast.Node.PromiseType.Result{2267 node.result = ast.Node.PromiseType.Result{
...@@ -2348,8 +2332,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2348,8 +2332,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2348 Token.Id.Keyword_packed => {2332 Token.Id.Keyword_packed => {
2349 stack.append(State{ .ContainerKind = ContainerKindCtx{2333 stack.append(State{ .ContainerKind = ContainerKindCtx{
2350 .opt_ctx = opt_ctx,2334 .opt_ctx = opt_ctx,
2351 .ltoken = token.index,2335 .layout_token = token.index,
2352 .layout = ast.Node.ContainerDecl.Layout.Packed,
2353 } }) catch unreachable;2336 } }) catch unreachable;
2354 continue;2337 continue;
2355 },2338 },
...@@ -2364,11 +2347,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2364,11 +2347,10 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2364 Token.Id.Keyword_struct,2347 Token.Id.Keyword_struct,
2365 Token.Id.Keyword_union,2348 Token.Id.Keyword_union,
2366 Token.Id.Keyword_enum => {2349 Token.Id.Keyword_enum => {
2367 putBackToken(&tok_it, &tree);2350 prevToken(&tok_it, &tree);
2368 stack.append(State{ .ContainerKind = ContainerKindCtx{2351 stack.append(State{ .ContainerKind = ContainerKindCtx{
2369 .opt_ctx = opt_ctx,2352 .opt_ctx = opt_ctx,
2370 .ltoken = token.index,2353 .layout_token = null,
2371 .layout = ast.Node.ContainerDecl.Layout.Auto,
2372 } }) catch unreachable;2354 } }) catch unreachable;
2373 continue;2355 continue;
2374 },2356 },
...@@ -2466,7 +2448,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2466,7 +2448,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2466 },2448 },
2467 else => {2449 else => {
2468 if (!try parseBlockExpr(&stack, arena, opt_ctx, token.ptr, token.index)) {2450 if (!try parseBlockExpr(&stack, arena, opt_ctx, token.ptr, token.index)) {
2469 putBackToken(&tok_it, &tree);2451 prevToken(&tok_it, &tree);
2470 if (opt_ctx != OptionalCtx.Optional) {2452 if (opt_ctx != OptionalCtx.Optional) {
2471 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token.index } };2453 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token.index } };
2472 return tree;2454 return tree;
...@@ -2502,7 +2484,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2502,7 +2484,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2502 const token_index = token.index;2484 const token_index = token.index;
2503 const token_ptr = token.ptr;2485 const token_ptr = token.ptr;
2504 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) ?? {2486 opt_ctx.store((try parseStringLiteral(arena, &tok_it, token_ptr, token_index, &tree)) ?? {
2505 putBackToken(&tok_it, &tree);2487 prevToken(&tok_it, &tree);
2506 if (opt_ctx != OptionalCtx.Optional) {2488 if (opt_ctx != OptionalCtx.Optional) {
2507 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token_index } };2489 ((try tree.errors.addOne())).* = Error{ .ExpectedPrimaryExpr = Error.ExpectedPrimaryExpr{ .token = token_index } };
2508 return tree;2490 return tree;
...@@ -2576,7 +2558,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {...@@ -2576,7 +2558,7 @@ pub fn parse(allocator: &mem.Allocator, source: []const u8) !ast.Tree {
2576 } };2558 } };
2577 return tree;2559 return tree;
2578 }2560 }
2579 (expect_token_save.ptr).* = token_index;2561 expect_token_save.ptr.* = token_index;
2580 continue;2562 continue;
2581 },2563 },
2582 State.IfToken => |token_id| {2564 State.IfToken => |token_id| {
...@@ -2645,8 +2627,7 @@ const ExternTypeCtx = struct {...@@ -2645,8 +2627,7 @@ const ExternTypeCtx = struct {
26452627
2646const ContainerKindCtx = struct {2628const ContainerKindCtx = struct {
2647 opt_ctx: OptionalCtx,2629 opt_ctx: OptionalCtx,
2648 ltoken: TokenIndex,2630 layout_token: ?TokenIndex,
2649 layout: ast.Node.ContainerDecl.Layout,
2650};2631};
26512632
2652const ExpectTokenSave = struct {2633const ExpectTokenSave = struct {
...@@ -2808,9 +2789,9 @@ const State = union(enum) {...@@ -2808,9 +2789,9 @@ const State = union(enum) {
2808 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),2789 ErrorTagListCommaOrEnd: ListSave(ast.Node.ErrorSetDecl.DeclList),
2809 SwitchCaseOrEnd: ListSave(ast.Node.Switch.CaseList),2790 SwitchCaseOrEnd: ListSave(ast.Node.Switch.CaseList),
2810 SwitchCaseCommaOrEnd: ListSave(ast.Node.Switch.CaseList),2791 SwitchCaseCommaOrEnd: ListSave(ast.Node.Switch.CaseList),
2811 SwitchCaseFirstItem: &ast.Node.SwitchCase.ItemList,2792 SwitchCaseFirstItem: &ast.Node.SwitchCase,
2812 SwitchCaseItem: &ast.Node.SwitchCase.ItemList,2793 SwitchCaseItem: &ast.Node.SwitchCase,
2813 SwitchCaseItemCommaOrEnd: &ast.Node.SwitchCase.ItemList,2794 SwitchCaseItemCommaOrEnd: &ast.Node.SwitchCase,
28142795
2815 SuspendBody: &ast.Node.Suspend,2796 SuspendBody: &ast.Node.Suspend,
2816 AsyncAllocator: &ast.Node.AsyncAttribute,2797 AsyncAllocator: &ast.Node.AsyncAttribute,
...@@ -2899,14 +2880,6 @@ fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, t...@@ -2899,14 +2880,6 @@ fn eatDocComments(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, t
2899 return result;2880 return result;
2900}2881}
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
2910fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, token_ptr: &const Token, token_index: TokenIndex, tree: &ast.Tree) !?&ast.Node {2883fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterator, token_ptr: &const Token, token_index: TokenIndex, tree: &ast.Tree) !?&ast.Node {
2911 switch (token_ptr.id) {2884 switch (token_ptr.id) {
2912 Token.Id.StringLiteral => {2885 Token.Id.StringLiteral => {
...@@ -2923,7 +2896,7 @@ fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterato...@@ -2923,7 +2896,7 @@ fn parseStringLiteral(arena: &mem.Allocator, tok_it: &ast.Tree.TokenList.Iterato
2923 const multiline_str_index = multiline_str.index;2896 const multiline_str_index = multiline_str.index;
2924 const multiline_str_ptr = multiline_str.ptr;2897 const multiline_str_ptr = multiline_str.ptr;
2925 if (multiline_str_ptr.id != Token.Id.MultilineStringLiteralLine) {2898 if (multiline_str_ptr.id != Token.Id.MultilineStringLiteralLine) {
2926 putBackToken(tok_it, tree);2899 prevToken(tok_it, tree);
2927 break;2900 break;
2928 }2901 }
29292902
...@@ -3176,11 +3149,12 @@ fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, compti...@@ -3176,11 +3149,12 @@ fn createToCtxLiteral(arena: &mem.Allocator, opt_ctx: &const OptionalCtx, compti
3176}3149}
31773150
3178fn eatToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree, id: @TagType(Token.Id)) ?TokenIndex {3151fn 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);
3184 return null;3158 return null;
3185}3159}
31863160
...@@ -3189,27 +3163,20 @@ fn nextToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) AnnotatedTok...@@ -3189,27 +3163,20 @@ fn nextToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) AnnotatedTok
3189 .index = tok_it.index,3163 .index = tok_it.index,
3190 .ptr = ??tok_it.next(),3164 .ptr = ??tok_it.next(),
3191 };3165 };
3192 // possibly skip a following same line token3166 assert(result.ptr.id != Token.Id.LineComment);
3193 const token = tok_it.next() ?? return result;3167
3194 if (token.id != Token.Id.LineComment) {3168 while (true) {
3195 putBackToken(tok_it, tree);3169 const next_tok = tok_it.peek() ?? return result;
3196 return result;3170 if (next_tok.id != Token.Id.LineComment) return result;
3197 }3171 _ = tok_it.next();
3198 const loc = tree.tokenLocationPtr(result.ptr.end, token);
3199 if (loc.line != 0) {
3200 putBackToken(tok_it, tree);
3201 }3172 }
3202 return result;
3203}3173}
32043174
3205fn putBackToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) void {3175fn prevToken(tok_it: &ast.Tree.TokenList.Iterator, tree: &ast.Tree) void {
3206 const prev_tok = ??tok_it.prev();3176 while (true) {
3207 if (prev_tok.id == Token.Id.LineComment) {3177 const prev_tok = tok_it.prev() ?? return;
3208 const minus2_tok = tok_it.prev() ?? return;3178 if (prev_tok.id == Token.Id.LineComment) continue;
3209 const loc = tree.tokenLocationPtr(minus2_tok.end, prev_tok);3179 return;
3210 if (loc.line != 0) {
3211 _ = tok_it.next();
3212 }
3213 }3180 }
3214}3181}
32153182
std/zig/parser_test.zig+74-15
...@@ -1,3 +1,64 @@...@@ -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
1test "zig fmt: ptr deref operator" {62test "zig fmt: ptr deref operator" {
2 try testCanonical(63 try testCanonical(
3 \\const a = b.*;64 \\const a = b.*;
...@@ -7,6 +68,13 @@ test "zig fmt: ptr deref operator" {...@@ -7,6 +68,13 @@ test "zig fmt: ptr deref operator" {
768
8test "zig fmt: comment after if before another if" {69test "zig fmt: comment after if before another if" {
9 try testCanonical(70 try testCanonical(
71 \\test "aoeu" {
72 \\ // comment
73 \\ if (x) {
74 \\ bar();
75 \\ }
76 \\}
77 \\
10 \\test "aoeu" {78 \\test "aoeu" {
11 \\ if (x) {79 \\ if (x) {
12 \\ foo();80 \\ foo();
...@@ -21,7 +89,7 @@ test "zig fmt: comment after if before another if" {...@@ -21,7 +89,7 @@ test "zig fmt: comment after if before another if" {
21}89}
2290
23test "zig fmt: line comment between if block and else keyword" {91test "zig fmt: line comment between if block and else keyword" {
24 try testTransform(92 try testCanonical(
25 \\test "aoeu" {93 \\test "aoeu" {
26 \\ // cexp(finite|nan +- i inf|nan) = nan + i nan94 \\ // cexp(finite|nan +- i inf|nan) = nan + i nan
27 \\ if ((hx & 0x7fffffff) != 0x7f800000) {95 \\ if ((hx & 0x7fffffff) != 0x7f800000) {
...@@ -37,20 +105,6 @@ test "zig fmt: line comment between if block and else keyword" {...@@ -37,20 +105,6 @@ test "zig fmt: line comment between if block and else keyword" {
37 \\ return Complex(f32).new(x, y - y);105 \\ return Complex(f32).new(x, y - y);
38 \\ }106 \\ }
39 \\}107 \\}
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 \\}
54 \\108 \\
55 );109 );
56}110}
...@@ -652,6 +706,11 @@ test "zig fmt: multiline string" {...@@ -652,6 +706,11 @@ test "zig fmt: multiline string" {
652 \\ c\\two)706 \\ c\\two)
653 \\ c\\three707 \\ c\\three
654 \\ ;708 \\ ;
709 \\ const s3 = // hi
710 \\ \\one
711 \\ \\two)
712 \\ \\three
713 \\ ;
655 \\}714 \\}
656 \\715 \\
657 );716 );
std/zig/render.zig+674-498
...@@ -19,17 +19,21 @@ pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) (@typeOf(...@@ -19,17 +19,21 @@ pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) (@typeOf(
19 while (it.next()) |decl| {19 while (it.next()) |decl| {
20 try renderTopLevelDecl(allocator, stream, tree, 0, decl.*);20 try renderTopLevelDecl(allocator, stream, tree, 0, decl.*);
21 if (it.peek()) |next_decl| {21 if (it.peek()) |next_decl| {
22 const n = if (nodeLineOffset(tree, decl.*, next_decl.*) >= 2) u8(2) else u8(1);22 try renderExtraNewline(tree, stream, next_decl.*);
23 try stream.writeByteNTimes('\n', n);
24 }23 }
25 }24 }
26 try stream.write("\n");
27}25}
2826
29fn nodeLineOffset(tree: &ast.Tree, a: &ast.Node, b: &ast.Node) usize {27fn renderExtraNewline(tree: &ast.Tree, stream: var, node: &ast.Node) !void {
30 const a_last_token = tree.tokens.at(a.lastToken());28 var first_token = node.firstToken();
31 const loc = tree.tokenLocation(a_last_token.end, b.firstToken());29 while (tree.tokens.at(first_token - 1).id == Token.Id.DocComment) {
32 return loc.line;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 }
33}37}
3438
35fn renderTopLevelDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, decl: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {39fn 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...@@ -37,119 +41,124 @@ fn renderTopLevelDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, i
37 ast.Node.Id.FnProto => {41 ast.Node.Id.FnProto => {
38 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);42 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
3943
40 try renderComments(tree, stream, fn_proto, indent);44 try renderDocComments(tree, stream, fn_proto, indent);
41 try renderExpression(allocator, stream, tree, indent, decl);
4245
43 if (fn_proto.body_node) |body_node| {46 if (fn_proto.body_node) |body_node| {
44 try stream.write(" ");47 try renderExpression(allocator, stream, tree, indent, decl, Space.Space);
45 try renderExpression(allocator, stream, tree, indent, body_node);48 try renderExpression(allocator, stream, tree, indent, body_node, Space.Newline);
46 } else {49 } 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);
48 }52 }
49 },53 },
54
50 ast.Node.Id.Use => {55 ast.Node.Id.Use => {
51 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);56 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
5257
53 if (use_decl.visib_token) |visib_token| {58 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
55 }60 }
56 try stream.write("use ");61 try renderToken(tree, stream, use_decl.use_token, indent, Space.Space); // use
57 try renderExpression(allocator, stream, tree, indent, use_decl.expr);62 try renderExpression(allocator, stream, tree, indent, use_decl.expr, Space.None);
58 try stream.write(";");63 try renderToken(tree, stream, use_decl.semicolon_token, indent, Space.Newline); // ;
59 },64 },
65
60 ast.Node.Id.VarDecl => {66 ast.Node.Id.VarDecl => {
61 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);67 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);
64 try renderVarDecl(allocator, stream, tree, indent, var_decl);70 try renderVarDecl(allocator, stream, tree, indent, var_decl);
65 },71 },
72
66 ast.Node.Id.TestDecl => {73 ast.Node.Id.TestDecl => {
67 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);74 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
6875
69 try renderComments(tree, stream, test_decl, indent);76 try renderDocComments(tree, stream, test_decl, indent);
70 try stream.write("test ");77 try renderToken(tree, stream, test_decl.test_token, indent, Space.Space);
71 try renderExpression(allocator, stream, tree, indent, test_decl.name);78 try renderExpression(allocator, stream, tree, indent, test_decl.name, Space.Space);
72 try stream.write(" ");79 try renderExpression(allocator, stream, tree, indent, test_decl.body_node, Space.Newline);
73 try renderExpression(allocator, stream, tree, indent, test_decl.body_node);
74 },80 },
81
75 ast.Node.Id.StructField => {82 ast.Node.Id.StructField => {
76 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);83 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
7784
78 try renderComments(tree, stream, field, indent);85 try renderDocComments(tree, stream, field, indent);
79 if (field.visib_token) |visib_token| {86 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
81 }88 }
82 try stream.print("{}: ", tree.tokenSlice(field.name_token));89 try renderToken(tree, stream, field.name_token, indent, Space.None); // name
83 try renderExpression(allocator, stream, tree, indent, field.type_expr);90 try renderToken(tree, stream, tree.nextToken(field.name_token), indent, Space.Space); // :
84 try renderToken(tree, stream, field.lastToken() + 1, indent, true, true);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); // ,
85 },93 },
94
86 ast.Node.Id.UnionTag => {95 ast.Node.Id.UnionTag => {
87 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);96 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
8897
89 try renderComments(tree, stream, tag, indent);98 try renderDocComments(tree, stream, tag, indent);
90 try stream.print("{}", tree.tokenSlice(tag.name_token));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
92 if (tag.type_expr) |type_expr| {103 if (tag.type_expr) |type_expr| {
93 try stream.print(": ");104 try renderToken(tree, stream, tree.nextToken(tag.name_token), indent, Space.Space); // :
94 try renderExpression(allocator, stream, tree, indent, type_expr);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);
95 }108 }
96109
97 if (tag.value_expr) |value_expr| {110 if (tag.value_expr) |value_expr| {
98 try stream.print(" = ");111 try renderToken(tree, stream, tree.prevToken(value_expr.firstToken()), indent, Space.Space); // =
99 try renderExpression(allocator, stream, tree, indent, value_expr);112 try renderExpression(allocator, stream, tree, indent, value_expr, Space.None);
100 }113 }
101114
102 try stream.write(",");115 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, Space.Newline); // ,
103 },116 },
117
104 ast.Node.Id.EnumTag => {118 ast.Node.Id.EnumTag => {
105 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);119 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
106120
107 try renderComments(tree, stream, tag, indent);121 try renderDocComments(tree, stream, tag, indent);
108 try stream.print("{}", tree.tokenSlice(tag.name_token));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
110 if (tag.value) |value| {126 if (tag.value) |value| {
111 try stream.print(" = ");127 try renderToken(tree, stream, tree.nextToken(tag.name_token), indent, Space.Space); // =
112 try renderExpression(allocator, stream, tree, indent, value);128 try renderExpression(allocator, stream, tree, indent, value, Space.None);
113 }129 }
114130
115 try stream.write(",");131 try renderToken(tree, stream, tree.nextToken(decl.lastToken()), indent, Space.Newline); // ,
116 },132 },
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 },
123 ast.Node.Id.Comptime => {134 ast.Node.Id.Comptime => {
124 try renderExpression(allocator, stream, tree, indent, decl);135 assert(!decl.requireSemiColon());
125 try maybeRenderSemicolon(stream, tree, indent, decl);136 try renderExpression(allocator, stream, tree, indent, decl, Space.Newline);
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));
131 },137 },
132 else => unreachable,138 else => unreachable,
133 }139 }
134}140}
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 {
137 switch (base.id) {143 switch (base.id) {
138 ast.Node.Id.Identifier => {144 ast.Node.Id.Identifier => {
139 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);145 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);
141 },147 },
142 ast.Node.Id.Block => {148 ast.Node.Id.Block => {
143 const block = @fieldParentPtr(ast.Node.Block, "base", base);149 const block = @fieldParentPtr(ast.Node.Block, "base", base);
150
144 if (block.label) |label| {151 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);
146 }154 }
147155
148 if (block.statements.len == 0) {156 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);
150 } else {159 } else {
151 try stream.write("{\n");
152 const block_indent = indent + indent_delta;160 const block_indent = indent + indent_delta;
161 try renderToken(tree, stream, block.lbrace, block_indent, Space.Newline);
153162
154 var it = block.statements.iterator(0);163 var it = block.statements.iterator(0);
155 while (it.next()) |statement| {164 while (it.next()) |statement| {
...@@ -157,114 +166,85 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -157,114 +166,85 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
157 try renderStatement(allocator, stream, tree, block_indent, statement.*);166 try renderStatement(allocator, stream, tree, block_indent, statement.*);
158167
159 if (it.peek()) |next_statement| {168 if (it.peek()) |next_statement| {
160 const n = if (nodeLineOffset(tree, statement.*, next_statement.*) >= 2) u8(2) else u8(1);169 try renderExtraNewline(tree, stream, next_statement.*);
161 try stream.writeByteNTimes('\n', n);
162 }170 }
163 }171 }
164172
165 try stream.write("\n");
166 try stream.writeByteNTimes(' ', indent);173 try stream.writeByteNTimes(' ', indent);
167 try stream.write("}");174 try renderToken(tree, stream, block.rbrace, indent, space);
168 }175 }
169 },176 },
170 ast.Node.Id.Defer => {177 ast.Node.Id.Defer => {
171 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);178 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
172 try stream.print("{} ", tree.tokenSlice(defer_node.defer_token));179
173 try renderExpression(allocator, stream, tree, indent, defer_node.expr);180 try renderToken(tree, stream, defer_node.defer_token, indent, Space.Space);
181 try renderExpression(allocator, stream, tree, indent, defer_node.expr, space);
174 },182 },
175 ast.Node.Id.Comptime => {183 ast.Node.Id.Comptime => {
176 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);184 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
177 try stream.print("{} ", tree.tokenSlice(comptime_node.comptime_token));185
178 try renderExpression(allocator, stream, tree, indent, comptime_node.expr);186 try renderToken(tree, stream, comptime_node.comptime_token, indent, Space.Space);
187 try renderExpression(allocator, stream, tree, indent, comptime_node.expr, space);
179 },188 },
189
180 ast.Node.Id.AsyncAttribute => {190 ast.Node.Id.AsyncAttribute => {
181 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);191 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
182 try stream.print("{}", tree.tokenSlice(async_attr.async_token));
183192
184 if (async_attr.allocator_type) |allocator_type| {193 if (async_attr.allocator_type) |allocator_type| {
185 try stream.write("<");194 try renderToken(tree, stream, async_attr.async_token, indent, Space.None);
186 try renderExpression(allocator, stream, tree, indent, allocator_type);195
187 try stream.write(">");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);
188 }201 }
189 },202 },
203
190 ast.Node.Id.Suspend => {204 ast.Node.Id.Suspend => {
191 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);205 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
206
192 if (suspend_node.label) |label| {207 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);
194 }210 }
195 try stream.print("{}", tree.tokenSlice(suspend_node.suspend_token));
196211
197 if (suspend_node.payload) |payload| {212 if (suspend_node.payload) |payload| {
198 try stream.write(" ");213 if (suspend_node.body) |body| {
199 try renderExpression(allocator, stream, tree, indent, payload);214 try renderToken(tree, stream, suspend_node.suspend_token, indent, Space.Space);
200 }215 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
201216 try renderExpression(allocator, stream, tree, indent, body, space);
202 if (suspend_node.body) |body| {217 } else {
203 try stream.write(" ");218 try renderToken(tree, stream, suspend_node.suspend_token, indent, Space.Space);
204 try renderExpression(allocator, stream, tree, indent, body);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);
205 }226 }
206 },227 },
207228
208 ast.Node.Id.InfixOp => {229 ast.Node.Id.InfixOp => {
209 const infix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);230 const infix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
210231
211 try renderExpression(allocator, stream, tree, indent, infix_op_node.lhs);232 const op_token = tree.tokens.at(infix_op_node.op_token);
212233 const op_space = switch (infix_op_node.op) {
213 const text = switch (infix_op_node.op) {234 ast.Node.InfixOp.Op.Period, ast.Node.InfixOp.Op.ErrorUnion => Space.None,
214 ast.Node.InfixOp.Op.Add => " + ",235 else => Space.Space,
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 },
264 };236 };
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);247 try renderExpression(allocator, stream, tree, indent, infix_op_node.rhs, space);
267 try renderExpression(allocator, stream, tree, indent, infix_op_node.rhs);
268 },248 },
269249
270 ast.Node.Id.PrefixOp => {250 ast.Node.Id.PrefixOp => {
...@@ -272,52 +252,73 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -272,52 +252,73 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
272252
273 switch (prefix_op_node.op) {253 switch (prefix_op_node.op) {
274 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {254 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); // &
276 if (addr_of_info.align_expr) |align_expr| {256 if (addr_of_info.align_expr) |align_expr| {
277 try stream.write("align(");257 const align_token = tree.nextToken(prefix_op_node.op_token);
278 try renderExpression(allocator, stream, tree, indent, align_expr);258 try renderToken(tree, stream, align_token, indent, Space.None); // align
279 try stream.write(") ");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); // )
280 }267 }
281 if (addr_of_info.const_token != null) {268 if (addr_of_info.const_token) |const_token| {
282 try stream.write("const ");269 try renderToken(tree, stream, const_token, indent, Space.Space); // const
283 }270 }
284 if (addr_of_info.volatile_token != null) {271 if (addr_of_info.volatile_token) |volatile_token| {
285 try stream.write("volatile ");272 try renderToken(tree, stream, volatile_token, indent, Space.Space); // volatile
286 }273 }
287 },274 },
288 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {275 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
290 if (addr_of_info.align_expr) |align_expr| {279 if (addr_of_info.align_expr) |align_expr| {
291 try stream.print("align(");280 const align_token = tree.nextToken(prefix_op_node.op_token);
292 try renderExpression(allocator, stream, tree, indent, align_expr);281 try renderToken(tree, stream, align_token, indent, Space.None); // align
293 try stream.print(") ");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); // )
294 }290 }
295 if (addr_of_info.const_token != null) {291 if (addr_of_info.const_token) |const_token| {
296 try stream.print("const ");292 try renderToken(tree, stream, const_token, indent, Space.Space);
297 }293 }
298 if (addr_of_info.volatile_token != null) {294 if (addr_of_info.volatile_token) |volatile_token| {
299 try stream.print("volatile ");295 try renderToken(tree, stream, volatile_token, indent, Space.Space);
300 }296 }
301 },297 },
302 ast.Node.PrefixOp.Op.ArrayType => |array_index| {298 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
303 try stream.print("[");299 try renderToken(tree, stream, prefix_op_node.op_token, indent, Space.None); // [
304 try renderExpression(allocator, stream, tree, indent, array_index);300 try renderExpression(allocator, stream, tree, indent, array_index, Space.None);
305 try stream.print("]");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);
306 },311 },
307 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),312
308 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),313 ast.Node.PrefixOp.Op.Try,
309 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),314 ast.Node.PrefixOp.Op.Await,
310 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),315 ast.Node.PrefixOp.Op.Cancel,
311 ast.Node.PrefixOp.Op.Try => try stream.write("try "),316 ast.Node.PrefixOp.Op.Resume => {
312 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),317 try renderToken(tree, stream, prefix_op_node.op_token, indent, Space.Space);
313 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),318 },
314 ast.Node.PrefixOp.Op.PointerType => try stream.write("*"),319 }
315 ast.Node.PrefixOp.Op.Await => try stream.write("await "),320
316 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),321 try renderExpression(allocator, stream, tree, indent, prefix_op_node.rhs, space);
317 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
318 }
319
320 try renderExpression(allocator, stream, tree, indent, prefix_op_node.rhs);
321 },322 },
322323
323 ast.Node.Id.SuffixOp => {324 ast.Node.Id.SuffixOp => {
...@@ -326,123 +327,139 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -326,123 +327,139 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
326 switch (suffix_op.op) {327 switch (suffix_op.op) {
327 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {328 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
328 if (call_info.async_attr) |async_attr| {329 if (call_info.async_attr) |async_attr| {
329 try renderExpression(allocator, stream, tree, indent, &async_attr.base);330 try renderExpression(allocator, stream, tree, indent, &async_attr.base, Space.Space);
330 try stream.write(" ");
331 }331 }
332332
333 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);333 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
334 try stream.write("(");334
335 const lparen = tree.nextToken(suffix_op.lhs.lastToken());
336 try renderToken(tree, stream, lparen, indent, Space.None);
335337
336 var it = call_info.params.iterator(0);338 var it = call_info.params.iterator(0);
337 while (it.next()) |param_node| {339 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
339 if (it.peek() != null) {342 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);
341 }345 }
342 }346 }
343347
344 try stream.write(")");348 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
345 },349 },
346350
347 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {351 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
348 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);352 const lbracket = tree.prevToken(index_expr.firstToken());
349 try stream.write("[");353 const rbracket = tree.nextToken(index_expr.lastToken());
350 try renderExpression(allocator, stream, tree, indent, index_expr);354
351 try stream.write("]");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); // ]
352 },359 },
353360
354 ast.Node.SuffixOp.Op.Deref => {361 ast.Node.SuffixOp.Op.Deref => {
355 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);362 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
356 try stream.write(".*");363 try renderToken(tree, stream, tree.prevToken(suffix_op.rtoken), indent, Space.None); // .
364 try renderToken(tree, stream, suffix_op.rtoken, indent, space); // *
357 },365 },
358366
359 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {367 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
360 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);368 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
361 try stream.write("[");369
362 try renderExpression(allocator, stream, tree, indent, range.start);370 const lbracket = tree.prevToken(range.start.firstToken());
363 try stream.write("..");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); // ..
364 if (range.end) |end| {376 if (range.end) |end| {
365 try renderExpression(allocator, stream, tree, indent, end);377 try renderExpression(allocator, stream, tree, indent, end, Space.None);
366 }378 }
367 try stream.write("]");379 try renderToken(tree, stream, suffix_op.rtoken, indent, space); // ]
368 },380 },
369381
370 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {382 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
383 const lbrace = tree.nextToken(suffix_op.lhs.lastToken());
384
371 if (field_inits.len == 0) {385 if (field_inits.len == 0) {
372 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);386 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
373 try stream.write("{}");387 try renderToken(tree, stream, lbrace, indent, Space.None);
388 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
374 return;389 return;
375 }390 }
376391
377 if (field_inits.len == 1) {392 if (field_inits.len == 1) {
378 const field_init = field_inits.at(0).*;393 const field_init = field_inits.at(0).*;
379394
380 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);395 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
381 try stream.write("{ ");396 try renderToken(tree, stream, lbrace, indent, Space.Space);
382 try renderExpression(allocator, stream, tree, indent, field_init);397 try renderExpression(allocator, stream, tree, indent, field_init, Space.Space);
383 try stream.write(" }");398 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
384 return;399 return;
385 }400 }
386401
387 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);402 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
388 try stream.write("{\n");403 try renderToken(tree, stream, lbrace, indent, Space.Newline);
389404
390 const new_indent = indent + indent_delta;405 const new_indent = indent + indent_delta;
391406
392 var it = field_inits.iterator(0);407 var it = field_inits.iterator(0);
393 while (it.next()) |field_init| {408 while (it.next()) |field_init| {
394 try stream.writeByteNTimes(' ', new_indent);409 try stream.writeByteNTimes(' ', new_indent);
395 try renderExpression(allocator, stream, tree, new_indent, field_init.*);410 try renderExpression(allocator, stream, tree, new_indent, field_init.*, Space.None);
396 if ((field_init.*).id != ast.Node.Id.LineComment) {411
397 try stream.write(",");412 const comma = tree.nextToken(field_init.*.lastToken());
398 }413 try renderToken(tree, stream, comma, new_indent, Space.Newline);
414
399 if (it.peek()) |next_field_init| {415 if (it.peek()) |next_field_init| {
400 const n = if (nodeLineOffset(tree, field_init.*, next_field_init.*) >= 2) u8(2) else u8(1);416 try renderExtraNewline(tree, stream, next_field_init.*);
401 try stream.writeByteNTimes('\n', n);
402 }417 }
403 }418 }
404419
405 try stream.write("\n");
406 try stream.writeByteNTimes(' ', indent);420 try stream.writeByteNTimes(' ', indent);
407 try stream.write("}");421 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
408 },422 },
409423
410 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {424 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
425 const lbrace = tree.nextToken(suffix_op.lhs.lastToken());
426
411 if (exprs.len == 0) {427 if (exprs.len == 0) {
412 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);428 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
413 try stream.write("{}");429 try renderToken(tree, stream, lbrace, indent, Space.None);
430 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
414 return;431 return;
415 }432 }
416 if (exprs.len == 1) {433 if (exprs.len == 1) {
417 const expr = exprs.at(0).*;434 const expr = exprs.at(0).*;
418435
419 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);436 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
420 try stream.write("{");437 try renderToken(tree, stream, lbrace, indent, Space.None);
421 try renderExpression(allocator, stream, tree, indent, expr);438 try renderExpression(allocator, stream, tree, indent, expr, Space.None);
422 try stream.write("}");439 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
423 return;440 return;
424 }441 }
425442
426 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);443 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs, Space.None);
427444
428 const new_indent = indent + indent_delta;445 const new_indent = indent + indent_delta;
429 try stream.write("{\n");446 try renderToken(tree, stream, lbrace, new_indent, Space.Newline);
430447
431 var it = exprs.iterator(0);448 var it = exprs.iterator(0);
432 while (it.next()) |expr| {449 while (it.next()) |expr| {
433 try stream.writeByteNTimes(' ', new_indent);450 try stream.writeByteNTimes(' ', new_indent);
434 try renderExpression(allocator, stream, tree, new_indent, expr.*);451 try renderExpression(allocator, stream, tree, new_indent, expr.*, Space.None);
435 try stream.write(",");452
453 const comma = tree.nextToken(expr.*.lastToken());
454 try renderToken(tree, stream, comma, new_indent, Space.Newline); // ,
436455
437 if (it.peek()) |next_expr| {456 if (it.peek()) |next_expr| {
438 const n = if (nodeLineOffset(tree, expr.*, next_expr.*) >= 2) u8(2) else u8(1);457 try renderExtraNewline(tree, stream, next_expr.*);
439 try stream.writeByteNTimes('\n', n);
440 }458 }
441 }459 }
442460
443 try stream.write("\n");
444 try stream.writeByteNTimes(' ', indent);461 try stream.writeByteNTimes(' ', indent);
445 try stream.write("}");462 try renderToken(tree, stream, suffix_op.rtoken, indent, space);
446 },463 },
447 }464 }
448 },465 },
...@@ -452,159 +469,182 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -452,159 +469,182 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
452469
453 switch (flow_expr.kind) {470 switch (flow_expr.kind) {
454 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {471 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);
456 if (maybe_label) |label| {474 if (maybe_label) |label| {
457 try stream.print(" :");475 const colon = tree.nextToken(flow_expr.ltoken);
458 try renderExpression(allocator, stream, tree, indent, label);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);
459 }480 }
460 },481 },
461 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {482 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);
463 if (maybe_label) |label| {485 if (maybe_label) |label| {
464 try stream.print(" :");486 const colon = tree.nextToken(flow_expr.ltoken);
465 try renderExpression(allocator, stream, tree, indent, label);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);
466 }491 }
467 },492 },
468 ast.Node.ControlFlowExpression.Kind.Return => {493 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);
470 },496 },
471 }497 }
472498
473 if (flow_expr.rhs) |rhs| {499 if (flow_expr.rhs) |rhs| {
474 try stream.write(" ");500 try renderExpression(allocator, stream, tree, indent, rhs, space);
475 try renderExpression(allocator, stream, tree, indent, rhs);
476 }501 }
477 },502 },
478503
479 ast.Node.Id.Payload => {504 ast.Node.Id.Payload => {
480 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);505 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
481506
482 try stream.write("|");507 try renderToken(tree, stream, payload.lpipe, indent, Space.None);
483 try renderExpression(allocator, stream, tree, indent, payload.error_symbol);508 try renderExpression(allocator, stream, tree, indent, payload.error_symbol, Space.None);
484 try stream.write("|");509 try renderToken(tree, stream, payload.rpipe, indent, space);
485 },510 },
486511
487 ast.Node.Id.PointerPayload => {512 ast.Node.Id.PointerPayload => {
488 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);513 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
489514
490 try stream.write("|");515 try renderToken(tree, stream, payload.lpipe, indent, Space.None);
491 if (payload.ptr_token) |ptr_token| {516 if (payload.ptr_token) |ptr_token| {
492 try stream.write(tree.tokenSlice(ptr_token));517 try renderToken(tree, stream, ptr_token, indent, Space.None);
493 }518 }
494 try renderExpression(allocator, stream, tree, indent, payload.value_symbol);519 try renderExpression(allocator, stream, tree, indent, payload.value_symbol, Space.None);
495 try stream.write("|");520 try renderToken(tree, stream, payload.rpipe, indent, space);
496 },521 },
497522
498 ast.Node.Id.PointerIndexPayload => {523 ast.Node.Id.PointerIndexPayload => {
499 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);524 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
500525
501 try stream.write("|");526 try renderToken(tree, stream, payload.lpipe, indent, Space.None);
502 if (payload.ptr_token) |ptr_token| {527 if (payload.ptr_token) |ptr_token| {
503 try stream.write(tree.tokenSlice(ptr_token));528 try renderToken(tree, stream, ptr_token, indent, Space.None);
504 }529 }
505 try renderExpression(allocator, stream, tree, indent, payload.value_symbol);530 try renderExpression(allocator, stream, tree, indent, payload.value_symbol, Space.None);
506531
507 if (payload.index_symbol) |index_symbol| {532 if (payload.index_symbol) |index_symbol| {
508 try stream.write(", ");533 const comma = tree.nextToken(payload.value_symbol.lastToken());
509 try renderExpression(allocator, stream, tree, indent, index_symbol);534
535 try renderToken(tree, stream, comma, indent, Space.Space);
536 try renderExpression(allocator, stream, tree, indent, index_symbol, Space.None);
510 }537 }
511538
512 try stream.write("|");539 try renderToken(tree, stream, payload.rpipe, indent, space);
513 },540 },
514541
515 ast.Node.Id.GroupedExpression => {542 ast.Node.Id.GroupedExpression => {
516 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);543 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
517544
518 try renderToken(tree, stream, grouped_expr.lparen, indent, false, false);545 try renderToken(tree, stream, grouped_expr.lparen, indent, Space.None);
519 try renderExpression(allocator, stream, tree, indent, grouped_expr.expr);546 try renderExpression(allocator, stream, tree, indent, grouped_expr.expr, Space.None);
520 try renderToken(tree, stream, grouped_expr.rparen, indent, false, false);547 try renderToken(tree, stream, grouped_expr.rparen, indent, space);
521 },548 },
522549
523 ast.Node.Id.FieldInitializer => {550 ast.Node.Id.FieldInitializer => {
524 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);551 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
525552
526 try stream.print(".{} = ", tree.tokenSlice(field_init.name_token));553 try renderToken(tree, stream, field_init.period_token, indent, Space.None); // .
527 try renderExpression(allocator, stream, tree, indent, field_init.expr);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);
528 },557 },
529558
530 ast.Node.Id.IntegerLiteral => {559 ast.Node.Id.IntegerLiteral => {
531 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);560 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);
533 },562 },
534 ast.Node.Id.FloatLiteral => {563 ast.Node.Id.FloatLiteral => {
535 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);564 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);
537 },566 },
538 ast.Node.Id.StringLiteral => {567 ast.Node.Id.StringLiteral => {
539 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);568 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);
541 },570 },
542 ast.Node.Id.CharLiteral => {571 ast.Node.Id.CharLiteral => {
543 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);572 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);
545 },574 },
546 ast.Node.Id.BoolLiteral => {575 ast.Node.Id.BoolLiteral => {
547 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);576 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);
549 },578 },
550 ast.Node.Id.NullLiteral => {579 ast.Node.Id.NullLiteral => {
551 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);580 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);
553 },582 },
554 ast.Node.Id.ThisLiteral => {583 ast.Node.Id.ThisLiteral => {
555 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);584 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);
557 },586 },
558 ast.Node.Id.Unreachable => {587 ast.Node.Id.Unreachable => {
559 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);588 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);
561 },590 },
562 ast.Node.Id.ErrorType => {591 ast.Node.Id.ErrorType => {
563 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);592 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);
565 },594 },
566 ast.Node.Id.VarType => {595 ast.Node.Id.VarType => {
567 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);596 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);
569 },598 },
570 ast.Node.Id.ContainerDecl => {599 ast.Node.Id.ContainerDecl => {
571 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);600 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
572601
573 switch (container_decl.layout) {602 if (container_decl.layout_token) |layout_token| {
574 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),603 try renderToken(tree, stream, layout_token, indent, Space.Space);
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"),
583 }604 }
584605
585 switch (container_decl.init_arg_expr) {606 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 },
587 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {610 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
588 if (enum_tag_type) |expr| {619 if (enum_tag_type) |expr| {
589 try stream.write("(enum(");620 try renderToken(tree, stream, tree.nextToken(enum_token), indent, Space.None); // (
590 try renderExpression(allocator, stream, tree, indent, expr);621 try renderExpression(allocator, stream, tree, indent, expr, Space.None);
591 try stream.write(")) ");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); // )
592 } else {626 } else {
593 try stream.write("(enum) ");627 try renderToken(tree, stream, tree.nextToken(enum_token), indent, Space.Space); // )
594 }628 }
595 },629 },
596 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {630 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
597 try stream.write("(");631 try renderToken(tree, stream, container_decl.kind_token, indent, Space.None); // union
598 try renderExpression(allocator, stream, tree, indent, type_expr);632
599 try stream.write(") ");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); // )
600 },639 },
601 }640 }
602641
603 if (container_decl.fields_and_decls.len == 0) {642 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); // }
605 } else {645 } else {
606 try stream.write("{\n");
607 const new_indent = indent + indent_delta;646 const new_indent = indent + indent_delta;
647 try renderToken(tree, stream, container_decl.lbrace_token, new_indent, Space.Newline); // {
608648
609 var it = container_decl.fields_and_decls.iterator(0);649 var it = container_decl.fields_and_decls.iterator(0);
610 while (it.next()) |decl| {650 while (it.next()) |decl| {
...@@ -612,22 +652,24 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -612,22 +652,24 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
612 try renderTopLevelDecl(allocator, stream, tree, new_indent, decl.*);652 try renderTopLevelDecl(allocator, stream, tree, new_indent, decl.*);
613653
614 if (it.peek()) |next_decl| {654 if (it.peek()) |next_decl| {
615 const n = if (nodeLineOffset(tree, decl.*, next_decl.*) >= 2) u8(2) else u8(1);655 try renderExtraNewline(tree, stream, next_decl.*);
616 try stream.writeByteNTimes('\n', n);
617 }656 }
618 }657 }
619658
620 try stream.write("\n");
621 try stream.writeByteNTimes(' ', indent);659 try stream.writeByteNTimes(' ', indent);
622 try stream.write("}");660 try renderToken(tree, stream, container_decl.rbrace_token, indent, space); // }
623 }661 }
624 },662 },
625663
626 ast.Node.Id.ErrorSetDecl => {664 ast.Node.Id.ErrorSetDecl => {
627 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);665 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
628666
667 const lbrace = tree.nextToken(err_set_decl.error_token);
668
629 if (err_set_decl.decls.len == 0) {669 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);
631 return;673 return;
632 }674 }
633675
...@@ -642,62 +684,80 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -642,62 +684,80 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
642 break :blk;684 break :blk;
643 }685 }
644686
645 try stream.write("error{");687 try renderToken(tree, stream, err_set_decl.error_token, indent, Space.None); // error
646 try renderTopLevelDecl(allocator, stream, tree, indent, node);688 try renderToken(tree, stream, lbrace, indent, Space.None); // {
647 try stream.write("}");689 try renderExpression(allocator, stream, tree, indent, node, Space.None);
690 try renderToken(tree, stream, err_set_decl.rbrace_token, indent, space); // }
648 return;691 return;
649 }692 }
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); // {
652 const new_indent = indent + indent_delta;696 const new_indent = indent + indent_delta;
653697
654 var it = err_set_decl.decls.iterator(0);698 var it = err_set_decl.decls.iterator(0);
655 while (it.next()) |node| {699 while (it.next()) |node| {
656 try stream.writeByteNTimes(' ', new_indent);700 try stream.writeByteNTimes(' ', new_indent);
657 try renderTopLevelDecl(allocator, stream, tree, new_indent, node.*);701 try renderExpression(allocator, stream, tree, new_indent, node.*, Space.None);
658 if ((node.*).id != ast.Node.Id.LineComment) {702 try renderToken(tree, stream, tree.nextToken(node.*.lastToken()), new_indent, Space.Newline); // ,
659 try stream.write(",");703
660 }
661 if (it.peek()) |next_node| {704 if (it.peek()) |next_node| {
662 const n = if (nodeLineOffset(tree, node.*, next_node.*) >= 2) u8(2) else u8(1);705 try renderExtraNewline(tree, stream, next_node.*);
663 try stream.writeByteNTimes('\n', n);
664 }706 }
665 }707 }
666708
667 try stream.write("\n");
668 try stream.writeByteNTimes(' ', indent);709 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
670 },718 },
671719
672 ast.Node.Id.MultilineStringLiteral => {720 ast.Node.Id.MultilineStringLiteral => {
673 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);721 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
676 var i: usize = 0;729 var i: usize = 0;
677 while (i < multiline_str_literal.lines.len) : (i += 1) {730 while (i < multiline_str_literal.lines.len) : (i += 1) {
678 const t = multiline_str_literal.lines.at(i).*;731 const t = multiline_str_literal.lines.at(i).*;
679 try stream.writeByteNTimes(' ', indent + indent_delta);732 if (!skip_first_indent) {
680 try stream.print("{}", tree.tokenSlice(t));733 try stream.writeByteNTimes(' ', indent + indent_delta);
734 }
735 try renderToken(tree, stream, t, indent, Space.None);
736 skip_first_indent = false;
681 }737 }
682 try stream.writeByteNTimes(' ', indent);738 try stream.writeByteNTimes(' ', indent);
683 },739 },
684 ast.Node.Id.UndefinedLiteral => {740 ast.Node.Id.UndefinedLiteral => {
685 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);741 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);
687 },743 },
688744
689 ast.Node.Id.BuiltinCall => {745 ast.Node.Id.BuiltinCall => {
690 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);746 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
693 var it = builtin_call.params.iterator(0);751 var it = builtin_call.params.iterator(0);
694 while (it.next()) |param_node| {752 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
696 if (it.peek() != null) {755 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); // ,
698 }758 }
699 }759 }
700 try stream.write(")");760 try renderToken(tree, stream, builtin_call.rparen_token, indent, space); // )
701 },761 },
702762
703 ast.Node.Id.FnProto => {763 ast.Node.Id.FnProto => {
...@@ -706,108 +766,123 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -706,108 +766,123 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
706 if (fn_proto.visib_token) |visib_token_index| {766 if (fn_proto.visib_token) |visib_token_index| {
707 const visib_token = tree.tokens.at(visib_token_index);767 const visib_token = tree.tokens.at(visib_token_index);
708 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);768 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
710 }771 }
711772
712 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {773 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
714 }775 }
715776
716 if (fn_proto.lib_name) |lib_name| {777 if (fn_proto.lib_name) |lib_name| {
717 try renderExpression(allocator, stream, tree, indent, lib_name);778 try renderExpression(allocator, stream, tree, indent, lib_name, Space.Space);
718 try stream.write(" ");
719 }779 }
720780
721 if (fn_proto.cc_token) |cc_token| {781 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
723 }783 }
724784
725 if (fn_proto.async_attr) |async_attr| {785 if (fn_proto.async_attr) |async_attr| {
726 try renderExpression(allocator, stream, tree, indent, &async_attr.base);786 try renderExpression(allocator, stream, tree, indent, &async_attr.base, Space.Space);
727 try stream.write(" ");
728 }787 }
729788
730 try stream.write("fn");789 if (fn_proto.name_token) |name_token| blk: {
731790 try renderToken(tree, stream, fn_proto.fn_token, indent, Space.Space); // fn
732 if (fn_proto.name_token) |name_token| {791 try renderToken(tree, stream, name_token, indent, Space.None); // name
733 try stream.print(" {}", tree.tokenSlice(name_token));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); // (
734 }796 }
735797
736 try stream.write("(");
737
738 var it = fn_proto.params.iterator(0);798 var it = fn_proto.params.iterator(0);
739 while (it.next()) |param_decl_node| {799 while (it.next()) |param_decl_node| {
740 try renderParamDecl(allocator, stream, tree, indent, param_decl_node.*);800 try renderParamDecl(allocator, stream, tree, indent, param_decl_node.*);
741801
742 if (it.peek() != null) {802 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); // ,
744 }805 }
745 }806 }
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
749 if (fn_proto.align_expr) |align_expr| {814 if (fn_proto.align_expr) |align_expr| {
750 try stream.write("align(");815 const align_rparen = tree.nextToken(align_expr.lastToken());
751 try renderExpression(allocator, stream, tree, indent, align_expr);816 const align_lparen = tree.prevToken(align_expr.firstToken());
752 try stream.write(") ");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); // )
753 }823 }
754824
755 switch (fn_proto.return_type) {825 switch (fn_proto.return_type) {
756 ast.Node.FnProto.ReturnType.Explicit => |node| {826 ast.Node.FnProto.ReturnType.Explicit => |node| {
757 try renderExpression(allocator, stream, tree, indent, node);827 try renderExpression(allocator, stream, tree, indent, node, space);
758 },828 },
759 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {829 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
760 try stream.write("!");830 try renderToken(tree, stream, tree.prevToken(node.firstToken()), indent, Space.None); // !
761 try renderExpression(allocator, stream, tree, indent, node);831 try renderExpression(allocator, stream, tree, indent, node, space);
762 },832 },
763 }833 }
764 },834 },
765835
766 ast.Node.Id.PromiseType => {836 ast.Node.Id.PromiseType => {
767 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);837 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
768 try stream.write(tree.tokenSlice(promise_type.promise_token));838
769 if (promise_type.result) |result| {839 if (promise_type.result) |result| {
770 try stream.write(tree.tokenSlice(result.arrow_token));840 try renderToken(tree, stream, promise_type.promise_token, indent, Space.None); // promise
771 try renderExpression(allocator, stream, tree, indent, result.return_type);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
772 }845 }
773 },846 },
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
780 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes848 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
781849
782 ast.Node.Id.Switch => {850 ast.Node.Id.Switch => {
783 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);851 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
786 if (switch_node.cases.len == 0) {859 if (switch_node.cases.len == 0) {
787 try renderExpression(allocator, stream, tree, indent, switch_node.expr);860 try renderExpression(allocator, stream, tree, indent, switch_node.expr, Space.None);
788 try stream.write(") {}");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); // }
789 return;864 return;
790 }865 }
791866
792 try renderExpression(allocator, stream, tree, indent, switch_node.expr);867 try renderExpression(allocator, stream, tree, indent, switch_node.expr, Space.None);
793 try stream.write(") {\n");868
869 try renderToken(tree, stream, rparen, indent, Space.Space); // )
870 try renderToken(tree, stream, lbrace, indent, Space.Newline); // {
794871
795 const new_indent = indent + indent_delta;872 const new_indent = indent + indent_delta;
796873
797 var it = switch_node.cases.iterator(0);874 var it = switch_node.cases.iterator(0);
798 while (it.next()) |node| {875 while (it.next()) |node| {
799 try stream.writeByteNTimes(' ', new_indent);876 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
802 if (it.peek()) |next_node| {879 if (it.peek()) |next_node| {
803 const n = if (nodeLineOffset(tree, node.*, next_node.*) >= 2) u8(2) else u8(1);880 try renderExtraNewline(tree, stream, next_node.*);
804 try stream.writeByteNTimes('\n', n);
805 }881 }
806 }882 }
807883
808 try stream.write("\n");
809 try stream.writeByteNTimes(' ', indent);884 try stream.writeByteNTimes(' ', indent);
810 try stream.write("}");885 try renderToken(tree, stream, switch_node.rbrace, indent, space); // }
811 },886 },
812887
813 ast.Node.Id.SwitchCase => {888 ast.Node.Id.SwitchCase => {
...@@ -815,54 +890,50 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -815,54 +890,50 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
815890
816 var it = switch_case.items.iterator(0);891 var it = switch_case.items.iterator(0);
817 while (it.next()) |node| {892 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) {896 const comma_token = tree.nextToken(node.*.lastToken());
821 try stream.write(",\n");897 try renderToken(tree, stream, comma_token, indent, Space.Newline); // ,
898 try renderExtraNewline(tree, stream, next_node.*);
822 try stream.writeByteNTimes(' ', indent);899 try stream.writeByteNTimes(' ', indent);
900 } else {
901 try renderExpression(allocator, stream, tree, indent, node.*, Space.Space);
823 }902 }
824 }903 }
825904
826 try stream.write(" => ");905 try renderToken(tree, stream, switch_case.arrow_token, indent, Space.Space); // =>
827906
828 if (switch_case.payload) |payload| {907 if (switch_case.payload) |payload| {
829 try renderExpression(allocator, stream, tree, indent, payload);908 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
830 try stream.write(" ");
831 }909 }
832910
833 try renderExpression(allocator, stream, tree, indent, switch_case.expr);911 // add a trailing comma if necessary
834 {912 const end_token = switch_case.lastToken() + 1;
835 // Handle missing comma after last switch case913 switch (tree.tokens.at(end_token).id) {
836 var index = switch_case.lastToken() + 1;914 Token.Id.Comma => {
837 switch (tree.tokens.at(index).id) {915 try renderExpression(allocator, stream, tree, indent, switch_case.expr, Space.None);
838 Token.Id.RBrace => {916 try renderToken(tree, stream, end_token, indent, space); // ,
839 try stream.write(",");917 },
840 },918 Token.Id.LineComment => {
841 Token.Id.LineComment => {919 try renderExpression(allocator, stream, tree, indent, switch_case.expr, Space.NoComment);
842 try stream.write(", ");920 try stream.write(", ");
843 try renderToken(tree, stream, index, indent, true, true);921 try renderToken(tree, stream, end_token, indent, space);
844 },922 },
845 else => try renderToken(tree, stream, index, indent, true, true),923 else => {
846 }924 try renderExpression(allocator, stream, tree, indent, switch_case.expr, Space.None);
925 try stream.write(",\n");
926 assert(space == Space.Newline);
927 },
847 }928 }
848 },929 },
849 ast.Node.Id.SwitchElse => {930 ast.Node.Id.SwitchElse => {
850 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);931 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);
852 },933 },
853 ast.Node.Id.Else => {934 ast.Node.Id.Else => {
854 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);935 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
866 const block_body = switch (else_node.body.id) {937 const block_body = switch (else_node.body.id) {
867 ast.Node.Id.Block,938 ast.Node.Id.Block,
868 ast.Node.Id.If,939 ast.Node.Id.If,
...@@ -872,21 +943,19 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -872,21 +943,19 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
872 else => false,943 else => false,
873 };944 };
874945
875 if (block_body) {946 const after_else_space = if (block_body or else_node.payload != null) Space.Space else Space.Newline;
876 try stream.write(" ");947 try renderToken(tree, stream, else_node.else_token, indent, after_else_space);
877 }
878948
879 if (else_node.payload) |payload| {949 if (else_node.payload) |payload| {
880 try renderExpression(allocator, stream, tree, indent, payload);950 const payload_space = if (block_body) Space.Space else Space.Newline;
881 try stream.write(" ");951 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
882 }952 }
883953
884 if (block_body) {954 if (block_body) {
885 try renderExpression(allocator, stream, tree, indent, else_node.body);955 try renderExpression(allocator, stream, tree, indent, else_node.body, space);
886 } else {956 } else {
887 try stream.write("\n");
888 try stream.writeByteNTimes(' ', indent + indent_delta);957 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);
890 }959 }
891 },960 },
892961
...@@ -894,103 +963,134 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -894,103 +963,134 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
894 const while_node = @fieldParentPtr(ast.Node.While, "base", base);963 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
895964
896 if (while_node.label) |label| {965 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); // :
898 }968 }
899969
900 if (while_node.inline_token) |inline_token| {970 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
902 }972 }
903973
904 try stream.print("{} (", tree.tokenSlice(while_node.while_token));974 try renderToken(tree, stream, while_node.while_token, indent, Space.Space); // while
905 try renderExpression(allocator, stream, tree, indent, while_node.condition);975 try renderToken(tree, stream, tree.nextToken(while_node.while_token), indent, Space.None); // (
906 try stream.write(")");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
908 if (while_node.payload) |payload| {985 if (while_node.payload) |payload| {
909 try stream.write(" ");986 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
910 try renderExpression(allocator, stream, tree, indent, payload);
911 }987 }
912988
913 if (while_node.continue_expr) |continue_expr| {989 if (while_node.continue_expr) |continue_expr| {
914 try stream.write(" : (");990 const rparen = tree.nextToken(continue_expr.lastToken());
915 try renderExpression(allocator, stream, tree, indent, continue_expr);991 const lparen = tree.prevToken(continue_expr.firstToken());
916 try stream.write(")");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); // )
917 }1001 }
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
919 if (while_node.body.id == ast.Node.Id.Block) {1011 if (while_node.body.id == ast.Node.Id.Block) {
920 try stream.write(" ");1012 try renderExpression(allocator, stream, tree, indent, while_node.body, body_space);
921 try renderExpression(allocator, stream, tree, indent, while_node.body);
922 } else {1013 } else {
923 try stream.write("\n");
924 try stream.writeByteNTimes(' ', indent + indent_delta);1014 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);
926 }1016 }
9271017
928 if (while_node.@"else") |@"else"| {1018 if (while_node.@"else") |@"else"| {
929 if (while_node.body.id == ast.Node.Id.Block) {1019 if (while_node.body.id == ast.Node.Id.Block) {
930 try stream.write(" ");
931 } else {1020 } else {
932 try stream.write("\n");
933 try stream.writeByteNTimes(' ', indent);1021 try stream.writeByteNTimes(' ', indent);
934 }1022 }
9351023
936 try renderExpression(allocator, stream, tree, indent, &@"else".base);1024 try renderExpression(allocator, stream, tree, indent, &@"else".base, space);
937 }1025 }
938 },1026 },
9391027
940 ast.Node.Id.For => {1028 ast.Node.Id.For => {
941 const for_node = @fieldParentPtr(ast.Node.For, "base", base);1029 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
1030
942 if (for_node.label) |label| {1031 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); // :
944 }1034 }
9451035
946 if (for_node.inline_token) |inline_token| {1036 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
948 }1038 }
9491039
950 try stream.print("{} (", tree.tokenSlice(for_node.for_token));1040 try renderToken(tree, stream, for_node.for_token, indent, Space.Space); // for
951 try renderExpression(allocator, stream, tree, indent, for_node.array_expr);1041 try renderToken(tree, stream, tree.nextToken(for_node.for_token), indent, Space.None); // (
952 try stream.write(")");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
954 if (for_node.payload) |payload| {1049 if (for_node.payload) |payload| {
955 try stream.write(" ");1050 const payload_space = if (for_node.body.id == ast.Node.Id.Block) Space.Space else Space.Newline;
956 try renderExpression(allocator, stream, tree, indent, payload);1051 try renderExpression(allocator, stream, tree, indent, payload, payload_space);
957 }1052 }
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 };
959 if (for_node.body.id == ast.Node.Id.Block) {1065 if (for_node.body.id == ast.Node.Id.Block) {
960 try stream.write(" ");1066 try renderExpression(allocator, stream, tree, indent, for_node.body, body_space);
961 try renderExpression(allocator, stream, tree, indent, for_node.body);
962 } else {1067 } else {
963 try stream.write("\n");
964 try stream.writeByteNTimes(' ', indent + indent_delta);1068 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);
966 }1070 }
9671071
968 if (for_node.@"else") |@"else"| {1072 if (for_node.@"else") |@"else"| {
969 if (for_node.body.id == ast.Node.Id.Block) {1073 if (for_node.body.id != ast.Node.Id.Block) {
970 try stream.write(" ");
971 } else {
972 try stream.write("\n");
973 try stream.writeByteNTimes(' ', indent);1074 try stream.writeByteNTimes(' ', indent);
974 }1075 }
9751076
976 try renderExpression(allocator, stream, tree, indent, &@"else".base);1077 try renderExpression(allocator, stream, tree, indent, &@"else".base, space);
977 }1078 }
978 },1079 },
9791080
980 ast.Node.Id.If => {1081 ast.Node.Id.If => {
981 const if_node = @fieldParentPtr(ast.Node.If, "base", base);1082 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);1084 try renderToken(tree, stream, if_node.if_token, indent, Space.Space);
985 try renderToken(tree, stream, if_node.condition.lastToken() + 1, indent, false, true);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
987 if (if_node.payload) |payload| {1090 if (if_node.payload) |payload| {
988 try renderExpression(allocator, stream, tree, indent, payload);1091 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
989 try stream.write(" ");
990 }1092 }
9911093
992 try renderExpression(allocator, stream, tree, indent, if_node.body);
993
994 switch (if_node.body.id) {1094 switch (if_node.body.id) {
995 ast.Node.Id.Block,1095 ast.Node.Id.Block,
996 ast.Node.Id.If,1096 ast.Node.Id.If,
...@@ -999,25 +1099,29 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -999,25 +1099,29 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
999 ast.Node.Id.Switch => {1099 ast.Node.Id.Switch => {
1000 if (if_node.@"else") |@"else"| {1100 if (if_node.@"else") |@"else"| {
1001 if (if_node.body.id == ast.Node.Id.Block) {1101 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);
1003 } else {1103 } else {
1004 try stream.write("\n");1104 try renderExpression(allocator, stream, tree, indent, if_node.body, Space.Newline);
1005 try stream.writeByteNTimes(' ', indent);1105 try stream.writeByteNTimes(' ', indent);
1006 }1106 }
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);
1009 }1111 }
1010 },1112 },
1011 else => {1113 else => {
1012 if (if_node.@"else") |@"else"| {1114 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
1015 if (@"else".payload) |payload| {1118 if (@"else".payload) |payload| {
1016 try renderExpression(allocator, stream, tree, indent, payload);1119 try renderExpression(allocator, stream, tree, indent, payload, Space.Space);
1017 try stream.write(" ");
1018 }1120 }
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);
1021 }1125 }
1022 },1126 },
1023 }1127 }
...@@ -1025,15 +1129,17 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -1025,15 +1129,17 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
10251129
1026 ast.Node.Id.Asm => {1130 ast.Node.Id.Asm => {
1027 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);1131 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
1030 if (asm_node.volatile_token) |volatile_token| {1135 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); // (
1032 }1140 }
10331141
1034 try stream.print("(");1142 try renderExpression(allocator, stream, tree, indent, asm_node.template, Space.Newline);
1035 try renderExpression(allocator, stream, tree, indent, asm_node.template);
1036 try stream.print("\n");
1037 const indent_once = indent + indent_delta;1143 const indent_once = indent + indent_delta;
1038 try stream.writeByteNTimes(' ', indent_once);1144 try stream.writeByteNTimes(' ', indent_once);
1039 try stream.print(": ");1145 try stream.print(": ");
...@@ -1043,13 +1149,15 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -1043,13 +1149,15 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
1043 var it = asm_node.outputs.iterator(0);1149 var it = asm_node.outputs.iterator(0);
1044 while (it.next()) |asm_output| {1150 while (it.next()) |asm_output| {
1045 const node = &(asm_output.*).base;1151 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
1048 if (it.peek()) |next_asm_output| {1154 if (it.peek()) |next_asm_output| {
1049 const next_node = &(next_asm_output.*).base;1155 const next_node = &(next_asm_output.*).base;
1050 const n = if (nodeLineOffset(tree, node, next_node) >= 2) u8(2) else u8(1);1156
1051 try stream.writeByte(',');1157 const comma = tree.prevToken(next_asm_output.*.firstToken());
1052 try stream.writeByteNTimes('\n', n);1158 try renderToken(tree, stream, comma, indent_extra, Space.Newline); // ,
1159 try renderExtraNewline(tree, stream, next_node);
1160
1053 try stream.writeByteNTimes(' ', indent_extra);1161 try stream.writeByteNTimes(' ', indent_extra);
1054 }1162 }
1055 }1163 }
...@@ -1063,13 +1171,15 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -1063,13 +1171,15 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
1063 var it = asm_node.inputs.iterator(0);1171 var it = asm_node.inputs.iterator(0);
1064 while (it.next()) |asm_input| {1172 while (it.next()) |asm_input| {
1065 const node = &(asm_input.*).base;1173 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
1068 if (it.peek()) |next_asm_input| {1176 if (it.peek()) |next_asm_input| {
1069 const next_node = &(next_asm_input.*).base;1177 const next_node = &(next_asm_input.*).base;
1070 const n = if (nodeLineOffset(tree, node, next_node) >= 2) u8(2) else u8(1);1178
1071 try stream.writeByte(',');1179 const comma = tree.prevToken(next_asm_input.*.firstToken());
1072 try stream.writeByteNTimes('\n', n);1180 try renderToken(tree, stream, comma, indent_extra, Space.Newline); // ,
1181 try renderExtraNewline(tree, stream, next_node);
1182
1073 try stream.writeByteNTimes(' ', indent_extra);1183 try stream.writeByteNTimes(' ', indent_extra);
1074 }1184 }
1075 }1185 }
...@@ -1082,7 +1192,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -1082,7 +1192,7 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
1082 {1192 {
1083 var it = asm_node.clobbers.iterator(0);1193 var it = asm_node.clobbers.iterator(0);
1084 while (it.next()) |node| {1194 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
1087 if (it.peek() != null) {1197 if (it.peek() != null) {
1088 try stream.write(", ");1198 try stream.write(", ");
...@@ -1090,47 +1200,46 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -1090,47 +1200,46 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
1090 }1200 }
1091 }1201 }
10921202
1093 try stream.write(")");1203 try renderToken(tree, stream, asm_node.rparen, indent, space);
1094 },1204 },
10951205
1096 ast.Node.Id.AsmInput => {1206 ast.Node.Id.AsmInput => {
1097 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);1207 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
10981208
1099 try stream.write("[");1209 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);
1101 try stream.write("] ");1211 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);
1103 try stream.write(" (");1213 try stream.write(" (");
1104 try renderExpression(allocator, stream, tree, indent, asm_input.expr);1214 try renderExpression(allocator, stream, tree, indent, asm_input.expr, Space.None);
1105 try stream.write(")");1215 try renderToken(tree, stream, asm_input.lastToken(), indent, space); // )
1106 },1216 },
11071217
1108 ast.Node.Id.AsmOutput => {1218 ast.Node.Id.AsmOutput => {
1109 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);1219 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
11101220
1111 try stream.write("[");1221 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);
1113 try stream.write("] ");1223 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);
1115 try stream.write(" (");1225 try stream.write(" (");
11161226
1117 switch (asm_output.kind) {1227 switch (asm_output.kind) {
1118 ast.Node.AsmOutput.Kind.Variable => |variable_name| {1228 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);
1120 },1230 },
1121 ast.Node.AsmOutput.Kind.Return => |return_type| {1231 ast.Node.AsmOutput.Kind.Return => |return_type| {
1122 try stream.write("-> ");1232 try stream.write("-> ");
1123 try renderExpression(allocator, stream, tree, indent, return_type);1233 try renderExpression(allocator, stream, tree, indent, return_type, Space.None);
1124 },1234 },
1125 }1235 }
11261236
1127 try stream.write(")");1237 try renderToken(tree, stream, asm_output.lastToken(), indent, space); // )
1128 },1238 },
11291239
1130 ast.Node.Id.StructField,1240 ast.Node.Id.StructField,
1131 ast.Node.Id.UnionTag,1241 ast.Node.Id.UnionTag,
1132 ast.Node.Id.EnumTag,1242 ast.Node.Id.EnumTag,
1133 ast.Node.Id.ErrorTag,
1134 ast.Node.Id.Root,1243 ast.Node.Id.Root,
1135 ast.Node.Id.VarDecl,1244 ast.Node.Id.VarDecl,
1136 ast.Node.Id.Use,1245 ast.Node.Id.Use,
...@@ -1139,70 +1248,74 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind...@@ -1139,70 +1248,74 @@ fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, ind
1139 }1248 }
1140}1249}
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{
1143 if (var_decl.visib_token) |visib_token| {1254 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
1145 }1256 }
11461257
1147 if (var_decl.extern_export_token) |extern_export_token| {1258 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
1150 if (var_decl.lib_name) |lib_name| {1261 if (var_decl.lib_name) |lib_name| {
1151 try renderExpression(allocator, stream, tree, indent, lib_name);1262 try renderExpression(allocator, stream, tree, indent, lib_name, Space.Space); // "lib"
1152 try stream.write(" ");
1153 }1263 }
1154 }1264 }
11551265
1156 if (var_decl.comptime_token) |comptime_token| {1266 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
1158 }1268 }
11591269
1160 try renderToken(tree, stream, var_decl.mut_token, indent, false, true);1270 try renderToken(tree, stream, var_decl.mut_token, indent, Space.Space); // var
1161 try renderToken(tree, stream, var_decl.name_token, indent, false, false);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
1163 if (var_decl.type_node) |type_node| {1276 if (var_decl.type_node) |type_node| {
1164 try stream.write(": ");1277 try renderToken(tree, stream, tree.nextToken(var_decl.name_token), indent, Space.Space);
1165 try renderExpression(allocator, stream, tree, indent, type_node);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);
1166 }1280 }
11671281
1168 if (var_decl.align_node) |align_node| {1282 if (var_decl.align_node) |align_node| {
1169 try stream.write(" align(");1283 const lparen = tree.prevToken(align_node.firstToken());
1170 try renderExpression(allocator, stream, tree, indent, align_node);1284 const align_kw = tree.prevToken(lparen);
1171 try stream.write(")");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); // )
1172 }1291 }
11731292
1174 if (var_decl.init_node) |init_node| {1293 if (var_decl.init_node) |init_node| {
1175 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";1294 const s = if (init_node.id == ast.Node.Id.MultilineStringLiteral) Space.None else Space.Space;
1176 try stream.write(text);1295 try renderToken(tree, stream, var_decl.eq_token, indent, s); // =
1177 try renderExpression(allocator, stream, tree, indent, init_node);1296 try renderExpression(allocator, stream, tree, indent, init_node, Space.None);
1178 }1297 }
11791298
1180 try renderToken(tree, stream, var_decl.semicolon_token, indent, true, false);1299 try renderToken(tree, stream, var_decl.semicolon_token, indent, Space.Newline);
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 }
1189}1300}
11901301
1191fn renderParamDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {1302fn renderParamDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
1192 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);1303 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
1304
1193 if (param_decl.comptime_token) |comptime_token| {1305 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);
1195 }1307 }
1196 if (param_decl.noalias_token) |noalias_token| {1308 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);
1198 }1310 }
1199 if (param_decl.name_token) |name_token| {1311 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); // :
1201 }1314 }
1202 if (param_decl.var_args_token) |var_args_token| {1315 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);
1204 } else {1317 } 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);
1206 }1319 }
1207}1320}
12081321
...@@ -1213,41 +1326,104 @@ fn renderStatement(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, inde...@@ -1213,41 +1326,104 @@ fn renderStatement(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, inde
1213 try renderVarDecl(allocator, stream, tree, indent, var_decl);1326 try renderVarDecl(allocator, stream, tree, indent, var_decl);
1214 },1327 },
1215 else => {1328 else => {
1216 try renderExpression(allocator, stream, tree, indent, base);1329 if (base.requireSemiColon()) {
1217 try maybeRenderSemicolon(stream, tree, indent, base);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 }
1218 },1338 },
1219 }1339 }
1220}1340}
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 {1342const Space = enum {
1223 const token = tree.tokens.at(token_index);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);
1224 try stream.write(tree.tokenSlicePtr(token));1353 try stream.write(tree.tokenSlicePtr(token));
12251354
1226 const next_token = tree.tokens.at(token_index + 1);1355 if (space == Space.NoComment) return;
1227 if (next_token.id == Token.Id.LineComment) {1356
1228 const loc = tree.tokenLocationPtr(token.end, next_token);1357 var next_token = tree.tokens.at(token_index + 1);
1229 if (loc.line == 0) {1358 if (next_token.id != Token.Id.LineComment) {
1230 try stream.print(" {}", tree.tokenSlicePtr(next_token));1359 switch (space) {
1231 if (!line_break) {1360 Space.None, Space.NoNewline, Space.NoIndent => return,
1232 try stream.write("\n");1361 Space.Newline => return stream.write("\n"),
12331362 Space.Space => return stream.writeByte(' '),
1234 const after_comment_token = tree.tokens.at(token_index + 2);1363 Space.NoComment => unreachable,
1235 const next_line_indent = switch (after_comment_token.id) {1364 }
1236 Token.Id.RParen, Token.Id.RBrace, Token.Id.RBracket => indent,1365 }
1237 else => indent + indent_delta,1366
1238 };1367 var loc = tree.tokenLocationPtr(token.end, next_token);
1239 try stream.writeByteNTimes(' ', next_line_indent);1368 var offset: usize = 1;
1240 return;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,
1241 }1388 }
1389 return;
1242 }1390 }
1391 loc = tree.tokenLocationPtr(token.end, next_token);
1243 }1392 }
12441393
1245 if (!line_break and space) {1394 while (true) {
1246 try stream.writeByte(' ');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);
1247 }1423 }
1248}1424}
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 {
1251 const comment = node.doc_comments ?? return;1427 const comment = node.doc_comments ?? return;
1252 var it = comment.lines.iterator(0);1428 var it = comment.lines.iterator(0);
1253 while (it.next()) |line_token_index| {1429 while (it.next()) |line_token_index| {