authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-09 18:49:05-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-09-09 18:49:05-07:00
log9501ea688f414c3c8af473f9f6ba471ed2c1953e
tree20517cb77a078c0a9057379ffe57605c7345042d
parent57390999894a74f289a6eace6deed6c17b65f298

stage2: --autofix proof-of-concept

* Introduce the `--autofix` CLI flag when building an executable, object, or library. * Refactor std.zig.render to use a struct parameter to make it easier to add/remove fields from the struct. * Introduce a "Fixups" concept to std.zig.render which can perform edits while rendering code, while leaving the Ast read-only. * Add a fixup for adding a discard after a variable declaration. * Update the Module code to check for fixable errors after AstGen lowering. Improvements that need to be made before this can be merged: * Introduce an error for "pointless discard" and a fixup for it so that --autofix can undo the effects of itself when a variable becomes used. * Support local variables as well as local constants. * Support captures in addition to local variables and constants. * Integrate properly with incremental compilation. * Integrate with the Zig build system. * Distinguish between AstGen errors that can be autofixed and those that cannot. * Remove std.debug.print statements. * Only perform fixups when all errors are autofixable errors. However, suppress all autofixable errors when reporting errors with --autofix. The purpose of this feature is to satisfy two use cases that traditionally have been at odds: * Some people want the guarantee that all Zig code they read has the property that there are no unused locals. * Some people find no value from such errors and want to not have to deal with them. The problem with an `--allow-unused` flag is that people from the second group will use it, and then some projects will fail to compile without the flag enabled. I like to think of Zig as having "inline warnings". The warnings are there, inside your source code, next to the relevant lines, ready to be noticed by diffs, code reviews, and when refactoring. `--autofix` is a way for Zig to automatically insert inline warnings for those who wish to iterate quickly on a messy codebase.

5 files changed, 817 insertions(+), 673 deletions(-)

lib/std/zig/Ast.zig+8-1
...@@ -17,6 +17,7 @@ const testing = std.testing;...@@ -17,6 +17,7 @@ const testing = std.testing;
17const mem = std.mem;17const mem = std.mem;
18const Token = std.zig.Token;18const Token = std.zig.Token;
19const Ast = @This();19const Ast = @This();
20const private_render = @import("./render.zig");
2021
21pub const TokenIndex = u32;22pub const TokenIndex = u32;
22pub const ByteOffset = u32;23pub const ByteOffset = u32;
...@@ -60,8 +61,14 @@ pub fn render(tree: Ast, gpa: mem.Allocator) RenderError![]u8 {...@@ -60,8 +61,14 @@ pub fn render(tree: Ast, gpa: mem.Allocator) RenderError![]u8 {
60 return buffer.toOwnedSlice();61 return buffer.toOwnedSlice();
61}62}
6263
64pub const Fixups = private_render.Fixups;
65
63pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8)) RenderError!void {66pub fn renderToArrayList(tree: Ast, buffer: *std.ArrayList(u8)) RenderError!void {
64 return @import("./render.zig").renderTree(buffer, tree);67 return private_render.renderTree(buffer, tree, .{});
68}
69
70pub fn renderWithFixups(tree: Ast, buffer: *std.ArrayList(u8), fixups: Fixups) RenderError!void {
71 return private_render.renderTree(buffer, tree, fixups);
65}72}
6673
67/// Returns an extra offset for column and byte offset of errors that74/// Returns an extra offset for column and byte offset of errors that
lib/std/zig/render.zig+676-618
...@@ -13,44 +13,73 @@ pub const Error = Ast.RenderError;...@@ -13,44 +13,73 @@ pub const Error = Ast.RenderError;
1313
14const Ais = AutoIndentingStream(std.ArrayList(u8).Writer);14const Ais = AutoIndentingStream(std.ArrayList(u8).Writer);
1515
16pub fn renderTree(buffer: *std.ArrayList(u8), tree: Ast) Error!void {16pub const Fixups = struct {
17 /// The key is the mut token (`var`/`const`) of the variable declaration
18 /// that should have a `_ = foo;` inserted afterwards.
19 unused_var_decls: std.AutoHashMapUnmanaged(Ast.TokenIndex, void) = .{},
20
21 pub fn count(f: Fixups) usize {
22 return f.unused_var_decls.count();
23 }
24
25 pub fn deinit(f: *Fixups, gpa: Allocator) void {
26 f.unused_var_decls.deinit(gpa);
27 f.* = undefined;
28 }
29};
30
31const Render = struct {
32 gpa: Allocator,
33 ais: *Ais,
34 tree: Ast,
35 fixups: Fixups,
36};
37
38pub fn renderTree(buffer: *std.ArrayList(u8), tree: Ast, fixups: Fixups) Error!void {
17 assert(tree.errors.len == 0); // Cannot render an invalid tree.39 assert(tree.errors.len == 0); // Cannot render an invalid tree.
18 var auto_indenting_stream = Ais{40 var auto_indenting_stream = Ais{
19 .indent_delta = indent_delta,41 .indent_delta = indent_delta,
20 .underlying_writer = buffer.writer(),42 .underlying_writer = buffer.writer(),
21 };43 };
22 const ais = &auto_indenting_stream;44 var r: Render = .{
45 .gpa = buffer.allocator,
46 .ais = &auto_indenting_stream,
47 .tree = tree,
48 .fixups = fixups,
49 };
2350
24 // Render all the line comments at the beginning of the file.51 // Render all the line comments at the beginning of the file.
25 const comment_end_loc = tree.tokens.items(.start)[0];52 const comment_end_loc = tree.tokens.items(.start)[0];
26 _ = try renderComments(ais, tree, 0, comment_end_loc);53 _ = try renderComments(r, 0, comment_end_loc);
2754
28 if (tree.tokens.items(.tag)[0] == .container_doc_comment) {55 if (tree.tokens.items(.tag)[0] == .container_doc_comment) {
29 try renderContainerDocComments(ais, tree, 0);56 try renderContainerDocComments(r, 0);
30 }57 }
3158
32 try renderMembers(buffer.allocator, ais, tree, tree.rootDecls());59 try renderMembers(r, tree.rootDecls());
3360
34 if (ais.disabled_offset) |disabled_offset| {61 if (r.ais.disabled_offset) |disabled_offset| {
35 try writeFixingWhitespace(ais.underlying_writer, tree.source[disabled_offset..]);62 try writeFixingWhitespace(r.ais.underlying_writer, tree.source[disabled_offset..]);
36 }63 }
37}64}
3865
39/// Render all members in the given slice, keeping empty lines where appropriate66/// Render all members in the given slice, keeping empty lines where appropriate
40fn renderMembers(gpa: Allocator, ais: *Ais, tree: Ast, members: []const Ast.Node.Index) Error!void {67fn renderMembers(r: Render, members: []const Ast.Node.Index) Error!void {
41 if (members.len == 0) return;68 if (members.len == 0) return;
42 try renderMember(gpa, ais, tree, members[0], .newline);69 try renderMember(r, members[0], .newline);
43 for (members[1..]) |member| {70 for (members[1..]) |member| {
44 try renderExtraNewline(ais, tree, member);71 try renderExtraNewline(r, member);
45 try renderMember(gpa, ais, tree, member, .newline);72 try renderMember(r, member, .newline);
46 }73 }
47}74}
4875
49fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, space: Space) Error!void {76fn renderMember(r: Render, decl: Ast.Node.Index, space: Space) Error!void {
77 const tree = r.tree;
78 const ais = r.ais;
50 const token_tags = tree.tokens.items(.tag);79 const token_tags = tree.tokens.items(.tag);
51 const main_tokens = tree.nodes.items(.main_token);80 const main_tokens = tree.nodes.items(.main_token);
52 const datas = tree.nodes.items(.data);81 const datas = tree.nodes.items(.data);
53 try renderDocComments(ais, tree, tree.firstToken(decl));82 try renderDocComments(r, tree.firstToken(decl));
54 switch (tree.nodes.items(.tag)[decl]) {83 switch (tree.nodes.items(.tag)[decl]) {
55 .fn_decl => {84 .fn_decl => {
56 // Some examples:85 // Some examples:
...@@ -78,7 +107,7 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac...@@ -78,7 +107,7 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac
78 }107 }
79 }108 }
80 while (i < fn_token) : (i += 1) {109 while (i < fn_token) : (i += 1) {
81 try renderToken(ais, tree, i, .space);110 try renderToken(r, i, .space);
82 }111 }
83 switch (tree.nodes.items(.tag)[fn_proto]) {112 switch (tree.nodes.items(.tag)[fn_proto]) {
84 .fn_proto_one, .fn_proto => {113 .fn_proto_one, .fn_proto => {
...@@ -96,8 +125,8 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac...@@ -96,8 +125,8 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac
96 else => unreachable,125 else => unreachable,
97 }126 }
98 assert(datas[decl].rhs != 0);127 assert(datas[decl].rhs != 0);
99 try renderExpression(gpa, ais, tree, fn_proto, .space);128 try renderExpression(r, fn_proto, .space);
100 return renderExpression(gpa, ais, tree, datas[decl].rhs, space);129 return renderExpression(r, datas[decl].rhs, space);
101 },130 },
102 .fn_proto_simple,131 .fn_proto_simple,
103 .fn_proto_multi,132 .fn_proto_multi,
...@@ -126,42 +155,42 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac...@@ -126,42 +155,42 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac
126 }155 }
127 }156 }
128 while (i < fn_token) : (i += 1) {157 while (i < fn_token) : (i += 1) {
129 try renderToken(ais, tree, i, .space);158 try renderToken(r, i, .space);
130 }159 }
131 try renderExpression(gpa, ais, tree, decl, .none);160 try renderExpression(r, decl, .none);
132 return renderToken(ais, tree, tree.lastToken(decl) + 1, space); // semicolon161 return renderToken(r, tree.lastToken(decl) + 1, space); // semicolon
133 },162 },
134163
135 .@"usingnamespace" => {164 .@"usingnamespace" => {
136 const main_token = main_tokens[decl];165 const main_token = main_tokens[decl];
137 const expr = datas[decl].lhs;166 const expr = datas[decl].lhs;
138 if (main_token > 0 and token_tags[main_token - 1] == .keyword_pub) {167 if (main_token > 0 and token_tags[main_token - 1] == .keyword_pub) {
139 try renderToken(ais, tree, main_token - 1, .space); // pub168 try renderToken(r, main_token - 1, .space); // pub
140 }169 }
141 try renderToken(ais, tree, main_token, .space); // usingnamespace170 try renderToken(r, main_token, .space); // usingnamespace
142 try renderExpression(gpa, ais, tree, expr, .none);171 try renderExpression(r, expr, .none);
143 return renderToken(ais, tree, tree.lastToken(expr) + 1, space); // ;172 return renderToken(r, tree.lastToken(expr) + 1, space); // ;
144 },173 },
145174
146 .global_var_decl => return renderVarDecl(gpa, ais, tree, tree.globalVarDecl(decl)),175 .global_var_decl => return renderVarDecl(r, tree.globalVarDecl(decl)),
147 .local_var_decl => return renderVarDecl(gpa, ais, tree, tree.localVarDecl(decl)),176 .local_var_decl => return renderVarDecl(r, tree.localVarDecl(decl)),
148 .simple_var_decl => return renderVarDecl(gpa, ais, tree, tree.simpleVarDecl(decl)),177 .simple_var_decl => return renderVarDecl(r, tree.simpleVarDecl(decl)),
149 .aligned_var_decl => return renderVarDecl(gpa, ais, tree, tree.alignedVarDecl(decl)),178 .aligned_var_decl => return renderVarDecl(r, tree.alignedVarDecl(decl)),
150179
151 .test_decl => {180 .test_decl => {
152 const test_token = main_tokens[decl];181 const test_token = main_tokens[decl];
153 try renderToken(ais, tree, test_token, .space);182 try renderToken(r, test_token, .space);
154 const test_name_tag = token_tags[test_token + 1];183 const test_name_tag = token_tags[test_token + 1];
155 if (test_name_tag == .string_literal or test_name_tag == .identifier) {184 if (test_name_tag == .string_literal or test_name_tag == .identifier) {
156 try renderToken(ais, tree, test_token + 1, .space);185 try renderToken(r, test_token + 1, .space);
157 }186 }
158 try renderExpression(gpa, ais, tree, datas[decl].rhs, space);187 try renderExpression(r, datas[decl].rhs, space);
159 },188 },
160189
161 .container_field_init => return renderContainerField(gpa, ais, tree, tree.containerFieldInit(decl), space),190 .container_field_init => return renderContainerField(r, tree.containerFieldInit(decl), space),
162 .container_field_align => return renderContainerField(gpa, ais, tree, tree.containerFieldAlign(decl), space),191 .container_field_align => return renderContainerField(r, tree.containerFieldAlign(decl), space),
163 .container_field => return renderContainerField(gpa, ais, tree, tree.containerField(decl), space),192 .container_field => return renderContainerField(r, tree.containerField(decl), space),
164 .@"comptime" => return renderExpression(gpa, ais, tree, decl, space),193 .@"comptime" => return renderExpression(r, decl, space),
165194
166 .root => unreachable,195 .root => unreachable,
167 else => unreachable,196 else => unreachable,
...@@ -169,16 +198,18 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac...@@ -169,16 +198,18 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac
169}198}
170199
171/// Render all expressions in the slice, keeping empty lines where appropriate200/// Render all expressions in the slice, keeping empty lines where appropriate
172fn renderExpressions(gpa: Allocator, ais: *Ais, tree: Ast, expressions: []const Ast.Node.Index, space: Space) Error!void {201fn renderExpressions(r: Render, expressions: []const Ast.Node.Index, space: Space) Error!void {
173 if (expressions.len == 0) return;202 if (expressions.len == 0) return;
174 try renderExpression(gpa, ais, tree, expressions[0], space);203 try renderExpression(r, expressions[0], space);
175 for (expressions[1..]) |expression| {204 for (expressions[1..]) |expression| {
176 try renderExtraNewline(ais, tree, expression);205 try renderExtraNewline(r, expression);
177 try renderExpression(gpa, ais, tree, expression, space);206 try renderExpression(r, expression, space);
178 }207 }
179}208}
180209
181fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, space: Space) Error!void {210fn renderExpression(r: Render, node: Ast.Node.Index, space: Space) Error!void {
211 const tree = r.tree;
212 const ais = r.ais;
182 const token_tags = tree.tokens.items(.tag);213 const token_tags = tree.tokens.items(.tag);
183 const main_tokens = tree.nodes.items(.main_token);214 const main_tokens = tree.nodes.items(.main_token);
184 const node_tags = tree.nodes.items(.tag);215 const node_tags = tree.nodes.items(.tag);
...@@ -196,7 +227,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -196,7 +227,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
196 try ais.writer().writeAll(lexeme);227 try ais.writer().writeAll(lexeme);
197 }228 }
198229
199 return renderSpace(ais, tree, token_index, lexeme.len, space);230 return renderSpace(r, token_index, lexeme.len, space);
200 },231 },
201232
202 .integer_literal,233 .integer_literal,
...@@ -205,29 +236,29 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -205,29 +236,29 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
205 .unreachable_literal,236 .unreachable_literal,
206 .anyframe_literal,237 .anyframe_literal,
207 .string_literal,238 .string_literal,
208 => return renderToken(ais, tree, main_tokens[node], space),239 => return renderToken(r, main_tokens[node], space),
209240
210 .multiline_string_literal => {241 .multiline_string_literal => {
211 var locked_indents = ais.lockOneShotIndent();242 var locked_indents = ais.lockOneShotIndent();
212 try ais.maybeInsertNewline();243 try ais.maybeInsertNewline();
213244
214 var i = datas[node].lhs;245 var i = datas[node].lhs;
215 while (i <= datas[node].rhs) : (i += 1) try renderToken(ais, tree, i, .newline);246 while (i <= datas[node].rhs) : (i += 1) try renderToken(r, i, .newline);
216247
217 while (locked_indents > 0) : (locked_indents -= 1) ais.popIndent();248 while (locked_indents > 0) : (locked_indents -= 1) ais.popIndent();
218249
219 switch (space) {250 switch (space) {
220 .none, .space, .newline, .skip => {},251 .none, .space, .newline, .skip => {},
221 .semicolon => if (token_tags[i] == .semicolon) try renderToken(ais, tree, i, .newline),252 .semicolon => if (token_tags[i] == .semicolon) try renderToken(r, i, .newline),
222 .comma => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .newline),253 .comma => if (token_tags[i] == .comma) try renderToken(r, i, .newline),
223 .comma_space => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .space),254 .comma_space => if (token_tags[i] == .comma) try renderToken(r, i, .space),
224 }255 }
225 },256 },
226257
227 .error_value => {258 .error_value => {
228 try renderToken(ais, tree, main_tokens[node], .none);259 try renderToken(r, main_tokens[node], .none);
229 try renderToken(ais, tree, main_tokens[node] + 1, .none);260 try renderToken(r, main_tokens[node] + 1, .none);
230 return renderToken(ais, tree, main_tokens[node] + 2, space);261 return renderToken(r, main_tokens[node] + 2, space);
231 },262 },
232263
233 .block_two,264 .block_two,
...@@ -235,18 +266,18 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -235,18 +266,18 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
235 => {266 => {
236 const statements = [2]Ast.Node.Index{ datas[node].lhs, datas[node].rhs };267 const statements = [2]Ast.Node.Index{ datas[node].lhs, datas[node].rhs };
237 if (datas[node].lhs == 0) {268 if (datas[node].lhs == 0) {
238 return renderBlock(gpa, ais, tree, node, statements[0..0], space);269 return renderBlock(r, node, statements[0..0], space);
239 } else if (datas[node].rhs == 0) {270 } else if (datas[node].rhs == 0) {
240 return renderBlock(gpa, ais, tree, node, statements[0..1], space);271 return renderBlock(r, node, statements[0..1], space);
241 } else {272 } else {
242 return renderBlock(gpa, ais, tree, node, statements[0..2], space);273 return renderBlock(r, node, statements[0..2], space);
243 }274 }
244 },275 },
245 .block,276 .block,
246 .block_semicolon,277 .block_semicolon,
247 => {278 => {
248 const statements = tree.extra_data[datas[node].lhs..datas[node].rhs];279 const statements = tree.extra_data[datas[node].lhs..datas[node].rhs];
249 return renderBlock(gpa, ais, tree, node, statements, space);280 return renderBlock(r, node, statements, space);
250 },281 },
251282
252 .@"errdefer" => {283 .@"errdefer" => {
...@@ -254,33 +285,33 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -254,33 +285,33 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
254 const payload_token = datas[node].lhs;285 const payload_token = datas[node].lhs;
255 const expr = datas[node].rhs;286 const expr = datas[node].rhs;
256287
257 try renderToken(ais, tree, defer_token, .space);288 try renderToken(r, defer_token, .space);
258 if (payload_token != 0) {289 if (payload_token != 0) {
259 try renderToken(ais, tree, payload_token - 1, .none); // |290 try renderToken(r, payload_token - 1, .none); // |
260 try renderToken(ais, tree, payload_token, .none); // identifier291 try renderToken(r, payload_token, .none); // identifier
261 try renderToken(ais, tree, payload_token + 1, .space); // |292 try renderToken(r, payload_token + 1, .space); // |
262 }293 }
263 return renderExpression(gpa, ais, tree, expr, space);294 return renderExpression(r, expr, space);
264 },295 },
265296
266 .@"defer" => {297 .@"defer" => {
267 const defer_token = main_tokens[node];298 const defer_token = main_tokens[node];
268 const expr = datas[node].rhs;299 const expr = datas[node].rhs;
269 try renderToken(ais, tree, defer_token, .space);300 try renderToken(r, defer_token, .space);
270 return renderExpression(gpa, ais, tree, expr, space);301 return renderExpression(r, expr, space);
271 },302 },
272 .@"comptime", .@"nosuspend" => {303 .@"comptime", .@"nosuspend" => {
273 const comptime_token = main_tokens[node];304 const comptime_token = main_tokens[node];
274 const block = datas[node].lhs;305 const block = datas[node].lhs;
275 try renderToken(ais, tree, comptime_token, .space);306 try renderToken(r, comptime_token, .space);
276 return renderExpression(gpa, ais, tree, block, space);307 return renderExpression(r, block, space);
277 },308 },
278309
279 .@"suspend" => {310 .@"suspend" => {
280 const suspend_token = main_tokens[node];311 const suspend_token = main_tokens[node];
281 const body = datas[node].lhs;312 const body = datas[node].lhs;
282 try renderToken(ais, tree, suspend_token, .space);313 try renderToken(r, suspend_token, .space);
283 return renderExpression(gpa, ais, tree, body, space);314 return renderExpression(r, body, space);
284 },315 },
285316
286 .@"catch" => {317 .@"catch" => {
...@@ -290,27 +321,27 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -290,27 +321,27 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
290 const same_line = tree.tokensOnSameLine(main_token, fallback_first);321 const same_line = tree.tokensOnSameLine(main_token, fallback_first);
291 const after_op_space = if (same_line) Space.space else Space.newline;322 const after_op_space = if (same_line) Space.space else Space.newline;
292323
293 try renderExpression(gpa, ais, tree, datas[node].lhs, .space); // target324 try renderExpression(r, datas[node].lhs, .space); // target
294325
295 if (token_tags[fallback_first - 1] == .pipe) {326 if (token_tags[fallback_first - 1] == .pipe) {
296 try renderToken(ais, tree, main_token, .space); // catch keyword327 try renderToken(r, main_token, .space); // catch keyword
297 try renderToken(ais, tree, main_token + 1, .none); // pipe328 try renderToken(r, main_token + 1, .none); // pipe
298 try renderToken(ais, tree, main_token + 2, .none); // payload identifier329 try renderToken(r, main_token + 2, .none); // payload identifier
299 try renderToken(ais, tree, main_token + 3, after_op_space); // pipe330 try renderToken(r, main_token + 3, after_op_space); // pipe
300 } else {331 } else {
301 assert(token_tags[fallback_first - 1] == .keyword_catch);332 assert(token_tags[fallback_first - 1] == .keyword_catch);
302 try renderToken(ais, tree, main_token, after_op_space); // catch keyword333 try renderToken(r, main_token, after_op_space); // catch keyword
303 }334 }
304335
305 ais.pushIndentOneShot();336 ais.pushIndentOneShot();
306 try renderExpression(gpa, ais, tree, datas[node].rhs, space); // fallback337 try renderExpression(r, datas[node].rhs, space); // fallback
307 },338 },
308339
309 .field_access => {340 .field_access => {
310 const main_token = main_tokens[node];341 const main_token = main_tokens[node];
311 const field_access = datas[node];342 const field_access = datas[node];
312343
313 try renderExpression(gpa, ais, tree, field_access.lhs, .none);344 try renderExpression(r, field_access.lhs, .none);
314345
315 // Allow a line break between the lhs and the dot if the lhs and rhs346 // Allow a line break between the lhs and the dot if the lhs and rhs
316 // are on different lines.347 // are on different lines.
...@@ -321,7 +352,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -321,7 +352,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
321 ais.pushIndentOneShot();352 ais.pushIndentOneShot();
322 }353 }
323354
324 try renderToken(ais, tree, main_token, .none);355 try renderToken(r, main_token, .none);
325356
326 // This check ensures that zag() is indented in the following example:357 // This check ensures that zag() is indented in the following example:
327 // const x = foo358 // const x = foo
...@@ -332,16 +363,16 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -332,16 +363,16 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
332 ais.pushIndentOneShot();363 ais.pushIndentOneShot();
333 }364 }
334365
335 return renderToken(ais, tree, field_access.rhs, space);366 return renderToken(r, field_access.rhs, space);
336 },367 },
337368
338 .error_union,369 .error_union,
339 .switch_range,370 .switch_range,
340 => {371 => {
341 const infix = datas[node];372 const infix = datas[node];
342 try renderExpression(gpa, ais, tree, infix.lhs, .none);373 try renderExpression(r, infix.lhs, .none);
343 try renderToken(ais, tree, main_tokens[node], .none);374 try renderToken(r, main_tokens[node], .none);
344 return renderExpression(gpa, ais, tree, infix.rhs, space);375 return renderExpression(r, infix.rhs, space);
345 },376 },
346377
347 .add,378 .add,
...@@ -393,17 +424,17 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -393,17 +424,17 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
393 .@"orelse",424 .@"orelse",
394 => {425 => {
395 const infix = datas[node];426 const infix = datas[node];
396 try renderExpression(gpa, ais, tree, infix.lhs, .space);427 try renderExpression(r, infix.lhs, .space);
397 const op_token = main_tokens[node];428 const op_token = main_tokens[node];
398 if (tree.tokensOnSameLine(op_token, op_token + 1)) {429 if (tree.tokensOnSameLine(op_token, op_token + 1)) {
399 try renderToken(ais, tree, op_token, .space);430 try renderToken(r, op_token, .space);
400 } else {431 } else {
401 ais.pushIndent();432 ais.pushIndent();
402 try renderToken(ais, tree, op_token, .newline);433 try renderToken(r, op_token, .newline);
403 ais.popIndent();434 ais.popIndent();
404 }435 }
405 ais.pushIndentOneShot();436 ais.pushIndentOneShot();
406 return renderExpression(gpa, ais, tree, infix.rhs, space);437 return renderExpression(r, infix.rhs, space);
407 },438 },
408439
409 .bit_not,440 .bit_not,
...@@ -413,66 +444,66 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -413,66 +444,66 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
413 .optional_type,444 .optional_type,
414 .address_of,445 .address_of,
415 => {446 => {
416 try renderToken(ais, tree, main_tokens[node], .none);447 try renderToken(r, main_tokens[node], .none);
417 return renderExpression(gpa, ais, tree, datas[node].lhs, space);448 return renderExpression(r, datas[node].lhs, space);
418 },449 },
419450
420 .@"try",451 .@"try",
421 .@"resume",452 .@"resume",
422 .@"await",453 .@"await",
423 => {454 => {
424 try renderToken(ais, tree, main_tokens[node], .space);455 try renderToken(r, main_tokens[node], .space);
425 return renderExpression(gpa, ais, tree, datas[node].lhs, space);456 return renderExpression(r, datas[node].lhs, space);
426 },457 },
427458
428 .array_type => return renderArrayType(gpa, ais, tree, tree.arrayType(node), space),459 .array_type => return renderArrayType(r, tree.arrayType(node), space),
429 .array_type_sentinel => return renderArrayType(gpa, ais, tree, tree.arrayTypeSentinel(node), space),460 .array_type_sentinel => return renderArrayType(r, tree.arrayTypeSentinel(node), space),
430461
431 .ptr_type_aligned => return renderPtrType(gpa, ais, tree, tree.ptrTypeAligned(node), space),462 .ptr_type_aligned => return renderPtrType(r, tree.ptrTypeAligned(node), space),
432 .ptr_type_sentinel => return renderPtrType(gpa, ais, tree, tree.ptrTypeSentinel(node), space),463 .ptr_type_sentinel => return renderPtrType(r, tree.ptrTypeSentinel(node), space),
433 .ptr_type => return renderPtrType(gpa, ais, tree, tree.ptrType(node), space),464 .ptr_type => return renderPtrType(r, tree.ptrType(node), space),
434 .ptr_type_bit_range => return renderPtrType(gpa, ais, tree, tree.ptrTypeBitRange(node), space),465 .ptr_type_bit_range => return renderPtrType(r, tree.ptrTypeBitRange(node), space),
435466
436 .array_init_one, .array_init_one_comma => {467 .array_init_one, .array_init_one_comma => {
437 var elements: [1]Ast.Node.Index = undefined;468 var elements: [1]Ast.Node.Index = undefined;
438 return renderArrayInit(gpa, ais, tree, tree.arrayInitOne(&elements, node), space);469 return renderArrayInit(r, tree.arrayInitOne(&elements, node), space);
439 },470 },
440 .array_init_dot_two, .array_init_dot_two_comma => {471 .array_init_dot_two, .array_init_dot_two_comma => {
441 var elements: [2]Ast.Node.Index = undefined;472 var elements: [2]Ast.Node.Index = undefined;
442 return renderArrayInit(gpa, ais, tree, tree.arrayInitDotTwo(&elements, node), space);473 return renderArrayInit(r, tree.arrayInitDotTwo(&elements, node), space);
443 },474 },
444 .array_init_dot,475 .array_init_dot,
445 .array_init_dot_comma,476 .array_init_dot_comma,
446 => return renderArrayInit(gpa, ais, tree, tree.arrayInitDot(node), space),477 => return renderArrayInit(r, tree.arrayInitDot(node), space),
447 .array_init,478 .array_init,
448 .array_init_comma,479 .array_init_comma,
449 => return renderArrayInit(gpa, ais, tree, tree.arrayInit(node), space),480 => return renderArrayInit(r, tree.arrayInit(node), space),
450481
451 .struct_init_one, .struct_init_one_comma => {482 .struct_init_one, .struct_init_one_comma => {
452 var fields: [1]Ast.Node.Index = undefined;483 var fields: [1]Ast.Node.Index = undefined;
453 return renderStructInit(gpa, ais, tree, node, tree.structInitOne(&fields, node), space);484 return renderStructInit(r, node, tree.structInitOne(&fields, node), space);
454 },485 },
455 .struct_init_dot_two, .struct_init_dot_two_comma => {486 .struct_init_dot_two, .struct_init_dot_two_comma => {
456 var fields: [2]Ast.Node.Index = undefined;487 var fields: [2]Ast.Node.Index = undefined;
457 return renderStructInit(gpa, ais, tree, node, tree.structInitDotTwo(&fields, node), space);488 return renderStructInit(r, node, tree.structInitDotTwo(&fields, node), space);
458 },489 },
459 .struct_init_dot,490 .struct_init_dot,
460 .struct_init_dot_comma,491 .struct_init_dot_comma,
461 => return renderStructInit(gpa, ais, tree, node, tree.structInitDot(node), space),492 => return renderStructInit(r, node, tree.structInitDot(node), space),
462 .struct_init,493 .struct_init,
463 .struct_init_comma,494 .struct_init_comma,
464 => return renderStructInit(gpa, ais, tree, node, tree.structInit(node), space),495 => return renderStructInit(r, node, tree.structInit(node), space),
465496
466 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => {497 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => {
467 var params: [1]Ast.Node.Index = undefined;498 var params: [1]Ast.Node.Index = undefined;
468 return renderCall(gpa, ais, tree, tree.callOne(&params, node), space);499 return renderCall(r, tree.callOne(&params, node), space);
469 },500 },
470501
471 .call,502 .call,
472 .call_comma,503 .call_comma,
473 .async_call,504 .async_call,
474 .async_call_comma,505 .async_call_comma,
475 => return renderCall(gpa, ais, tree, tree.callFull(node), space),506 => return renderCall(r, tree.callFull(node), space),
476507
477 .array_access => {508 .array_access => {
478 const suffix = datas[node];509 const suffix = datas[node];
...@@ -480,27 +511,27 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -480,27 +511,27 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
480 const rbracket = tree.lastToken(suffix.rhs) + 1;511 const rbracket = tree.lastToken(suffix.rhs) + 1;
481 const one_line = tree.tokensOnSameLine(lbracket, rbracket);512 const one_line = tree.tokensOnSameLine(lbracket, rbracket);
482 const inner_space = if (one_line) Space.none else Space.newline;513 const inner_space = if (one_line) Space.none else Space.newline;
483 try renderExpression(gpa, ais, tree, suffix.lhs, .none);514 try renderExpression(r, suffix.lhs, .none);
484 ais.pushIndentNextLine();515 ais.pushIndentNextLine();
485 try renderToken(ais, tree, lbracket, inner_space); // [516 try renderToken(r, lbracket, inner_space); // [
486 try renderExpression(gpa, ais, tree, suffix.rhs, inner_space);517 try renderExpression(r, suffix.rhs, inner_space);
487 ais.popIndent();518 ais.popIndent();
488 return renderToken(ais, tree, rbracket, space); // ]519 return renderToken(r, rbracket, space); // ]
489 },520 },
490521
491 .slice_open => return renderSlice(gpa, ais, tree, node, tree.sliceOpen(node), space),522 .slice_open => return renderSlice(r, node, tree.sliceOpen(node), space),
492 .slice => return renderSlice(gpa, ais, tree, node, tree.slice(node), space),523 .slice => return renderSlice(r, node, tree.slice(node), space),
493 .slice_sentinel => return renderSlice(gpa, ais, tree, node, tree.sliceSentinel(node), space),524 .slice_sentinel => return renderSlice(r, node, tree.sliceSentinel(node), space),
494525
495 .deref => {526 .deref => {
496 try renderExpression(gpa, ais, tree, datas[node].lhs, .none);527 try renderExpression(r, datas[node].lhs, .none);
497 return renderToken(ais, tree, main_tokens[node], space);528 return renderToken(r, main_tokens[node], space);
498 },529 },
499530
500 .unwrap_optional => {531 .unwrap_optional => {
501 try renderExpression(gpa, ais, tree, datas[node].lhs, .none);532 try renderExpression(r, datas[node].lhs, .none);
502 try renderToken(ais, tree, main_tokens[node], .none);533 try renderToken(r, main_tokens[node], .none);
503 return renderToken(ais, tree, datas[node].rhs, space);534 return renderToken(r, datas[node].rhs, space);
504 },535 },
505536
506 .@"break" => {537 .@"break" => {
...@@ -508,19 +539,19 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -508,19 +539,19 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
508 const label_token = datas[node].lhs;539 const label_token = datas[node].lhs;
509 const target = datas[node].rhs;540 const target = datas[node].rhs;
510 if (label_token == 0 and target == 0) {541 if (label_token == 0 and target == 0) {
511 try renderToken(ais, tree, main_token, space); // break keyword542 try renderToken(r, main_token, space); // break keyword
512 } else if (label_token == 0 and target != 0) {543 } else if (label_token == 0 and target != 0) {
513 try renderToken(ais, tree, main_token, .space); // break keyword544 try renderToken(r, main_token, .space); // break keyword
514 try renderExpression(gpa, ais, tree, target, space);545 try renderExpression(r, target, space);
515 } else if (label_token != 0 and target == 0) {546 } else if (label_token != 0 and target == 0) {
516 try renderToken(ais, tree, main_token, .space); // break keyword547 try renderToken(r, main_token, .space); // break keyword
517 try renderToken(ais, tree, label_token - 1, .none); // colon548 try renderToken(r, label_token - 1, .none); // colon
518 try renderToken(ais, tree, label_token, space); // identifier549 try renderToken(r, label_token, space); // identifier
519 } else if (label_token != 0 and target != 0) {550 } else if (label_token != 0 and target != 0) {
520 try renderToken(ais, tree, main_token, .space); // break keyword551 try renderToken(r, main_token, .space); // break keyword
521 try renderToken(ais, tree, label_token - 1, .none); // colon552 try renderToken(r, label_token - 1, .none); // colon
522 try renderToken(ais, tree, label_token, .space); // identifier553 try renderToken(r, label_token, .space); // identifier
523 try renderExpression(gpa, ais, tree, target, space);554 try renderExpression(r, target, space);
524 }555 }
525 },556 },
526557
...@@ -528,136 +559,136 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -528,136 +559,136 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
528 const main_token = main_tokens[node];559 const main_token = main_tokens[node];
529 const label = datas[node].lhs;560 const label = datas[node].lhs;
530 if (label != 0) {561 if (label != 0) {
531 try renderToken(ais, tree, main_token, .space); // continue562 try renderToken(r, main_token, .space); // continue
532 try renderToken(ais, tree, label - 1, .none); // :563 try renderToken(r, label - 1, .none); // :
533 return renderToken(ais, tree, label, space); // label564 return renderToken(r, label, space); // label
534 } else {565 } else {
535 return renderToken(ais, tree, main_token, space); // continue566 return renderToken(r, main_token, space); // continue
536 }567 }
537 },568 },
538569
539 .@"return" => {570 .@"return" => {
540 if (datas[node].lhs != 0) {571 if (datas[node].lhs != 0) {
541 try renderToken(ais, tree, main_tokens[node], .space);572 try renderToken(r, main_tokens[node], .space);
542 try renderExpression(gpa, ais, tree, datas[node].lhs, space);573 try renderExpression(r, datas[node].lhs, space);
543 } else {574 } else {
544 try renderToken(ais, tree, main_tokens[node], space);575 try renderToken(r, main_tokens[node], space);
545 }576 }
546 },577 },
547578
548 .grouped_expression => {579 .grouped_expression => {
549 try renderToken(ais, tree, main_tokens[node], .none); // lparen580 try renderToken(r, main_tokens[node], .none); // lparen
550 ais.pushIndentOneShot();581 ais.pushIndentOneShot();
551 try renderExpression(gpa, ais, tree, datas[node].lhs, .none);582 try renderExpression(r, datas[node].lhs, .none);
552 return renderToken(ais, tree, datas[node].rhs, space); // rparen583 return renderToken(r, datas[node].rhs, space); // rparen
553 },584 },
554585
555 .container_decl,586 .container_decl,
556 .container_decl_trailing,587 .container_decl_trailing,
557 => return renderContainerDecl(gpa, ais, tree, node, tree.containerDecl(node), space),588 => return renderContainerDecl(r, node, tree.containerDecl(node), space),
558589
559 .container_decl_two, .container_decl_two_trailing => {590 .container_decl_two, .container_decl_two_trailing => {
560 var buffer: [2]Ast.Node.Index = undefined;591 var buffer: [2]Ast.Node.Index = undefined;
561 return renderContainerDecl(gpa, ais, tree, node, tree.containerDeclTwo(&buffer, node), space);592 return renderContainerDecl(r, node, tree.containerDeclTwo(&buffer, node), space);
562 },593 },
563 .container_decl_arg,594 .container_decl_arg,
564 .container_decl_arg_trailing,595 .container_decl_arg_trailing,
565 => return renderContainerDecl(gpa, ais, tree, node, tree.containerDeclArg(node), space),596 => return renderContainerDecl(r, node, tree.containerDeclArg(node), space),
566597
567 .tagged_union,598 .tagged_union,
568 .tagged_union_trailing,599 .tagged_union_trailing,
569 => return renderContainerDecl(gpa, ais, tree, node, tree.taggedUnion(node), space),600 => return renderContainerDecl(r, node, tree.taggedUnion(node), space),
570601
571 .tagged_union_two, .tagged_union_two_trailing => {602 .tagged_union_two, .tagged_union_two_trailing => {
572 var buffer: [2]Ast.Node.Index = undefined;603 var buffer: [2]Ast.Node.Index = undefined;
573 return renderContainerDecl(gpa, ais, tree, node, tree.taggedUnionTwo(&buffer, node), space);604 return renderContainerDecl(r, node, tree.taggedUnionTwo(&buffer, node), space);
574 },605 },
575 .tagged_union_enum_tag,606 .tagged_union_enum_tag,
576 .tagged_union_enum_tag_trailing,607 .tagged_union_enum_tag_trailing,
577 => return renderContainerDecl(gpa, ais, tree, node, tree.taggedUnionEnumTag(node), space),608 => return renderContainerDecl(r, node, tree.taggedUnionEnumTag(node), space),
578609
579 .error_set_decl => {610 .error_set_decl => {
580 const error_token = main_tokens[node];611 const error_token = main_tokens[node];
581 const lbrace = error_token + 1;612 const lbrace = error_token + 1;
582 const rbrace = datas[node].rhs;613 const rbrace = datas[node].rhs;
583614
584 try renderToken(ais, tree, error_token, .none);615 try renderToken(r, error_token, .none);
585616
586 if (lbrace + 1 == rbrace) {617 if (lbrace + 1 == rbrace) {
587 // There is nothing between the braces so render condensed: `error{}`618 // There is nothing between the braces so render condensed: `error{}`
588 try renderToken(ais, tree, lbrace, .none);619 try renderToken(r, lbrace, .none);
589 return renderToken(ais, tree, rbrace, space);620 return renderToken(r, rbrace, space);
590 } else if (lbrace + 2 == rbrace and token_tags[lbrace + 1] == .identifier) {621 } else if (lbrace + 2 == rbrace and token_tags[lbrace + 1] == .identifier) {
591 // There is exactly one member and no trailing comma or622 // There is exactly one member and no trailing comma or
592 // comments, so render without surrounding spaces: `error{Foo}`623 // comments, so render without surrounding spaces: `error{Foo}`
593 try renderToken(ais, tree, lbrace, .none);624 try renderToken(r, lbrace, .none);
594 try renderToken(ais, tree, lbrace + 1, .none); // identifier625 try renderToken(r, lbrace + 1, .none); // identifier
595 return renderToken(ais, tree, rbrace, space);626 return renderToken(r, rbrace, space);
596 } else if (token_tags[rbrace - 1] == .comma) {627 } else if (token_tags[rbrace - 1] == .comma) {
597 // There is a trailing comma so render each member on a new line.628 // There is a trailing comma so render each member on a new line.
598 ais.pushIndentNextLine();629 ais.pushIndentNextLine();
599 try renderToken(ais, tree, lbrace, .newline);630 try renderToken(r, lbrace, .newline);
600 var i = lbrace + 1;631 var i = lbrace + 1;
601 while (i < rbrace) : (i += 1) {632 while (i < rbrace) : (i += 1) {
602 if (i > lbrace + 1) try renderExtraNewlineToken(ais, tree, i);633 if (i > lbrace + 1) try renderExtraNewlineToken(r, i);
603 switch (token_tags[i]) {634 switch (token_tags[i]) {
604 .doc_comment => try renderToken(ais, tree, i, .newline),635 .doc_comment => try renderToken(r, i, .newline),
605 .identifier => try renderToken(ais, tree, i, .comma),636 .identifier => try renderToken(r, i, .comma),
606 .comma => {},637 .comma => {},
607 else => unreachable,638 else => unreachable,
608 }639 }
609 }640 }
610 ais.popIndent();641 ais.popIndent();
611 return renderToken(ais, tree, rbrace, space);642 return renderToken(r, rbrace, space);
612 } else {643 } else {
613 // There is no trailing comma so render everything on one line.644 // There is no trailing comma so render everything on one line.
614 try renderToken(ais, tree, lbrace, .space);645 try renderToken(r, lbrace, .space);
615 var i = lbrace + 1;646 var i = lbrace + 1;
616 while (i < rbrace) : (i += 1) {647 while (i < rbrace) : (i += 1) {
617 switch (token_tags[i]) {648 switch (token_tags[i]) {
618 .doc_comment => unreachable, // TODO649 .doc_comment => unreachable, // TODO
619 .identifier => try renderToken(ais, tree, i, .comma_space),650 .identifier => try renderToken(r, i, .comma_space),
620 .comma => {},651 .comma => {},
621 else => unreachable,652 else => unreachable,
622 }653 }
623 }654 }
624 return renderToken(ais, tree, rbrace, space);655 return renderToken(r, rbrace, space);
625 }656 }
626 },657 },
627658
628 .builtin_call_two, .builtin_call_two_comma => {659 .builtin_call_two, .builtin_call_two_comma => {
629 if (datas[node].lhs == 0) {660 if (datas[node].lhs == 0) {
630 return renderBuiltinCall(gpa, ais, tree, main_tokens[node], &.{}, space);661 return renderBuiltinCall(r, main_tokens[node], &.{}, space);
631 } else if (datas[node].rhs == 0) {662 } else if (datas[node].rhs == 0) {
632 return renderBuiltinCall(gpa, ais, tree, main_tokens[node], &.{datas[node].lhs}, space);663 return renderBuiltinCall(r, main_tokens[node], &.{datas[node].lhs}, space);
633 } else {664 } else {
634 return renderBuiltinCall(gpa, ais, tree, main_tokens[node], &.{ datas[node].lhs, datas[node].rhs }, space);665 return renderBuiltinCall(r, main_tokens[node], &.{ datas[node].lhs, datas[node].rhs }, space);
635 }666 }
636 },667 },
637 .builtin_call, .builtin_call_comma => {668 .builtin_call, .builtin_call_comma => {
638 const params = tree.extra_data[datas[node].lhs..datas[node].rhs];669 const params = tree.extra_data[datas[node].lhs..datas[node].rhs];
639 return renderBuiltinCall(gpa, ais, tree, main_tokens[node], params, space);670 return renderBuiltinCall(r, main_tokens[node], params, space);
640 },671 },
641672
642 .fn_proto_simple => {673 .fn_proto_simple => {
643 var params: [1]Ast.Node.Index = undefined;674 var params: [1]Ast.Node.Index = undefined;
644 return renderFnProto(gpa, ais, tree, tree.fnProtoSimple(&params, node), space);675 return renderFnProto(r, tree.fnProtoSimple(&params, node), space);
645 },676 },
646 .fn_proto_multi => return renderFnProto(gpa, ais, tree, tree.fnProtoMulti(node), space),677 .fn_proto_multi => return renderFnProto(r, tree.fnProtoMulti(node), space),
647 .fn_proto_one => {678 .fn_proto_one => {
648 var params: [1]Ast.Node.Index = undefined;679 var params: [1]Ast.Node.Index = undefined;
649 return renderFnProto(gpa, ais, tree, tree.fnProtoOne(&params, node), space);680 return renderFnProto(r, tree.fnProtoOne(&params, node), space);
650 },681 },
651 .fn_proto => return renderFnProto(gpa, ais, tree, tree.fnProto(node), space),682 .fn_proto => return renderFnProto(r, tree.fnProto(node), space),
652683
653 .anyframe_type => {684 .anyframe_type => {
654 const main_token = main_tokens[node];685 const main_token = main_tokens[node];
655 if (datas[node].rhs != 0) {686 if (datas[node].rhs != 0) {
656 try renderToken(ais, tree, main_token, .none); // anyframe687 try renderToken(r, main_token, .none); // anyframe
657 try renderToken(ais, tree, main_token + 1, .none); // ->688 try renderToken(r, main_token + 1, .none); // ->
658 return renderExpression(gpa, ais, tree, datas[node].rhs, space);689 return renderExpression(r, datas[node].rhs, space);
659 } else {690 } else {
660 return renderToken(ais, tree, main_token, space); // anyframe691 return renderToken(r, main_token, space); // anyframe
661 }692 }
662 },693 },
663694
...@@ -670,40 +701,40 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -670,40 +701,40 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
670 const cases = tree.extra_data[extra.start..extra.end];701 const cases = tree.extra_data[extra.start..extra.end];
671 const rparen = tree.lastToken(condition) + 1;702 const rparen = tree.lastToken(condition) + 1;
672703
673 try renderToken(ais, tree, switch_token, .space); // switch keyword704 try renderToken(r, switch_token, .space); // switch keyword
674 try renderToken(ais, tree, switch_token + 1, .none); // lparen705 try renderToken(r, switch_token + 1, .none); // lparen
675 try renderExpression(gpa, ais, tree, condition, .none); // condtion expression706 try renderExpression(r, condition, .none); // condtion expression
676 try renderToken(ais, tree, rparen, .space); // rparen707 try renderToken(r, rparen, .space); // rparen
677708
678 ais.pushIndentNextLine();709 ais.pushIndentNextLine();
679 if (cases.len == 0) {710 if (cases.len == 0) {
680 try renderToken(ais, tree, rparen + 1, .none); // lbrace711 try renderToken(r, rparen + 1, .none); // lbrace
681 } else {712 } else {
682 try renderToken(ais, tree, rparen + 1, .newline); // lbrace713 try renderToken(r, rparen + 1, .newline); // lbrace
683 try renderExpressions(gpa, ais, tree, cases, .comma);714 try renderExpressions(r, cases, .comma);
684 }715 }
685 ais.popIndent();716 ais.popIndent();
686 return renderToken(ais, tree, tree.lastToken(node), space); // rbrace717 return renderToken(r, tree.lastToken(node), space); // rbrace
687 },718 },
688719
689 .switch_case_one => return renderSwitchCase(gpa, ais, tree, tree.switchCaseOne(node), space),720 .switch_case_one => return renderSwitchCase(r, tree.switchCaseOne(node), space),
690 .switch_case => return renderSwitchCase(gpa, ais, tree, tree.switchCase(node), space),721 .switch_case => return renderSwitchCase(r, tree.switchCase(node), space),
691722
692 .while_simple => return renderWhile(gpa, ais, tree, tree.whileSimple(node), space),723 .while_simple => return renderWhile(r, tree.whileSimple(node), space),
693 .while_cont => return renderWhile(gpa, ais, tree, tree.whileCont(node), space),724 .while_cont => return renderWhile(r, tree.whileCont(node), space),
694 .@"while" => return renderWhile(gpa, ais, tree, tree.whileFull(node), space),725 .@"while" => return renderWhile(r, tree.whileFull(node), space),
695 .for_simple => return renderWhile(gpa, ais, tree, tree.forSimple(node), space),726 .for_simple => return renderWhile(r, tree.forSimple(node), space),
696 .@"for" => return renderWhile(gpa, ais, tree, tree.forFull(node), space),727 .@"for" => return renderWhile(r, tree.forFull(node), space),
697728
698 .if_simple => return renderIf(gpa, ais, tree, tree.ifSimple(node), space),729 .if_simple => return renderIf(r, tree.ifSimple(node), space),
699 .@"if" => return renderIf(gpa, ais, tree, tree.ifFull(node), space),730 .@"if" => return renderIf(r, tree.ifFull(node), space),
700731
701 .asm_simple => return renderAsm(gpa, ais, tree, tree.asmSimple(node), space),732 .asm_simple => return renderAsm(r, tree.asmSimple(node), space),
702 .@"asm" => return renderAsm(gpa, ais, tree, tree.asmFull(node), space),733 .@"asm" => return renderAsm(r, tree.asmFull(node), space),
703734
704 .enum_literal => {735 .enum_literal => {
705 try renderToken(ais, tree, main_tokens[node] - 1, .none); // .736 try renderToken(r, main_tokens[node] - 1, .none); // .
706 return renderToken(ais, tree, main_tokens[node], space); // name737 return renderToken(r, main_tokens[node], space); // name
707 },738 },
708739
709 .fn_decl => unreachable,740 .fn_decl => unreachable,
...@@ -723,34 +754,29 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,...@@ -723,34 +754,29 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
723}754}
724755
725fn renderArrayType(756fn renderArrayType(
726 gpa: Allocator,757 r: Render,
727 ais: *Ais,
728 tree: Ast,
729 array_type: Ast.full.ArrayType,758 array_type: Ast.full.ArrayType,
730 space: Space,759 space: Space,
731) Error!void {760) Error!void {
761 const tree = r.tree;
762 const ais = r.ais;
732 const rbracket = tree.firstToken(array_type.ast.elem_type) - 1;763 const rbracket = tree.firstToken(array_type.ast.elem_type) - 1;
733 const one_line = tree.tokensOnSameLine(array_type.ast.lbracket, rbracket);764 const one_line = tree.tokensOnSameLine(array_type.ast.lbracket, rbracket);
734 const inner_space = if (one_line) Space.none else Space.newline;765 const inner_space = if (one_line) Space.none else Space.newline;
735 ais.pushIndentNextLine();766 ais.pushIndentNextLine();
736 try renderToken(ais, tree, array_type.ast.lbracket, inner_space); // lbracket767 try renderToken(r, array_type.ast.lbracket, inner_space); // lbracket
737 try renderExpression(gpa, ais, tree, array_type.ast.elem_count, inner_space);768 try renderExpression(r, array_type.ast.elem_count, inner_space);
738 if (array_type.ast.sentinel != 0) {769 if (array_type.ast.sentinel != 0) {
739 try renderToken(ais, tree, tree.firstToken(array_type.ast.sentinel) - 1, inner_space); // colon770 try renderToken(r, tree.firstToken(array_type.ast.sentinel) - 1, inner_space); // colon
740 try renderExpression(gpa, ais, tree, array_type.ast.sentinel, inner_space);771 try renderExpression(r, array_type.ast.sentinel, inner_space);
741 }772 }
742 ais.popIndent();773 ais.popIndent();
743 try renderToken(ais, tree, rbracket, .none); // rbracket774 try renderToken(r, rbracket, .none); // rbracket
744 return renderExpression(gpa, ais, tree, array_type.ast.elem_type, space);775 return renderExpression(r, array_type.ast.elem_type, space);
745}776}
746777
747fn renderPtrType(778fn renderPtrType(r: Render, ptr_type: Ast.full.PtrType, space: Space) Error!void {
748 gpa: Allocator,779 const tree = r.tree;
749 ais: *Ais,
750 tree: Ast,
751 ptr_type: Ast.full.PtrType,
752 space: Space,
753) Error!void {
754 switch (ptr_type.size) {780 switch (ptr_type.size) {
755 .One => {781 .One => {
756 // Since ** tokens exist and the same token is shared by two782 // Since ** tokens exist and the same token is shared by two
...@@ -761,90 +787,89 @@ fn renderPtrType(...@@ -761,90 +787,89 @@ fn renderPtrType(
761 if (tree.tokens.items(.tag)[ptr_type.ast.main_token] == .asterisk_asterisk and787 if (tree.tokens.items(.tag)[ptr_type.ast.main_token] == .asterisk_asterisk and
762 ptr_type.ast.main_token == tree.nodes.items(.main_token)[ptr_type.ast.child_type])788 ptr_type.ast.main_token == tree.nodes.items(.main_token)[ptr_type.ast.child_type])
763 {789 {
764 return renderExpression(gpa, ais, tree, ptr_type.ast.child_type, space);790 return renderExpression(r, ptr_type.ast.child_type, space);
765 }791 }
766 try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk792 try renderToken(r, ptr_type.ast.main_token, .none); // asterisk
767 },793 },
768 .Many => {794 .Many => {
769 if (ptr_type.ast.sentinel == 0) {795 if (ptr_type.ast.sentinel == 0) {
770 try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket796 try renderToken(r, ptr_type.ast.main_token - 1, .none); // lbracket
771 try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk797 try renderToken(r, ptr_type.ast.main_token, .none); // asterisk
772 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // rbracket798 try renderToken(r, ptr_type.ast.main_token + 1, .none); // rbracket
773 } else {799 } else {
774 try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket800 try renderToken(r, ptr_type.ast.main_token - 1, .none); // lbracket
775 try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk801 try renderToken(r, ptr_type.ast.main_token, .none); // asterisk
776 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // colon802 try renderToken(r, ptr_type.ast.main_token + 1, .none); // colon
777 try renderExpression(gpa, ais, tree, ptr_type.ast.sentinel, .none);803 try renderExpression(r, ptr_type.ast.sentinel, .none);
778 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket804 try renderToken(r, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket
779 }805 }
780 },806 },
781 .C => {807 .C => {
782 try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket808 try renderToken(r, ptr_type.ast.main_token - 1, .none); // lbracket
783 try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk809 try renderToken(r, ptr_type.ast.main_token, .none); // asterisk
784 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // c810 try renderToken(r, ptr_type.ast.main_token + 1, .none); // c
785 try renderToken(ais, tree, ptr_type.ast.main_token + 2, .none); // rbracket811 try renderToken(r, ptr_type.ast.main_token + 2, .none); // rbracket
786 },812 },
787 .Slice => {813 .Slice => {
788 if (ptr_type.ast.sentinel == 0) {814 if (ptr_type.ast.sentinel == 0) {
789 try renderToken(ais, tree, ptr_type.ast.main_token, .none); // lbracket815 try renderToken(r, ptr_type.ast.main_token, .none); // lbracket
790 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // rbracket816 try renderToken(r, ptr_type.ast.main_token + 1, .none); // rbracket
791 } else {817 } else {
792 try renderToken(ais, tree, ptr_type.ast.main_token, .none); // lbracket818 try renderToken(r, ptr_type.ast.main_token, .none); // lbracket
793 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // colon819 try renderToken(r, ptr_type.ast.main_token + 1, .none); // colon
794 try renderExpression(gpa, ais, tree, ptr_type.ast.sentinel, .none);820 try renderExpression(r, ptr_type.ast.sentinel, .none);
795 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket821 try renderToken(r, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket
796 }822 }
797 },823 },
798 }824 }
799825
800 if (ptr_type.allowzero_token) |allowzero_token| {826 if (ptr_type.allowzero_token) |allowzero_token| {
801 try renderToken(ais, tree, allowzero_token, .space);827 try renderToken(r, allowzero_token, .space);
802 }828 }
803829
804 if (ptr_type.ast.align_node != 0) {830 if (ptr_type.ast.align_node != 0) {
805 const align_first = tree.firstToken(ptr_type.ast.align_node);831 const align_first = tree.firstToken(ptr_type.ast.align_node);
806 try renderToken(ais, tree, align_first - 2, .none); // align832 try renderToken(r, align_first - 2, .none); // align
807 try renderToken(ais, tree, align_first - 1, .none); // lparen833 try renderToken(r, align_first - 1, .none); // lparen
808 try renderExpression(gpa, ais, tree, ptr_type.ast.align_node, .none);834 try renderExpression(r, ptr_type.ast.align_node, .none);
809 if (ptr_type.ast.bit_range_start != 0) {835 if (ptr_type.ast.bit_range_start != 0) {
810 assert(ptr_type.ast.bit_range_end != 0);836 assert(ptr_type.ast.bit_range_end != 0);
811 try renderToken(ais, tree, tree.firstToken(ptr_type.ast.bit_range_start) - 1, .none); // colon837 try renderToken(r, tree.firstToken(ptr_type.ast.bit_range_start) - 1, .none); // colon
812 try renderExpression(gpa, ais, tree, ptr_type.ast.bit_range_start, .none);838 try renderExpression(r, ptr_type.ast.bit_range_start, .none);
813 try renderToken(ais, tree, tree.firstToken(ptr_type.ast.bit_range_end) - 1, .none); // colon839 try renderToken(r, tree.firstToken(ptr_type.ast.bit_range_end) - 1, .none); // colon
814 try renderExpression(gpa, ais, tree, ptr_type.ast.bit_range_end, .none);840 try renderExpression(r, ptr_type.ast.bit_range_end, .none);
815 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.bit_range_end) + 1, .space); // rparen841 try renderToken(r, tree.lastToken(ptr_type.ast.bit_range_end) + 1, .space); // rparen
816 } else {842 } else {
817 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.align_node) + 1, .space); // rparen843 try renderToken(r, tree.lastToken(ptr_type.ast.align_node) + 1, .space); // rparen
818 }844 }
819 }845 }
820846
821 if (ptr_type.ast.addrspace_node != 0) {847 if (ptr_type.ast.addrspace_node != 0) {
822 const addrspace_first = tree.firstToken(ptr_type.ast.addrspace_node);848 const addrspace_first = tree.firstToken(ptr_type.ast.addrspace_node);
823 try renderToken(ais, tree, addrspace_first - 2, .none); // addrspace849 try renderToken(r, addrspace_first - 2, .none); // addrspace
824 try renderToken(ais, tree, addrspace_first - 1, .none); // lparen850 try renderToken(r, addrspace_first - 1, .none); // lparen
825 try renderExpression(gpa, ais, tree, ptr_type.ast.addrspace_node, .none);851 try renderExpression(r, ptr_type.ast.addrspace_node, .none);
826 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.addrspace_node) + 1, .space); // rparen852 try renderToken(r, tree.lastToken(ptr_type.ast.addrspace_node) + 1, .space); // rparen
827 }853 }
828854
829 if (ptr_type.const_token) |const_token| {855 if (ptr_type.const_token) |const_token| {
830 try renderToken(ais, tree, const_token, .space);856 try renderToken(r, const_token, .space);
831 }857 }
832858
833 if (ptr_type.volatile_token) |volatile_token| {859 if (ptr_type.volatile_token) |volatile_token| {
834 try renderToken(ais, tree, volatile_token, .space);860 try renderToken(r, volatile_token, .space);
835 }861 }
836862
837 try renderExpression(gpa, ais, tree, ptr_type.ast.child_type, space);863 try renderExpression(r, ptr_type.ast.child_type, space);
838}864}
839865
840fn renderSlice(866fn renderSlice(
841 gpa: Allocator,867 r: Render,
842 ais: *Ais,
843 tree: Ast,
844 slice_node: Ast.Node.Index,868 slice_node: Ast.Node.Index,
845 slice: Ast.full.Slice,869 slice: Ast.full.Slice,
846 space: Space,870 space: Space,
847) Error!void {871) Error!void {
872 const tree = r.tree;
848 const node_tags = tree.nodes.items(.tag);873 const node_tags = tree.nodes.items(.tag);
849 const after_start_space_bool = nodeCausesSliceOpSpace(node_tags[slice.ast.start]) or874 const after_start_space_bool = nodeCausesSliceOpSpace(node_tags[slice.ast.start]) or
850 if (slice.ast.end != 0) nodeCausesSliceOpSpace(node_tags[slice.ast.end]) else false;875 if (slice.ast.end != 0) nodeCausesSliceOpSpace(node_tags[slice.ast.end]) else false;
...@@ -853,33 +878,32 @@ fn renderSlice(...@@ -853,33 +878,32 @@ fn renderSlice(
853 after_start_space878 after_start_space
854 else if (slice.ast.sentinel != 0) Space.space else Space.none;879 else if (slice.ast.sentinel != 0) Space.space else Space.none;
855880
856 try renderExpression(gpa, ais, tree, slice.ast.sliced, .none);881 try renderExpression(r, slice.ast.sliced, .none);
857 try renderToken(ais, tree, slice.ast.lbracket, .none); // lbracket882 try renderToken(r, slice.ast.lbracket, .none); // lbracket
858883
859 const start_last = tree.lastToken(slice.ast.start);884 const start_last = tree.lastToken(slice.ast.start);
860 try renderExpression(gpa, ais, tree, slice.ast.start, after_start_space);885 try renderExpression(r, slice.ast.start, after_start_space);
861 try renderToken(ais, tree, start_last + 1, after_dots_space); // ellipsis2 ("..")886 try renderToken(r, start_last + 1, after_dots_space); // ellipsis2 ("..")
862887
863 if (slice.ast.end != 0) {888 if (slice.ast.end != 0) {
864 const after_end_space = if (slice.ast.sentinel != 0) Space.space else Space.none;889 const after_end_space = if (slice.ast.sentinel != 0) Space.space else Space.none;
865 try renderExpression(gpa, ais, tree, slice.ast.end, after_end_space);890 try renderExpression(r, slice.ast.end, after_end_space);
866 }891 }
867892
868 if (slice.ast.sentinel != 0) {893 if (slice.ast.sentinel != 0) {
869 try renderToken(ais, tree, tree.firstToken(slice.ast.sentinel) - 1, .none); // colon894 try renderToken(r, tree.firstToken(slice.ast.sentinel) - 1, .none); // colon
870 try renderExpression(gpa, ais, tree, slice.ast.sentinel, .none);895 try renderExpression(r, slice.ast.sentinel, .none);
871 }896 }
872897
873 try renderToken(ais, tree, tree.lastToken(slice_node), space); // rbracket898 try renderToken(r, tree.lastToken(slice_node), space); // rbracket
874}899}
875900
876fn renderAsmOutput(901fn renderAsmOutput(
877 gpa: Allocator,902 r: Render,
878 ais: *Ais,
879 tree: Ast,
880 asm_output: Ast.Node.Index,903 asm_output: Ast.Node.Index,
881 space: Space,904 space: Space,
882) Error!void {905) Error!void {
906 const tree = r.tree;
883 const token_tags = tree.tokens.items(.tag);907 const token_tags = tree.tokens.items(.tag);
884 const node_tags = tree.nodes.items(.tag);908 const node_tags = tree.nodes.items(.tag);
885 const main_tokens = tree.nodes.items(.main_token);909 const main_tokens = tree.nodes.items(.main_token);
...@@ -887,66 +911,79 @@ fn renderAsmOutput(...@@ -887,66 +911,79 @@ fn renderAsmOutput(
887 assert(node_tags[asm_output] == .asm_output);911 assert(node_tags[asm_output] == .asm_output);
888 const symbolic_name = main_tokens[asm_output];912 const symbolic_name = main_tokens[asm_output];
889913
890 try renderToken(ais, tree, symbolic_name - 1, .none); // lbracket914 try renderToken(r, symbolic_name - 1, .none); // lbracket
891 try renderToken(ais, tree, symbolic_name, .none); // ident915 try renderToken(r, symbolic_name, .none); // ident
892 try renderToken(ais, tree, symbolic_name + 1, .space); // rbracket916 try renderToken(r, symbolic_name + 1, .space); // rbracket
893 try renderToken(ais, tree, symbolic_name + 2, .space); // "constraint"917 try renderToken(r, symbolic_name + 2, .space); // "constraint"
894 try renderToken(ais, tree, symbolic_name + 3, .none); // lparen918 try renderToken(r, symbolic_name + 3, .none); // lparen
895919
896 if (token_tags[symbolic_name + 4] == .arrow) {920 if (token_tags[symbolic_name + 4] == .arrow) {
897 try renderToken(ais, tree, symbolic_name + 4, .space); // ->921 try renderToken(r, symbolic_name + 4, .space); // ->
898 try renderExpression(gpa, ais, tree, datas[asm_output].lhs, Space.none);922 try renderExpression(r, datas[asm_output].lhs, Space.none);
899 return renderToken(ais, tree, datas[asm_output].rhs, space); // rparen923 return renderToken(r, datas[asm_output].rhs, space); // rparen
900 } else {924 } else {
901 try renderToken(ais, tree, symbolic_name + 4, .none); // ident925 try renderToken(r, symbolic_name + 4, .none); // ident
902 return renderToken(ais, tree, symbolic_name + 5, space); // rparen926 return renderToken(r, symbolic_name + 5, space); // rparen
903 }927 }
904}928}
905929
906fn renderAsmInput(930fn renderAsmInput(
907 gpa: Allocator,931 r: Render,
908 ais: *Ais,
909 tree: Ast,
910 asm_input: Ast.Node.Index,932 asm_input: Ast.Node.Index,
911 space: Space,933 space: Space,
912) Error!void {934) Error!void {
935 const tree = r.tree;
913 const node_tags = tree.nodes.items(.tag);936 const node_tags = tree.nodes.items(.tag);
914 const main_tokens = tree.nodes.items(.main_token);937 const main_tokens = tree.nodes.items(.main_token);
915 const datas = tree.nodes.items(.data);938 const datas = tree.nodes.items(.data);
916 assert(node_tags[asm_input] == .asm_input);939 assert(node_tags[asm_input] == .asm_input);
917 const symbolic_name = main_tokens[asm_input];940 const symbolic_name = main_tokens[asm_input];
918941
919 try renderToken(ais, tree, symbolic_name - 1, .none); // lbracket942 try renderToken(r, symbolic_name - 1, .none); // lbracket
920 try renderToken(ais, tree, symbolic_name, .none); // ident943 try renderToken(r, symbolic_name, .none); // ident
921 try renderToken(ais, tree, symbolic_name + 1, .space); // rbracket944 try renderToken(r, symbolic_name + 1, .space); // rbracket
922 try renderToken(ais, tree, symbolic_name + 2, .space); // "constraint"945 try renderToken(r, symbolic_name + 2, .space); // "constraint"
923 try renderToken(ais, tree, symbolic_name + 3, .none); // lparen946 try renderToken(r, symbolic_name + 3, .none); // lparen
924 try renderExpression(gpa, ais, tree, datas[asm_input].lhs, Space.none);947 try renderExpression(r, datas[asm_input].lhs, Space.none);
925 return renderToken(ais, tree, datas[asm_input].rhs, space); // rparen948 return renderToken(r, datas[asm_input].rhs, space); // rparen
949}
950
951fn renderVarDecl(r: Render, var_decl: Ast.full.VarDecl) Error!void {
952 try renderVarDeclWithoutFixups(r, var_decl);
953 if (r.fixups.unused_var_decls.contains(var_decl.ast.mut_token)) {
954 // Discard the variable like this: `_ = foo;`
955 const w = r.ais.writer();
956 try w.writeAll("_ = ");
957 try w.writeAll(tokenSliceForRender(r.tree, var_decl.ast.mut_token + 1));
958 try w.writeAll(";\n");
959 }
926}960}
927961
928fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDecl) Error!void {962fn renderVarDeclWithoutFixups(r: Render, var_decl: Ast.full.VarDecl) Error!void {
963 const tree = r.tree;
964 const ais = r.ais;
965
929 if (var_decl.visib_token) |visib_token| {966 if (var_decl.visib_token) |visib_token| {
930 try renderToken(ais, tree, visib_token, Space.space); // pub967 try renderToken(r, visib_token, Space.space); // pub
931 }968 }
932969
933 if (var_decl.extern_export_token) |extern_export_token| {970 if (var_decl.extern_export_token) |extern_export_token| {
934 try renderToken(ais, tree, extern_export_token, Space.space); // extern971 try renderToken(r, extern_export_token, Space.space); // extern
935972
936 if (var_decl.lib_name) |lib_name| {973 if (var_decl.lib_name) |lib_name| {
937 try renderToken(ais, tree, lib_name, Space.space); // "lib"974 try renderToken(r, lib_name, Space.space); // "lib"
938 }975 }
939 }976 }
940977
941 if (var_decl.threadlocal_token) |thread_local_token| {978 if (var_decl.threadlocal_token) |thread_local_token| {
942 try renderToken(ais, tree, thread_local_token, Space.space); // threadlocal979 try renderToken(r, thread_local_token, Space.space); // threadlocal
943 }980 }
944981
945 if (var_decl.comptime_token) |comptime_token| {982 if (var_decl.comptime_token) |comptime_token| {
946 try renderToken(ais, tree, comptime_token, Space.space); // comptime983 try renderToken(r, comptime_token, Space.space); // comptime
947 }984 }
948985
949 try renderToken(ais, tree, var_decl.ast.mut_token, .space); // var986 try renderToken(r, var_decl.ast.mut_token, .space); // var
950987
951 const name_space = if (var_decl.ast.type_node == 0 and988 const name_space = if (var_decl.ast.type_node == 0 and
952 (var_decl.ast.align_node != 0 or989 (var_decl.ast.align_node != 0 or
...@@ -956,18 +993,18 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec...@@ -956,18 +993,18 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec
956 Space.space993 Space.space
957 else994 else
958 Space.none;995 Space.none;
959 try renderToken(ais, tree, var_decl.ast.mut_token + 1, name_space); // name996 try renderToken(r, var_decl.ast.mut_token + 1, name_space); // name
960997
961 if (var_decl.ast.type_node != 0) {998 if (var_decl.ast.type_node != 0) {
962 try renderToken(ais, tree, var_decl.ast.mut_token + 2, Space.space); // :999 try renderToken(r, var_decl.ast.mut_token + 2, Space.space); // :
963 if (var_decl.ast.align_node != 0 or var_decl.ast.addrspace_node != 0 or1000 if (var_decl.ast.align_node != 0 or var_decl.ast.addrspace_node != 0 or
964 var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0)1001 var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0)
965 {1002 {
966 try renderExpression(gpa, ais, tree, var_decl.ast.type_node, .space);1003 try renderExpression(r, var_decl.ast.type_node, .space);
967 } else {1004 } else {
968 try renderExpression(gpa, ais, tree, var_decl.ast.type_node, .none);1005 try renderExpression(r, var_decl.ast.type_node, .none);
969 const semicolon = tree.lastToken(var_decl.ast.type_node) + 1;1006 const semicolon = tree.lastToken(var_decl.ast.type_node) + 1;
970 return renderToken(ais, tree, semicolon, Space.newline); // ;1007 return renderToken(r, semicolon, Space.newline); // ;
971 }1008 }
972 }1009 }
9731010
...@@ -975,16 +1012,16 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec...@@ -975,16 +1012,16 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec
975 const lparen = tree.firstToken(var_decl.ast.align_node) - 1;1012 const lparen = tree.firstToken(var_decl.ast.align_node) - 1;
976 const align_kw = lparen - 1;1013 const align_kw = lparen - 1;
977 const rparen = tree.lastToken(var_decl.ast.align_node) + 1;1014 const rparen = tree.lastToken(var_decl.ast.align_node) + 1;
978 try renderToken(ais, tree, align_kw, Space.none); // align1015 try renderToken(r, align_kw, Space.none); // align
979 try renderToken(ais, tree, lparen, Space.none); // (1016 try renderToken(r, lparen, Space.none); // (
980 try renderExpression(gpa, ais, tree, var_decl.ast.align_node, Space.none);1017 try renderExpression(r, var_decl.ast.align_node, Space.none);
981 if (var_decl.ast.addrspace_node != 0 or var_decl.ast.section_node != 0 or1018 if (var_decl.ast.addrspace_node != 0 or var_decl.ast.section_node != 0 or
982 var_decl.ast.init_node != 0)1019 var_decl.ast.init_node != 0)
983 {1020 {
984 try renderToken(ais, tree, rparen, .space); // )1021 try renderToken(r, rparen, .space); // )
985 } else {1022 } else {
986 try renderToken(ais, tree, rparen, .none); // )1023 try renderToken(r, rparen, .none); // )
987 return renderToken(ais, tree, rparen + 1, Space.newline); // ;1024 return renderToken(r, rparen + 1, Space.newline); // ;
988 }1025 }
989 }1026 }
9901027
...@@ -992,14 +1029,14 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec...@@ -992,14 +1029,14 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec
992 const lparen = tree.firstToken(var_decl.ast.addrspace_node) - 1;1029 const lparen = tree.firstToken(var_decl.ast.addrspace_node) - 1;
993 const addrspace_kw = lparen - 1;1030 const addrspace_kw = lparen - 1;
994 const rparen = tree.lastToken(var_decl.ast.addrspace_node) + 1;1031 const rparen = tree.lastToken(var_decl.ast.addrspace_node) + 1;
995 try renderToken(ais, tree, addrspace_kw, Space.none); // addrspace1032 try renderToken(r, addrspace_kw, Space.none); // addrspace
996 try renderToken(ais, tree, lparen, Space.none); // (1033 try renderToken(r, lparen, Space.none); // (
997 try renderExpression(gpa, ais, tree, var_decl.ast.addrspace_node, Space.none);1034 try renderExpression(r, var_decl.ast.addrspace_node, Space.none);
998 if (var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0) {1035 if (var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0) {
999 try renderToken(ais, tree, rparen, .space); // )1036 try renderToken(r, rparen, .space); // )
1000 } else {1037 } else {
1001 try renderToken(ais, tree, rparen, .none); // )1038 try renderToken(r, rparen, .none); // )
1002 return renderToken(ais, tree, rparen + 1, Space.newline); // ;1039 return renderToken(r, rparen + 1, Space.newline); // ;
1003 }1040 }
1004 }1041 }
10051042
...@@ -1007,14 +1044,14 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec...@@ -1007,14 +1044,14 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec
1007 const lparen = tree.firstToken(var_decl.ast.section_node) - 1;1044 const lparen = tree.firstToken(var_decl.ast.section_node) - 1;
1008 const section_kw = lparen - 1;1045 const section_kw = lparen - 1;
1009 const rparen = tree.lastToken(var_decl.ast.section_node) + 1;1046 const rparen = tree.lastToken(var_decl.ast.section_node) + 1;
1010 try renderToken(ais, tree, section_kw, Space.none); // linksection1047 try renderToken(r, section_kw, Space.none); // linksection
1011 try renderToken(ais, tree, lparen, Space.none); // (1048 try renderToken(r, lparen, Space.none); // (
1012 try renderExpression(gpa, ais, tree, var_decl.ast.section_node, Space.none);1049 try renderExpression(r, var_decl.ast.section_node, Space.none);
1013 if (var_decl.ast.init_node != 0) {1050 if (var_decl.ast.init_node != 0) {
1014 try renderToken(ais, tree, rparen, .space); // )1051 try renderToken(r, rparen, .space); // )
1015 } else {1052 } else {
1016 try renderToken(ais, tree, rparen, .none); // )1053 try renderToken(r, rparen, .none); // )
1017 return renderToken(ais, tree, rparen + 1, Space.newline); // ;1054 return renderToken(r, rparen + 1, Space.newline); // ;
1018 }1055 }
1019 }1056 }
10201057
...@@ -1023,17 +1060,17 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec...@@ -1023,17 +1060,17 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec
1023 const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline;1060 const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline;
1024 {1061 {
1025 ais.pushIndent();1062 ais.pushIndent();
1026 try renderToken(ais, tree, eq_token, eq_space); // =1063 try renderToken(r, eq_token, eq_space); // =
1027 ais.popIndent();1064 ais.popIndent();
1028 }1065 }
1029 ais.pushIndentOneShot();1066 ais.pushIndentOneShot();
1030 return renderExpression(gpa, ais, tree, var_decl.ast.init_node, .semicolon); // ;1067 return renderExpression(r, var_decl.ast.init_node, .semicolon); // ;
1031 }1068 }
1032 return renderToken(ais, tree, var_decl.ast.mut_token + 2, .newline); // ;1069 return renderToken(r, var_decl.ast.mut_token + 2, .newline); // ;
1033}1070}
10341071
1035fn renderIf(gpa: Allocator, ais: *Ais, tree: Ast, if_node: Ast.full.If, space: Space) Error!void {1072fn renderIf(r: Render, if_node: Ast.full.If, space: Space) Error!void {
1036 return renderWhile(gpa, ais, tree, .{1073 return renderWhile(r, .{
1037 .ast = .{1074 .ast = .{
1038 .while_token = if_node.ast.if_token,1075 .while_token = if_node.ast.if_token,
1039 .cond_expr = if_node.ast.cond_expr,1076 .cond_expr = if_node.ast.cond_expr,
...@@ -1051,41 +1088,43 @@ fn renderIf(gpa: Allocator, ais: *Ais, tree: Ast, if_node: Ast.full.If, space: S...@@ -1051,41 +1088,43 @@ fn renderIf(gpa: Allocator, ais: *Ais, tree: Ast, if_node: Ast.full.If, space: S
10511088
1052/// Note that this function is additionally used to render if and for expressions, with1089/// Note that this function is additionally used to render if and for expressions, with
1053/// respective values set to null.1090/// respective values set to null.
1054fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While, space: Space) Error!void {1091fn renderWhile(r: Render, while_node: Ast.full.While, space: Space) Error!void {
1092 const tree = r.tree;
1093 const ais = r.ais;
1055 const node_tags = tree.nodes.items(.tag);1094 const node_tags = tree.nodes.items(.tag);
1056 const token_tags = tree.tokens.items(.tag);1095 const token_tags = tree.tokens.items(.tag);
10571096
1058 if (while_node.label_token) |label| {1097 if (while_node.label_token) |label| {
1059 try renderToken(ais, tree, label, .none); // label1098 try renderToken(r, label, .none); // label
1060 try renderToken(ais, tree, label + 1, .space); // :1099 try renderToken(r, label + 1, .space); // :
1061 }1100 }
10621101
1063 if (while_node.inline_token) |inline_token| {1102 if (while_node.inline_token) |inline_token| {
1064 try renderToken(ais, tree, inline_token, .space); // inline1103 try renderToken(r, inline_token, .space); // inline
1065 }1104 }
10661105
1067 try renderToken(ais, tree, while_node.ast.while_token, .space); // if/for/while1106 try renderToken(r, while_node.ast.while_token, .space); // if/for/while
1068 try renderToken(ais, tree, while_node.ast.while_token + 1, .none); // lparen1107 try renderToken(r, while_node.ast.while_token + 1, .none); // lparen
1069 try renderExpression(gpa, ais, tree, while_node.ast.cond_expr, .none); // condition1108 try renderExpression(r, while_node.ast.cond_expr, .none); // condition
10701109
1071 var last_prefix_token = tree.lastToken(while_node.ast.cond_expr) + 1; // rparen1110 var last_prefix_token = tree.lastToken(while_node.ast.cond_expr) + 1; // rparen
10721111
1073 if (while_node.payload_token) |payload_token| {1112 if (while_node.payload_token) |payload_token| {
1074 try renderToken(ais, tree, last_prefix_token, .space);1113 try renderToken(r, last_prefix_token, .space);
1075 try renderToken(ais, tree, payload_token - 1, .none); // |1114 try renderToken(r, payload_token - 1, .none); // |
1076 const ident = blk: {1115 const ident = blk: {
1077 if (token_tags[payload_token] == .asterisk) {1116 if (token_tags[payload_token] == .asterisk) {
1078 try renderToken(ais, tree, payload_token, .none); // *1117 try renderToken(r, payload_token, .none); // *
1079 break :blk payload_token + 1;1118 break :blk payload_token + 1;
1080 } else {1119 } else {
1081 break :blk payload_token;1120 break :blk payload_token;
1082 }1121 }
1083 };1122 };
1084 try renderToken(ais, tree, ident, .none); // identifier1123 try renderToken(r, ident, .none); // identifier
1085 const pipe = blk: {1124 const pipe = blk: {
1086 if (token_tags[ident + 1] == .comma) {1125 if (token_tags[ident + 1] == .comma) {
1087 try renderToken(ais, tree, ident + 1, .space); // ,1126 try renderToken(r, ident + 1, .space); // ,
1088 try renderToken(ais, tree, ident + 2, .none); // index1127 try renderToken(r, ident + 2, .none); // index
1089 break :blk ident + 3;1128 break :blk ident + 3;
1090 } else {1129 } else {
1091 break :blk ident + 1;1130 break :blk ident + 1;
...@@ -1095,11 +1134,11 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While,...@@ -1095,11 +1134,11 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While,
1095 }1134 }
10961135
1097 if (while_node.ast.cont_expr != 0) {1136 if (while_node.ast.cont_expr != 0) {
1098 try renderToken(ais, tree, last_prefix_token, .space);1137 try renderToken(r, last_prefix_token, .space);
1099 const lparen = tree.firstToken(while_node.ast.cont_expr) - 1;1138 const lparen = tree.firstToken(while_node.ast.cont_expr) - 1;
1100 try renderToken(ais, tree, lparen - 1, .space); // :1139 try renderToken(r, lparen - 1, .space); // :
1101 try renderToken(ais, tree, lparen, .none); // lparen1140 try renderToken(r, lparen, .none); // lparen
1102 try renderExpression(gpa, ais, tree, while_node.ast.cont_expr, .none);1141 try renderExpression(r, while_node.ast.cont_expr, .none);
1103 last_prefix_token = tree.lastToken(while_node.ast.cont_expr) + 1; // rparen1142 last_prefix_token = tree.lastToken(while_node.ast.cont_expr) + 1; // rparen
1104 }1143 }
11051144
...@@ -1108,27 +1147,27 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While,...@@ -1108,27 +1147,27 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While,
1108 !tree.tokensOnSameLine(last_prefix_token, tree.firstToken(while_node.ast.then_expr));1147 !tree.tokensOnSameLine(last_prefix_token, tree.firstToken(while_node.ast.then_expr));
1109 if (indent_then_expr or (then_expr_is_block and ais.isLineOverIndented())) {1148 if (indent_then_expr or (then_expr_is_block and ais.isLineOverIndented())) {
1110 ais.pushIndentNextLine();1149 ais.pushIndentNextLine();
1111 try renderToken(ais, tree, last_prefix_token, .newline);1150 try renderToken(r, last_prefix_token, .newline);
1112 ais.popIndent();1151 ais.popIndent();
1113 } else {1152 } else {
1114 try renderToken(ais, tree, last_prefix_token, .space);1153 try renderToken(r, last_prefix_token, .space);
1115 }1154 }
11161155
1117 if (while_node.ast.else_expr != 0) {1156 if (while_node.ast.else_expr != 0) {
1118 if (indent_then_expr) {1157 if (indent_then_expr) {
1119 ais.pushIndent();1158 ais.pushIndent();
1120 try renderExpression(gpa, ais, tree, while_node.ast.then_expr, .newline);1159 try renderExpression(r, while_node.ast.then_expr, .newline);
1121 ais.popIndent();1160 ais.popIndent();
1122 } else {1161 } else {
1123 try renderExpression(gpa, ais, tree, while_node.ast.then_expr, .space);1162 try renderExpression(r, while_node.ast.then_expr, .space);
1124 }1163 }
11251164
1126 var last_else_token = while_node.else_token;1165 var last_else_token = while_node.else_token;
11271166
1128 if (while_node.error_token) |error_token| {1167 if (while_node.error_token) |error_token| {
1129 try renderToken(ais, tree, while_node.else_token, .space); // else1168 try renderToken(r, while_node.else_token, .space); // else
1130 try renderToken(ais, tree, error_token - 1, .none); // |1169 try renderToken(r, error_token - 1, .none); // |
1131 try renderToken(ais, tree, error_token, .none); // identifier1170 try renderToken(r, error_token, .none); // identifier
1132 last_else_token = error_token + 1; // |1171 last_else_token = error_token + 1; // |
1133 }1172 }
11341173
...@@ -1137,111 +1176,107 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While,...@@ -1137,111 +1176,107 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While,
1137 !nodeIsIfForWhileSwitch(node_tags[while_node.ast.else_expr]);1176 !nodeIsIfForWhileSwitch(node_tags[while_node.ast.else_expr]);
1138 if (indent_else_expr) {1177 if (indent_else_expr) {
1139 ais.pushIndentNextLine();1178 ais.pushIndentNextLine();
1140 try renderToken(ais, tree, last_else_token, .newline);1179 try renderToken(r, last_else_token, .newline);
1141 ais.popIndent();1180 ais.popIndent();
1142 try renderExpressionIndented(gpa, ais, tree, while_node.ast.else_expr, space);1181 try renderExpressionIndented(r, while_node.ast.else_expr, space);
1143 } else {1182 } else {
1144 try renderToken(ais, tree, last_else_token, .space);1183 try renderToken(r, last_else_token, .space);
1145 try renderExpression(gpa, ais, tree, while_node.ast.else_expr, space);1184 try renderExpression(r, while_node.ast.else_expr, space);
1146 }1185 }
1147 } else {1186 } else {
1148 if (indent_then_expr) {1187 if (indent_then_expr) {
1149 try renderExpressionIndented(gpa, ais, tree, while_node.ast.then_expr, space);1188 try renderExpressionIndented(r, while_node.ast.then_expr, space);
1150 } else {1189 } else {
1151 try renderExpression(gpa, ais, tree, while_node.ast.then_expr, space);1190 try renderExpression(r, while_node.ast.then_expr, space);
1152 }1191 }
1153 }1192 }
1154}1193}
11551194
1156fn renderContainerField(1195fn renderContainerField(r: Render, field: Ast.full.ContainerField, space: Space) Error!void {
1157 gpa: Allocator,1196 const tree = r.tree;
1158 ais: *Ais,1197 const ais = r.ais;
1159 tree: Ast,
1160 field: Ast.full.ContainerField,
1161 space: Space,
1162) Error!void {
1163 if (field.comptime_token) |t| {1198 if (field.comptime_token) |t| {
1164 try renderToken(ais, tree, t, .space); // comptime1199 try renderToken(r, t, .space); // comptime
1165 }1200 }
1166 if (field.ast.type_expr == 0 and field.ast.value_expr == 0) {1201 if (field.ast.type_expr == 0 and field.ast.value_expr == 0) {
1167 return renderTokenComma(ais, tree, field.ast.name_token, space); // name1202 return renderTokenComma(r, field.ast.name_token, space); // name
1168 }1203 }
1169 if (field.ast.type_expr != 0 and field.ast.value_expr == 0) {1204 if (field.ast.type_expr != 0 and field.ast.value_expr == 0) {
1170 try renderToken(ais, tree, field.ast.name_token, .none); // name1205 try renderToken(r, field.ast.name_token, .none); // name
1171 try renderToken(ais, tree, field.ast.name_token + 1, .space); // :1206 try renderToken(r, field.ast.name_token + 1, .space); // :
11721207
1173 if (field.ast.align_expr != 0) {1208 if (field.ast.align_expr != 0) {
1174 try renderExpression(gpa, ais, tree, field.ast.type_expr, .space); // type1209 try renderExpression(r, field.ast.type_expr, .space); // type
1175 const align_token = tree.firstToken(field.ast.align_expr) - 2;1210 const align_token = tree.firstToken(field.ast.align_expr) - 2;
1176 try renderToken(ais, tree, align_token, .none); // align1211 try renderToken(r, align_token, .none); // align
1177 try renderToken(ais, tree, align_token + 1, .none); // (1212 try renderToken(r, align_token + 1, .none); // (
1178 try renderExpression(gpa, ais, tree, field.ast.align_expr, .none); // alignment1213 try renderExpression(r, field.ast.align_expr, .none); // alignment
1179 const rparen = tree.lastToken(field.ast.align_expr) + 1;1214 const rparen = tree.lastToken(field.ast.align_expr) + 1;
1180 return renderTokenComma(ais, tree, rparen, space); // )1215 return renderTokenComma(r, rparen, space); // )
1181 } else {1216 } else {
1182 return renderExpressionComma(gpa, ais, tree, field.ast.type_expr, space); // type1217 return renderExpressionComma(r, field.ast.type_expr, space); // type
1183 }1218 }
1184 }1219 }
1185 if (field.ast.type_expr == 0 and field.ast.value_expr != 0) {1220 if (field.ast.type_expr == 0 and field.ast.value_expr != 0) {
1186 try renderToken(ais, tree, field.ast.name_token, .space); // name1221 try renderToken(r, field.ast.name_token, .space); // name
1187 try renderToken(ais, tree, field.ast.name_token + 1, .space); // =1222 try renderToken(r, field.ast.name_token + 1, .space); // =
1188 return renderExpressionComma(gpa, ais, tree, field.ast.value_expr, space); // value1223 return renderExpressionComma(r, field.ast.value_expr, space); // value
1189 }1224 }
11901225
1191 try renderToken(ais, tree, field.ast.name_token, .none); // name1226 try renderToken(r, field.ast.name_token, .none); // name
1192 try renderToken(ais, tree, field.ast.name_token + 1, .space); // :1227 try renderToken(r, field.ast.name_token + 1, .space); // :
1193 try renderExpression(gpa, ais, tree, field.ast.type_expr, .space); // type1228 try renderExpression(r, field.ast.type_expr, .space); // type
11941229
1195 if (field.ast.align_expr != 0) {1230 if (field.ast.align_expr != 0) {
1196 const lparen_token = tree.firstToken(field.ast.align_expr) - 1;1231 const lparen_token = tree.firstToken(field.ast.align_expr) - 1;
1197 const align_kw = lparen_token - 1;1232 const align_kw = lparen_token - 1;
1198 const rparen_token = tree.lastToken(field.ast.align_expr) + 1;1233 const rparen_token = tree.lastToken(field.ast.align_expr) + 1;
1199 try renderToken(ais, tree, align_kw, .none); // align1234 try renderToken(r, align_kw, .none); // align
1200 try renderToken(ais, tree, lparen_token, .none); // (1235 try renderToken(r, lparen_token, .none); // (
1201 try renderExpression(gpa, ais, tree, field.ast.align_expr, .none); // alignment1236 try renderExpression(r, field.ast.align_expr, .none); // alignment
1202 try renderToken(ais, tree, rparen_token, .space); // )1237 try renderToken(r, rparen_token, .space); // )
1203 }1238 }
1204 const eq_token = tree.firstToken(field.ast.value_expr) - 1;1239 const eq_token = tree.firstToken(field.ast.value_expr) - 1;
1205 const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline;1240 const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline;
1206 {1241 {
1207 ais.pushIndent();1242 ais.pushIndent();
1208 try renderToken(ais, tree, eq_token, eq_space); // =1243 try renderToken(r, eq_token, eq_space); // =
1209 ais.popIndent();1244 ais.popIndent();
1210 }1245 }
12111246
1212 if (eq_space == .space)1247 if (eq_space == .space)
1213 return renderExpressionComma(gpa, ais, tree, field.ast.value_expr, space); // value1248 return renderExpressionComma(r, field.ast.value_expr, space); // value
12141249
1215 const token_tags = tree.tokens.items(.tag);1250 const token_tags = tree.tokens.items(.tag);
1216 const maybe_comma = tree.lastToken(field.ast.value_expr) + 1;1251 const maybe_comma = tree.lastToken(field.ast.value_expr) + 1;
12171252
1218 if (token_tags[maybe_comma] == .comma) {1253 if (token_tags[maybe_comma] == .comma) {
1219 ais.pushIndent();1254 ais.pushIndent();
1220 try renderExpression(gpa, ais, tree, field.ast.value_expr, .none); // value1255 try renderExpression(r, field.ast.value_expr, .none); // value
1221 ais.popIndent();1256 ais.popIndent();
1222 try renderToken(ais, tree, maybe_comma, .newline);1257 try renderToken(r, maybe_comma, .newline);
1223 } else {1258 } else {
1224 ais.pushIndent();1259 ais.pushIndent();
1225 try renderExpression(gpa, ais, tree, field.ast.value_expr, space); // value1260 try renderExpression(r, field.ast.value_expr, space); // value
1226 ais.popIndent();1261 ais.popIndent();
1227 }1262 }
1228}1263}
12291264
1230fn renderBuiltinCall(1265fn renderBuiltinCall(
1231 gpa: Allocator,1266 r: Render,
1232 ais: *Ais,
1233 tree: Ast,
1234 builtin_token: Ast.TokenIndex,1267 builtin_token: Ast.TokenIndex,
1235 params: []const Ast.Node.Index,1268 params: []const Ast.Node.Index,
1236 space: Space,1269 space: Space,
1237) Error!void {1270) Error!void {
1271 const tree = r.tree;
1272 const ais = r.ais;
1238 const token_tags = tree.tokens.items(.tag);1273 const token_tags = tree.tokens.items(.tag);
12391274
1240 try renderToken(ais, tree, builtin_token, .none); // @name1275 try renderToken(r, builtin_token, .none); // @name
12411276
1242 if (params.len == 0) {1277 if (params.len == 0) {
1243 try renderToken(ais, tree, builtin_token + 1, .none); // (1278 try renderToken(r, builtin_token + 1, .none); // (
1244 return renderToken(ais, tree, builtin_token + 2, space); // )1279 return renderToken(r, builtin_token + 2, space); // )
1245 }1280 }
12461281
1247 const last_param = params[params.len - 1];1282 const last_param = params[params.len - 1];
...@@ -1249,7 +1284,7 @@ fn renderBuiltinCall(...@@ -1249,7 +1284,7 @@ fn renderBuiltinCall(
12491284
1250 if (token_tags[after_last_param_token] != .comma) {1285 if (token_tags[after_last_param_token] != .comma) {
1251 // Render all on one line, no trailing comma.1286 // Render all on one line, no trailing comma.
1252 try renderToken(ais, tree, builtin_token + 1, .none); // (1287 try renderToken(r, builtin_token + 1, .none); // (
12531288
1254 for (params) |param_node, i| {1289 for (params) |param_node, i| {
1255 const first_param_token = tree.firstToken(param_node);1290 const first_param_token = tree.firstToken(param_node);
...@@ -1258,39 +1293,41 @@ fn renderBuiltinCall(...@@ -1258,39 +1293,41 @@ fn renderBuiltinCall(
1258 {1293 {
1259 ais.pushIndentOneShot();1294 ais.pushIndentOneShot();
1260 }1295 }
1261 try renderExpression(gpa, ais, tree, param_node, .none);1296 try renderExpression(r, param_node, .none);
12621297
1263 if (i + 1 < params.len) {1298 if (i + 1 < params.len) {
1264 const comma_token = tree.lastToken(param_node) + 1;1299 const comma_token = tree.lastToken(param_node) + 1;
1265 try renderToken(ais, tree, comma_token, .space); // ,1300 try renderToken(r, comma_token, .space); // ,
1266 }1301 }
1267 }1302 }
1268 return renderToken(ais, tree, after_last_param_token, space); // )1303 return renderToken(r, after_last_param_token, space); // )
1269 } else {1304 } else {
1270 // Render one param per line.1305 // Render one param per line.
1271 ais.pushIndent();1306 ais.pushIndent();
1272 try renderToken(ais, tree, builtin_token + 1, Space.newline); // (1307 try renderToken(r, builtin_token + 1, Space.newline); // (
12731308
1274 for (params) |param_node| {1309 for (params) |param_node| {
1275 try renderExpression(gpa, ais, tree, param_node, .comma);1310 try renderExpression(r, param_node, .comma);
1276 }1311 }
1277 ais.popIndent();1312 ais.popIndent();
12781313
1279 return renderToken(ais, tree, after_last_param_token + 1, space); // )1314 return renderToken(r, after_last_param_token + 1, space); // )
1280 }1315 }
1281}1316}
12821317
1283fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProto, space: Space) Error!void {1318fn renderFnProto(r: Render, fn_proto: Ast.full.FnProto, space: Space) Error!void {
1319 const tree = r.tree;
1320 const ais = r.ais;
1284 const token_tags = tree.tokens.items(.tag);1321 const token_tags = tree.tokens.items(.tag);
1285 const token_starts = tree.tokens.items(.start);1322 const token_starts = tree.tokens.items(.start);
12861323
1287 const after_fn_token = fn_proto.ast.fn_token + 1;1324 const after_fn_token = fn_proto.ast.fn_token + 1;
1288 const lparen = if (token_tags[after_fn_token] == .identifier) blk: {1325 const lparen = if (token_tags[after_fn_token] == .identifier) blk: {
1289 try renderToken(ais, tree, fn_proto.ast.fn_token, .space); // fn1326 try renderToken(r, fn_proto.ast.fn_token, .space); // fn
1290 try renderToken(ais, tree, after_fn_token, .none); // name1327 try renderToken(r, after_fn_token, .none); // name
1291 break :blk after_fn_token + 1;1328 break :blk after_fn_token + 1;
1292 } else blk: {1329 } else blk: {
1293 try renderToken(ais, tree, fn_proto.ast.fn_token, .space); // fn1330 try renderToken(r, fn_proto.ast.fn_token, .space); // fn
1294 break :blk fn_proto.ast.fn_token + 1;1331 break :blk fn_proto.ast.fn_token + 1;
1295 };1332 };
1296 assert(token_tags[lparen] == .l_paren);1333 assert(token_tags[lparen] == .l_paren);
...@@ -1342,7 +1379,7 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt...@@ -1342,7 +1379,7 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt
1342 const trailing_comma = token_tags[rparen - 1] == .comma;1379 const trailing_comma = token_tags[rparen - 1] == .comma;
1343 if (!trailing_comma and !hasComment(tree, lparen, rparen)) {1380 if (!trailing_comma and !hasComment(tree, lparen, rparen)) {
1344 // Render all on one line, no trailing comma.1381 // Render all on one line, no trailing comma.
1345 try renderToken(ais, tree, lparen, .none); // (1382 try renderToken(r, lparen, .none); // (
13461383
1347 var param_i: usize = 0;1384 var param_i: usize = 0;
1348 var last_param_token = lparen;1385 var last_param_token = lparen;
...@@ -1350,25 +1387,25 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt...@@ -1350,25 +1387,25 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt
1350 last_param_token += 1;1387 last_param_token += 1;
1351 switch (token_tags[last_param_token]) {1388 switch (token_tags[last_param_token]) {
1352 .doc_comment => {1389 .doc_comment => {
1353 try renderToken(ais, tree, last_param_token, .newline);1390 try renderToken(r, last_param_token, .newline);
1354 continue;1391 continue;
1355 },1392 },
1356 .ellipsis3 => {1393 .ellipsis3 => {
1357 try renderToken(ais, tree, last_param_token, .none); // ...1394 try renderToken(r, last_param_token, .none); // ...
1358 break;1395 break;
1359 },1396 },
1360 .keyword_noalias, .keyword_comptime => {1397 .keyword_noalias, .keyword_comptime => {
1361 try renderToken(ais, tree, last_param_token, .space);1398 try renderToken(r, last_param_token, .space);
1362 last_param_token += 1;1399 last_param_token += 1;
1363 },1400 },
1364 .identifier => {},1401 .identifier => {},
1365 .keyword_anytype => {1402 .keyword_anytype => {
1366 try renderToken(ais, tree, last_param_token, .none); // anytype1403 try renderToken(r, last_param_token, .none); // anytype
1367 continue;1404 continue;
1368 },1405 },
1369 .r_paren => break,1406 .r_paren => break,
1370 .comma => {1407 .comma => {
1371 try renderToken(ais, tree, last_param_token, .space); // ,1408 try renderToken(r, last_param_token, .space); // ,
1372 continue;1409 continue;
1373 },1410 },
1374 else => {}, // Parameter type without a name.1411 else => {}, // Parameter type without a name.
...@@ -1376,24 +1413,24 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt...@@ -1376,24 +1413,24 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt
1376 if (token_tags[last_param_token] == .identifier and1413 if (token_tags[last_param_token] == .identifier and
1377 token_tags[last_param_token + 1] == .colon)1414 token_tags[last_param_token + 1] == .colon)
1378 {1415 {
1379 try renderToken(ais, tree, last_param_token, .none); // name1416 try renderToken(r, last_param_token, .none); // name
1380 last_param_token += 1;1417 last_param_token += 1;
1381 try renderToken(ais, tree, last_param_token, .space); // :1418 try renderToken(r, last_param_token, .space); // :
1382 last_param_token += 1;1419 last_param_token += 1;
1383 }1420 }
1384 if (token_tags[last_param_token] == .keyword_anytype) {1421 if (token_tags[last_param_token] == .keyword_anytype) {
1385 try renderToken(ais, tree, last_param_token, .none); // anytype1422 try renderToken(r, last_param_token, .none); // anytype
1386 continue;1423 continue;
1387 }1424 }
1388 const param = fn_proto.ast.params[param_i];1425 const param = fn_proto.ast.params[param_i];
1389 param_i += 1;1426 param_i += 1;
1390 try renderExpression(gpa, ais, tree, param, .none);1427 try renderExpression(r, param, .none);
1391 last_param_token = tree.lastToken(param);1428 last_param_token = tree.lastToken(param);
1392 }1429 }
1393 } else {1430 } else {
1394 // One param per line.1431 // One param per line.
1395 ais.pushIndent();1432 ais.pushIndent();
1396 try renderToken(ais, tree, lparen, .newline); // (1433 try renderToken(r, lparen, .newline); // (
13971434
1398 var param_i: usize = 0;1435 var param_i: usize = 0;
1399 var last_param_token = lparen;1436 var last_param_token = lparen;
...@@ -1401,20 +1438,20 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt...@@ -1401,20 +1438,20 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt
1401 last_param_token += 1;1438 last_param_token += 1;
1402 switch (token_tags[last_param_token]) {1439 switch (token_tags[last_param_token]) {
1403 .doc_comment => {1440 .doc_comment => {
1404 try renderToken(ais, tree, last_param_token, .newline);1441 try renderToken(r, last_param_token, .newline);
1405 continue;1442 continue;
1406 },1443 },
1407 .ellipsis3 => {1444 .ellipsis3 => {
1408 try renderToken(ais, tree, last_param_token, .comma); // ...1445 try renderToken(r, last_param_token, .comma); // ...
1409 break;1446 break;
1410 },1447 },
1411 .keyword_noalias, .keyword_comptime => {1448 .keyword_noalias, .keyword_comptime => {
1412 try renderToken(ais, tree, last_param_token, .space);1449 try renderToken(r, last_param_token, .space);
1413 last_param_token += 1;1450 last_param_token += 1;
1414 },1451 },
1415 .identifier => {},1452 .identifier => {},
1416 .keyword_anytype => {1453 .keyword_anytype => {
1417 try renderToken(ais, tree, last_param_token, .comma); // anytype1454 try renderToken(r, last_param_token, .comma); // anytype
1418 if (token_tags[last_param_token + 1] == .comma)1455 if (token_tags[last_param_token + 1] == .comma)
1419 last_param_token += 1;1456 last_param_token += 1;
1420 continue;1457 continue;
...@@ -1425,56 +1462,56 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt...@@ -1425,56 +1462,56 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt
1425 if (token_tags[last_param_token] == .identifier and1462 if (token_tags[last_param_token] == .identifier and
1426 token_tags[last_param_token + 1] == .colon)1463 token_tags[last_param_token + 1] == .colon)
1427 {1464 {
1428 try renderToken(ais, tree, last_param_token, .none); // name1465 try renderToken(r, last_param_token, .none); // name
1429 last_param_token += 1;1466 last_param_token += 1;
1430 try renderToken(ais, tree, last_param_token, .space); // :1467 try renderToken(r, last_param_token, .space); // :
1431 last_param_token += 1;1468 last_param_token += 1;
1432 }1469 }
1433 if (token_tags[last_param_token] == .keyword_anytype) {1470 if (token_tags[last_param_token] == .keyword_anytype) {
1434 try renderToken(ais, tree, last_param_token, .comma); // anytype1471 try renderToken(r, last_param_token, .comma); // anytype
1435 if (token_tags[last_param_token + 1] == .comma)1472 if (token_tags[last_param_token + 1] == .comma)
1436 last_param_token += 1;1473 last_param_token += 1;
1437 continue;1474 continue;
1438 }1475 }
1439 const param = fn_proto.ast.params[param_i];1476 const param = fn_proto.ast.params[param_i];
1440 param_i += 1;1477 param_i += 1;
1441 try renderExpression(gpa, ais, tree, param, .comma);1478 try renderExpression(r, param, .comma);
1442 last_param_token = tree.lastToken(param);1479 last_param_token = tree.lastToken(param);
1443 if (token_tags[last_param_token + 1] == .comma) last_param_token += 1;1480 if (token_tags[last_param_token + 1] == .comma) last_param_token += 1;
1444 }1481 }
1445 ais.popIndent();1482 ais.popIndent();
1446 }1483 }
14471484
1448 try renderToken(ais, tree, rparen, .space); // )1485 try renderToken(r, rparen, .space); // )
14491486
1450 if (fn_proto.ast.align_expr != 0) {1487 if (fn_proto.ast.align_expr != 0) {
1451 const align_lparen = tree.firstToken(fn_proto.ast.align_expr) - 1;1488 const align_lparen = tree.firstToken(fn_proto.ast.align_expr) - 1;
1452 const align_rparen = tree.lastToken(fn_proto.ast.align_expr) + 1;1489 const align_rparen = tree.lastToken(fn_proto.ast.align_expr) + 1;
14531490
1454 try renderToken(ais, tree, align_lparen - 1, .none); // align1491 try renderToken(r, align_lparen - 1, .none); // align
1455 try renderToken(ais, tree, align_lparen, .none); // (1492 try renderToken(r, align_lparen, .none); // (
1456 try renderExpression(gpa, ais, tree, fn_proto.ast.align_expr, .none);1493 try renderExpression(r, fn_proto.ast.align_expr, .none);
1457 try renderToken(ais, tree, align_rparen, .space); // )1494 try renderToken(r, align_rparen, .space); // )
1458 }1495 }
14591496
1460 if (fn_proto.ast.addrspace_expr != 0) {1497 if (fn_proto.ast.addrspace_expr != 0) {
1461 const align_lparen = tree.firstToken(fn_proto.ast.addrspace_expr) - 1;1498 const align_lparen = tree.firstToken(fn_proto.ast.addrspace_expr) - 1;
1462 const align_rparen = tree.lastToken(fn_proto.ast.addrspace_expr) + 1;1499 const align_rparen = tree.lastToken(fn_proto.ast.addrspace_expr) + 1;
14631500
1464 try renderToken(ais, tree, align_lparen - 1, .none); // addrspace1501 try renderToken(r, align_lparen - 1, .none); // addrspace
1465 try renderToken(ais, tree, align_lparen, .none); // (1502 try renderToken(r, align_lparen, .none); // (
1466 try renderExpression(gpa, ais, tree, fn_proto.ast.addrspace_expr, .none);1503 try renderExpression(r, fn_proto.ast.addrspace_expr, .none);
1467 try renderToken(ais, tree, align_rparen, .space); // )1504 try renderToken(r, align_rparen, .space); // )
1468 }1505 }
14691506
1470 if (fn_proto.ast.section_expr != 0) {1507 if (fn_proto.ast.section_expr != 0) {
1471 const section_lparen = tree.firstToken(fn_proto.ast.section_expr) - 1;1508 const section_lparen = tree.firstToken(fn_proto.ast.section_expr) - 1;
1472 const section_rparen = tree.lastToken(fn_proto.ast.section_expr) + 1;1509 const section_rparen = tree.lastToken(fn_proto.ast.section_expr) + 1;
14731510
1474 try renderToken(ais, tree, section_lparen - 1, .none); // section1511 try renderToken(r, section_lparen - 1, .none); // section
1475 try renderToken(ais, tree, section_lparen, .none); // (1512 try renderToken(r, section_lparen, .none); // (
1476 try renderExpression(gpa, ais, tree, fn_proto.ast.section_expr, .none);1513 try renderExpression(r, fn_proto.ast.section_expr, .none);
1477 try renderToken(ais, tree, section_rparen, .space); // )1514 try renderToken(r, section_rparen, .space); // )
1478 }1515 }
14791516
1480 const is_callconv_inline = mem.eql(u8, "Inline", tree.tokenSlice(tree.nodes.items(.main_token)[fn_proto.ast.callconv_expr]));1517 const is_callconv_inline = mem.eql(u8, "Inline", tree.tokenSlice(tree.nodes.items(.main_token)[fn_proto.ast.callconv_expr]));
...@@ -1483,25 +1520,24 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt...@@ -1483,25 +1520,24 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt
1483 const callconv_lparen = tree.firstToken(fn_proto.ast.callconv_expr) - 1;1520 const callconv_lparen = tree.firstToken(fn_proto.ast.callconv_expr) - 1;
1484 const callconv_rparen = tree.lastToken(fn_proto.ast.callconv_expr) + 1;1521 const callconv_rparen = tree.lastToken(fn_proto.ast.callconv_expr) + 1;
14851522
1486 try renderToken(ais, tree, callconv_lparen - 1, .none); // callconv1523 try renderToken(r, callconv_lparen - 1, .none); // callconv
1487 try renderToken(ais, tree, callconv_lparen, .none); // (1524 try renderToken(r, callconv_lparen, .none); // (
1488 try renderExpression(gpa, ais, tree, fn_proto.ast.callconv_expr, .none);1525 try renderExpression(r, fn_proto.ast.callconv_expr, .none);
1489 try renderToken(ais, tree, callconv_rparen, .space); // )1526 try renderToken(r, callconv_rparen, .space); // )
1490 }1527 }
14911528
1492 if (token_tags[maybe_bang] == .bang) {1529 if (token_tags[maybe_bang] == .bang) {
1493 try renderToken(ais, tree, maybe_bang, .none); // !1530 try renderToken(r, maybe_bang, .none); // !
1494 }1531 }
1495 return renderExpression(gpa, ais, tree, fn_proto.ast.return_type, space);1532 return renderExpression(r, fn_proto.ast.return_type, space);
1496}1533}
14971534
1498fn renderSwitchCase(1535fn renderSwitchCase(
1499 gpa: Allocator,1536 r: Render,
1500 ais: *Ais,
1501 tree: Ast,
1502 switch_case: Ast.full.SwitchCase,1537 switch_case: Ast.full.SwitchCase,
1503 space: Space,1538 space: Space,
1504) Error!void {1539) Error!void {
1540 const tree = r.tree;
1505 const node_tags = tree.nodes.items(.tag);1541 const node_tags = tree.nodes.items(.tag);
1506 const token_tags = tree.tokens.items(.tag);1542 const token_tags = tree.tokens.items(.tag);
1507 const trailing_comma = token_tags[switch_case.ast.arrow_token - 1] == .comma;1543 const trailing_comma = token_tags[switch_case.ast.arrow_token - 1] == .comma;
...@@ -1512,17 +1548,17 @@ fn renderSwitchCase(...@@ -1512,17 +1548,17 @@ fn renderSwitchCase(
15121548
1513 // Render everything before the arrow1549 // Render everything before the arrow
1514 if (switch_case.ast.values.len == 0) {1550 if (switch_case.ast.values.len == 0) {
1515 try renderToken(ais, tree, switch_case.ast.arrow_token - 1, .space); // else keyword1551 try renderToken(r, switch_case.ast.arrow_token - 1, .space); // else keyword
1516 } else if (switch_case.ast.values.len == 1 and !has_comment_before_arrow) {1552 } else if (switch_case.ast.values.len == 1 and !has_comment_before_arrow) {
1517 // render on one line and drop the trailing comma if any1553 // render on one line and drop the trailing comma if any
1518 try renderExpression(gpa, ais, tree, switch_case.ast.values[0], .space);1554 try renderExpression(r, switch_case.ast.values[0], .space);
1519 } else if (trailing_comma or has_comment_before_arrow) {1555 } else if (trailing_comma or has_comment_before_arrow) {
1520 // Render each value on a new line1556 // Render each value on a new line
1521 try renderExpressions(gpa, ais, tree, switch_case.ast.values, .comma);1557 try renderExpressions(r, switch_case.ast.values, .comma);
1522 } else {1558 } else {
1523 // Render on one line1559 // Render on one line
1524 for (switch_case.ast.values) |value_expr| {1560 for (switch_case.ast.values) |value_expr| {
1525 try renderExpression(gpa, ais, tree, value_expr, .comma_space);1561 try renderExpression(r, value_expr, .comma_space);
1526 }1562 }
1527 }1563 }
15281564
...@@ -1533,31 +1569,31 @@ fn renderSwitchCase(...@@ -1533,31 +1569,31 @@ fn renderSwitchCase(
1533 else1569 else
1534 Space.space;1570 Space.space;
1535 const after_arrow_space: Space = if (switch_case.payload_token == null) pre_target_space else .space;1571 const after_arrow_space: Space = if (switch_case.payload_token == null) pre_target_space else .space;
1536 try renderToken(ais, tree, switch_case.ast.arrow_token, after_arrow_space);1572 try renderToken(r, switch_case.ast.arrow_token, after_arrow_space);
15371573
1538 if (switch_case.payload_token) |payload_token| {1574 if (switch_case.payload_token) |payload_token| {
1539 try renderToken(ais, tree, payload_token - 1, .none); // pipe1575 try renderToken(r, payload_token - 1, .none); // pipe
1540 if (token_tags[payload_token] == .asterisk) {1576 if (token_tags[payload_token] == .asterisk) {
1541 try renderToken(ais, tree, payload_token, .none); // asterisk1577 try renderToken(r, payload_token, .none); // asterisk
1542 try renderToken(ais, tree, payload_token + 1, .none); // identifier1578 try renderToken(r, payload_token + 1, .none); // identifier
1543 try renderToken(ais, tree, payload_token + 2, pre_target_space); // pipe1579 try renderToken(r, payload_token + 2, pre_target_space); // pipe
1544 } else {1580 } else {
1545 try renderToken(ais, tree, payload_token, .none); // identifier1581 try renderToken(r, payload_token, .none); // identifier
1546 try renderToken(ais, tree, payload_token + 1, pre_target_space); // pipe1582 try renderToken(r, payload_token + 1, pre_target_space); // pipe
1547 }1583 }
1548 }1584 }
15491585
1550 try renderExpression(gpa, ais, tree, switch_case.ast.target_expr, space);1586 try renderExpression(r, switch_case.ast.target_expr, space);
1551}1587}
15521588
1553fn renderBlock(1589fn renderBlock(
1554 gpa: Allocator,1590 r: Render,
1555 ais: *Ais,
1556 tree: Ast,
1557 block_node: Ast.Node.Index,1591 block_node: Ast.Node.Index,
1558 statements: []const Ast.Node.Index,1592 statements: []const Ast.Node.Index,
1559 space: Space,1593 space: Space,
1560) Error!void {1594) Error!void {
1595 const tree = r.tree;
1596 const ais = r.ais;
1561 const token_tags = tree.tokens.items(.tag);1597 const token_tags = tree.tokens.items(.tag);
1562 const node_tags = tree.nodes.items(.tag);1598 const node_tags = tree.nodes.items(.tag);
1563 const lbrace = tree.nodes.items(.main_token)[block_node];1599 const lbrace = tree.nodes.items(.main_token)[block_node];
...@@ -1565,50 +1601,50 @@ fn renderBlock(...@@ -1565,50 +1601,50 @@ fn renderBlock(
1565 if (token_tags[lbrace - 1] == .colon and1601 if (token_tags[lbrace - 1] == .colon and
1566 token_tags[lbrace - 2] == .identifier)1602 token_tags[lbrace - 2] == .identifier)
1567 {1603 {
1568 try renderToken(ais, tree, lbrace - 2, .none);1604 try renderToken(r, lbrace - 2, .none);
1569 try renderToken(ais, tree, lbrace - 1, .space);1605 try renderToken(r, lbrace - 1, .space);
1570 }1606 }
15711607
1572 ais.pushIndentNextLine();1608 ais.pushIndentNextLine();
1573 if (statements.len == 0) {1609 if (statements.len == 0) {
1574 try renderToken(ais, tree, lbrace, .none);1610 try renderToken(r, lbrace, .none);
1575 } else {1611 } else {
1576 try renderToken(ais, tree, lbrace, .newline);1612 try renderToken(r, lbrace, .newline);
1577 for (statements) |stmt, i| {1613 for (statements) |stmt, i| {
1578 if (i != 0) try renderExtraNewline(ais, tree, stmt);1614 if (i != 0) try renderExtraNewline(r, stmt);
1579 switch (node_tags[stmt]) {1615 switch (node_tags[stmt]) {
1580 .global_var_decl => try renderVarDecl(gpa, ais, tree, tree.globalVarDecl(stmt)),1616 .global_var_decl => try renderVarDecl(r, tree.globalVarDecl(stmt)),
1581 .local_var_decl => try renderVarDecl(gpa, ais, tree, tree.localVarDecl(stmt)),1617 .local_var_decl => try renderVarDecl(r, tree.localVarDecl(stmt)),
1582 .simple_var_decl => try renderVarDecl(gpa, ais, tree, tree.simpleVarDecl(stmt)),1618 .simple_var_decl => try renderVarDecl(r, tree.simpleVarDecl(stmt)),
1583 .aligned_var_decl => try renderVarDecl(gpa, ais, tree, tree.alignedVarDecl(stmt)),1619 .aligned_var_decl => try renderVarDecl(r, tree.alignedVarDecl(stmt)),
1584 else => try renderExpression(gpa, ais, tree, stmt, .semicolon),1620 else => try renderExpression(r, stmt, .semicolon),
1585 }1621 }
1586 }1622 }
1587 }1623 }
1588 ais.popIndent();1624 ais.popIndent();
15891625
1590 try renderToken(ais, tree, tree.lastToken(block_node), space); // rbrace1626 try renderToken(r, tree.lastToken(block_node), space); // rbrace
1591}1627}
15921628
1593fn renderStructInit(1629fn renderStructInit(
1594 gpa: Allocator,1630 r: Render,
1595 ais: *Ais,
1596 tree: Ast,
1597 struct_node: Ast.Node.Index,1631 struct_node: Ast.Node.Index,
1598 struct_init: Ast.full.StructInit,1632 struct_init: Ast.full.StructInit,
1599 space: Space,1633 space: Space,
1600) Error!void {1634) Error!void {
1635 const tree = r.tree;
1636 const ais = r.ais;
1601 const token_tags = tree.tokens.items(.tag);1637 const token_tags = tree.tokens.items(.tag);
1602 if (struct_init.ast.type_expr == 0) {1638 if (struct_init.ast.type_expr == 0) {
1603 try renderToken(ais, tree, struct_init.ast.lbrace - 1, .none); // .1639 try renderToken(r, struct_init.ast.lbrace - 1, .none); // .
1604 } else {1640 } else {
1605 try renderExpression(gpa, ais, tree, struct_init.ast.type_expr, .none); // T1641 try renderExpression(r, struct_init.ast.type_expr, .none); // T
1606 }1642 }
1607 if (struct_init.ast.fields.len == 0) {1643 if (struct_init.ast.fields.len == 0) {
1608 ais.pushIndentNextLine();1644 ais.pushIndentNextLine();
1609 try renderToken(ais, tree, struct_init.ast.lbrace, .none); // lbrace1645 try renderToken(r, struct_init.ast.lbrace, .none); // lbrace
1610 ais.popIndent();1646 ais.popIndent();
1611 return renderToken(ais, tree, struct_init.ast.lbrace + 1, space); // rbrace1647 return renderToken(r, struct_init.ast.lbrace + 1, space); // rbrace
1612 }1648 }
16131649
1614 const rbrace = tree.lastToken(struct_node);1650 const rbrace = tree.lastToken(struct_node);
...@@ -1616,59 +1652,60 @@ fn renderStructInit(...@@ -1616,59 +1652,60 @@ fn renderStructInit(
1616 if (trailing_comma or hasComment(tree, struct_init.ast.lbrace, rbrace)) {1652 if (trailing_comma or hasComment(tree, struct_init.ast.lbrace, rbrace)) {
1617 // Render one field init per line.1653 // Render one field init per line.
1618 ais.pushIndentNextLine();1654 ais.pushIndentNextLine();
1619 try renderToken(ais, tree, struct_init.ast.lbrace, .newline);1655 try renderToken(r, struct_init.ast.lbrace, .newline);
16201656
1621 try renderToken(ais, tree, struct_init.ast.lbrace + 1, .none); // .1657 try renderToken(r, struct_init.ast.lbrace + 1, .none); // .
1622 try renderToken(ais, tree, struct_init.ast.lbrace + 2, .space); // name1658 try renderToken(r, struct_init.ast.lbrace + 2, .space); // name
1623 try renderToken(ais, tree, struct_init.ast.lbrace + 3, .space); // =1659 try renderToken(r, struct_init.ast.lbrace + 3, .space); // =
1624 try renderExpression(gpa, ais, tree, struct_init.ast.fields[0], .comma);1660 try renderExpression(r, struct_init.ast.fields[0], .comma);
16251661
1626 for (struct_init.ast.fields[1..]) |field_init| {1662 for (struct_init.ast.fields[1..]) |field_init| {
1627 const init_token = tree.firstToken(field_init);1663 const init_token = tree.firstToken(field_init);
1628 try renderExtraNewlineToken(ais, tree, init_token - 3);1664 try renderExtraNewlineToken(r, init_token - 3);
1629 try renderToken(ais, tree, init_token - 3, .none); // .1665 try renderToken(r, init_token - 3, .none); // .
1630 try renderToken(ais, tree, init_token - 2, .space); // name1666 try renderToken(r, init_token - 2, .space); // name
1631 try renderToken(ais, tree, init_token - 1, .space); // =1667 try renderToken(r, init_token - 1, .space); // =
1632 try renderExpression(gpa, ais, tree, field_init, .comma);1668 try renderExpression(r, field_init, .comma);
1633 }1669 }
16341670
1635 ais.popIndent();1671 ais.popIndent();
1636 } else {1672 } else {
1637 // Render all on one line, no trailing comma.1673 // Render all on one line, no trailing comma.
1638 try renderToken(ais, tree, struct_init.ast.lbrace, .space);1674 try renderToken(r, struct_init.ast.lbrace, .space);
16391675
1640 for (struct_init.ast.fields) |field_init| {1676 for (struct_init.ast.fields) |field_init| {
1641 const init_token = tree.firstToken(field_init);1677 const init_token = tree.firstToken(field_init);
1642 try renderToken(ais, tree, init_token - 3, .none); // .1678 try renderToken(r, init_token - 3, .none); // .
1643 try renderToken(ais, tree, init_token - 2, .space); // name1679 try renderToken(r, init_token - 2, .space); // name
1644 try renderToken(ais, tree, init_token - 1, .space); // =1680 try renderToken(r, init_token - 1, .space); // =
1645 try renderExpression(gpa, ais, tree, field_init, .comma_space);1681 try renderExpression(r, field_init, .comma_space);
1646 }1682 }
1647 }1683 }
16481684
1649 return renderToken(ais, tree, rbrace, space);1685 return renderToken(r, rbrace, space);
1650}1686}
16511687
1652fn renderArrayInit(1688fn renderArrayInit(
1653 gpa: Allocator,1689 r: Render,
1654 ais: *Ais,
1655 tree: Ast,
1656 array_init: Ast.full.ArrayInit,1690 array_init: Ast.full.ArrayInit,
1657 space: Space,1691 space: Space,
1658) Error!void {1692) Error!void {
1693 const tree = r.tree;
1694 const ais = r.ais;
1695 const gpa = r.gpa;
1659 const token_tags = tree.tokens.items(.tag);1696 const token_tags = tree.tokens.items(.tag);
16601697
1661 if (array_init.ast.type_expr == 0) {1698 if (array_init.ast.type_expr == 0) {
1662 try renderToken(ais, tree, array_init.ast.lbrace - 1, .none); // .1699 try renderToken(r, array_init.ast.lbrace - 1, .none); // .
1663 } else {1700 } else {
1664 try renderExpression(gpa, ais, tree, array_init.ast.type_expr, .none); // T1701 try renderExpression(r, array_init.ast.type_expr, .none); // T
1665 }1702 }
16661703
1667 if (array_init.ast.elements.len == 0) {1704 if (array_init.ast.elements.len == 0) {
1668 ais.pushIndentNextLine();1705 ais.pushIndentNextLine();
1669 try renderToken(ais, tree, array_init.ast.lbrace, .none); // lbrace1706 try renderToken(r, array_init.ast.lbrace, .none); // lbrace
1670 ais.popIndent();1707 ais.popIndent();
1671 return renderToken(ais, tree, array_init.ast.lbrace + 1, space); // rbrace1708 return renderToken(r, array_init.ast.lbrace + 1, space); // rbrace
1672 }1709 }
16731710
1674 const last_elem = array_init.ast.elements[array_init.ast.elements.len - 1];1711 const last_elem = array_init.ast.elements[array_init.ast.elements.len - 1];
...@@ -1683,9 +1720,9 @@ fn renderArrayInit(...@@ -1683,9 +1720,9 @@ fn renderArrayInit(
1683 if (token_tags[first_token] != .multiline_string_literal_line and1720 if (token_tags[first_token] != .multiline_string_literal_line and
1684 !anythingBetween(tree, last_elem_token, rbrace))1721 !anythingBetween(tree, last_elem_token, rbrace))
1685 {1722 {
1686 try renderToken(ais, tree, array_init.ast.lbrace, .none);1723 try renderToken(r, array_init.ast.lbrace, .none);
1687 try renderExpression(gpa, ais, tree, only_elem, .none);1724 try renderExpression(r, only_elem, .none);
1688 return renderToken(ais, tree, rbrace, space);1725 return renderToken(r, rbrace, space);
1689 }1726 }
1690 }1727 }
16911728
...@@ -1696,19 +1733,19 @@ fn renderArrayInit(...@@ -1696,19 +1733,19 @@ fn renderArrayInit(
1696 // Render all on one line, no trailing comma.1733 // Render all on one line, no trailing comma.
1697 if (array_init.ast.elements.len == 1) {1734 if (array_init.ast.elements.len == 1) {
1698 // If there is only one element, we don't use spaces1735 // If there is only one element, we don't use spaces
1699 try renderToken(ais, tree, array_init.ast.lbrace, .none);1736 try renderToken(r, array_init.ast.lbrace, .none);
1700 try renderExpression(gpa, ais, tree, array_init.ast.elements[0], .none);1737 try renderExpression(r, array_init.ast.elements[0], .none);
1701 } else {1738 } else {
1702 try renderToken(ais, tree, array_init.ast.lbrace, .space);1739 try renderToken(r, array_init.ast.lbrace, .space);
1703 for (array_init.ast.elements) |elem| {1740 for (array_init.ast.elements) |elem| {
1704 try renderExpression(gpa, ais, tree, elem, .comma_space);1741 try renderExpression(r, elem, .comma_space);
1705 }1742 }
1706 }1743 }
1707 return renderToken(ais, tree, last_elem_token + 1, space); // rbrace1744 return renderToken(r, last_elem_token + 1, space); // rbrace
1708 }1745 }
17091746
1710 ais.pushIndentNextLine();1747 ais.pushIndentNextLine();
1711 try renderToken(ais, tree, array_init.ast.lbrace, .newline);1748 try renderToken(r, array_init.ast.lbrace, .newline);
17121749
1713 var expr_index: usize = 0;1750 var expr_index: usize = 0;
1714 while (true) {1751 while (true) {
...@@ -1764,6 +1801,12 @@ fn renderArrayInit(...@@ -1764,6 +1801,12 @@ fn renderArrayInit(
1764 .indent_delta = indent_delta,1801 .indent_delta = indent_delta,
1765 .underlying_writer = sub_expr_buffer.writer(),1802 .underlying_writer = sub_expr_buffer.writer(),
1766 };1803 };
1804 var sub_render: Render = .{
1805 .gpa = r.gpa,
1806 .ais = &auto_indenting_stream,
1807 .tree = r.tree,
1808 .fixups = r.fixups,
1809 };
17671810
1768 // Calculate size of columns in current section1811 // Calculate size of columns in current section
1769 var column_counter: usize = 0;1812 var column_counter: usize = 0;
...@@ -1774,7 +1817,7 @@ fn renderArrayInit(...@@ -1774,7 +1817,7 @@ fn renderArrayInit(
1774 sub_expr_buffer_starts[i] = start;1817 sub_expr_buffer_starts[i] = start;
17751818
1776 if (i + 1 < section_exprs.len) {1819 if (i + 1 < section_exprs.len) {
1777 try renderExpression(gpa, &auto_indenting_stream, tree, expr, .none);1820 try renderExpression(sub_render, expr, .none);
1778 const width = sub_expr_buffer.items.len - start;1821 const width = sub_expr_buffer.items.len - start;
1779 const this_contains_newline = mem.indexOfScalar(u8, sub_expr_buffer.items[start..], '\n') != null;1822 const this_contains_newline = mem.indexOfScalar(u8, sub_expr_buffer.items[start..], '\n') != null;
1780 contains_newline = contains_newline or this_contains_newline;1823 contains_newline = contains_newline or this_contains_newline;
...@@ -1794,7 +1837,7 @@ fn renderArrayInit(...@@ -1794,7 +1837,7 @@ fn renderArrayInit(
1794 column_counter = 0;1837 column_counter = 0;
1795 }1838 }
1796 } else {1839 } else {
1797 try renderExpression(gpa, &auto_indenting_stream, tree, expr, .comma);1840 try renderExpression(sub_render, expr, .comma);
1798 const width = sub_expr_buffer.items.len - start - 2;1841 const width = sub_expr_buffer.items.len - start - 2;
1799 const this_contains_newline = mem.indexOfScalar(u8, sub_expr_buffer.items[start .. sub_expr_buffer.items.len - 1], '\n') != null;1842 const this_contains_newline = mem.indexOfScalar(u8, sub_expr_buffer.items[start .. sub_expr_buffer.items.len - 1], '\n') != null;
1800 contains_newline = contains_newline or this_contains_newline;1843 contains_newline = contains_newline or this_contains_newline;
...@@ -1839,7 +1882,7 @@ fn renderArrayInit(...@@ -1839,7 +1882,7 @@ fn renderArrayInit(
1839 if (column_counter != row_size - 1) {1882 if (column_counter != row_size - 1) {
1840 if (!expr_newlines[i] and !expr_newlines[i + 1]) {1883 if (!expr_newlines[i] and !expr_newlines[i + 1]) {
1841 // Neither the current or next expression is multiline1884 // Neither the current or next expression is multiline
1842 try renderToken(ais, tree, comma, .space); // ,1885 try renderToken(r, comma, .space); // ,
1843 assert(column_widths[column_counter % row_size] >= expr_widths[i]);1886 assert(column_widths[column_counter % row_size] >= expr_widths[i]);
1844 const padding = column_widths[column_counter % row_size] - expr_widths[i];1887 const padding = column_widths[column_counter % row_size] - expr_widths[i];
1845 try ais.writer().writeByteNTimes(' ', padding);1888 try ais.writer().writeByteNTimes(' ', padding);
...@@ -1850,13 +1893,13 @@ fn renderArrayInit(...@@ -1850,13 +1893,13 @@ fn renderArrayInit(
1850 }1893 }
18511894
1852 if (single_line and row_size != 1) {1895 if (single_line and row_size != 1) {
1853 try renderToken(ais, tree, comma, .space); // ,1896 try renderToken(r, comma, .space); // ,
1854 continue;1897 continue;
1855 }1898 }
18561899
1857 column_counter = 0;1900 column_counter = 0;
1858 try renderToken(ais, tree, comma, .newline); // ,1901 try renderToken(r, comma, .newline); // ,
1859 try renderExtraNewline(ais, tree, next_expr);1902 try renderExtraNewline(r, next_expr);
1860 }1903 }
1861 }1904 }
18621905
...@@ -1865,49 +1908,49 @@ fn renderArrayInit(...@@ -1865,49 +1908,49 @@ fn renderArrayInit(
1865 }1908 }
18661909
1867 ais.popIndent();1910 ais.popIndent();
1868 return renderToken(ais, tree, rbrace, space); // rbrace1911 return renderToken(r, rbrace, space); // rbrace
1869}1912}
18701913
1871fn renderContainerDecl(1914fn renderContainerDecl(
1872 gpa: Allocator,1915 r: Render,
1873 ais: *Ais,
1874 tree: Ast,
1875 container_decl_node: Ast.Node.Index,1916 container_decl_node: Ast.Node.Index,
1876 container_decl: Ast.full.ContainerDecl,1917 container_decl: Ast.full.ContainerDecl,
1877 space: Space,1918 space: Space,
1878) Error!void {1919) Error!void {
1920 const tree = r.tree;
1921 const ais = r.ais;
1879 const token_tags = tree.tokens.items(.tag);1922 const token_tags = tree.tokens.items(.tag);
1880 const node_tags = tree.nodes.items(.tag);1923 const node_tags = tree.nodes.items(.tag);
18811924
1882 if (container_decl.layout_token) |layout_token| {1925 if (container_decl.layout_token) |layout_token| {
1883 try renderToken(ais, tree, layout_token, .space);1926 try renderToken(r, layout_token, .space);
1884 }1927 }
18851928
1886 var lbrace: Ast.TokenIndex = undefined;1929 var lbrace: Ast.TokenIndex = undefined;
1887 if (container_decl.ast.enum_token) |enum_token| {1930 if (container_decl.ast.enum_token) |enum_token| {
1888 try renderToken(ais, tree, container_decl.ast.main_token, .none); // union1931 try renderToken(r, container_decl.ast.main_token, .none); // union
1889 try renderToken(ais, tree, enum_token - 1, .none); // lparen1932 try renderToken(r, enum_token - 1, .none); // lparen
1890 try renderToken(ais, tree, enum_token, .none); // enum1933 try renderToken(r, enum_token, .none); // enum
1891 if (container_decl.ast.arg != 0) {1934 if (container_decl.ast.arg != 0) {
1892 try renderToken(ais, tree, enum_token + 1, .none); // lparen1935 try renderToken(r, enum_token + 1, .none); // lparen
1893 try renderExpression(gpa, ais, tree, container_decl.ast.arg, .none);1936 try renderExpression(r, container_decl.ast.arg, .none);
1894 const rparen = tree.lastToken(container_decl.ast.arg) + 1;1937 const rparen = tree.lastToken(container_decl.ast.arg) + 1;
1895 try renderToken(ais, tree, rparen, .none); // rparen1938 try renderToken(r, rparen, .none); // rparen
1896 try renderToken(ais, tree, rparen + 1, .space); // rparen1939 try renderToken(r, rparen + 1, .space); // rparen
1897 lbrace = rparen + 2;1940 lbrace = rparen + 2;
1898 } else {1941 } else {
1899 try renderToken(ais, tree, enum_token + 1, .space); // rparen1942 try renderToken(r, enum_token + 1, .space); // rparen
1900 lbrace = enum_token + 2;1943 lbrace = enum_token + 2;
1901 }1944 }
1902 } else if (container_decl.ast.arg != 0) {1945 } else if (container_decl.ast.arg != 0) {
1903 try renderToken(ais, tree, container_decl.ast.main_token, .none); // union1946 try renderToken(r, container_decl.ast.main_token, .none); // union
1904 try renderToken(ais, tree, container_decl.ast.main_token + 1, .none); // lparen1947 try renderToken(r, container_decl.ast.main_token + 1, .none); // lparen
1905 try renderExpression(gpa, ais, tree, container_decl.ast.arg, .none);1948 try renderExpression(r, container_decl.ast.arg, .none);
1906 const rparen = tree.lastToken(container_decl.ast.arg) + 1;1949 const rparen = tree.lastToken(container_decl.ast.arg) + 1;
1907 try renderToken(ais, tree, rparen, .space); // rparen1950 try renderToken(r, rparen, .space); // rparen
1908 lbrace = rparen + 1;1951 lbrace = rparen + 1;
1909 } else {1952 } else {
1910 try renderToken(ais, tree, container_decl.ast.main_token, .space); // union1953 try renderToken(r, container_decl.ast.main_token, .space); // union
1911 lbrace = container_decl.ast.main_token + 1;1954 lbrace = container_decl.ast.main_token + 1;
1912 }1955 }
19131956
...@@ -1915,13 +1958,13 @@ fn renderContainerDecl(...@@ -1915,13 +1958,13 @@ fn renderContainerDecl(
1915 if (container_decl.ast.members.len == 0) {1958 if (container_decl.ast.members.len == 0) {
1916 ais.pushIndentNextLine();1959 ais.pushIndentNextLine();
1917 if (token_tags[lbrace + 1] == .container_doc_comment) {1960 if (token_tags[lbrace + 1] == .container_doc_comment) {
1918 try renderToken(ais, tree, lbrace, .newline); // lbrace1961 try renderToken(r, lbrace, .newline); // lbrace
1919 try renderContainerDocComments(ais, tree, lbrace + 1);1962 try renderContainerDocComments(r, lbrace + 1);
1920 } else {1963 } else {
1921 try renderToken(ais, tree, lbrace, .none); // lbrace1964 try renderToken(r, lbrace, .none); // lbrace
1922 }1965 }
1923 ais.popIndent();1966 ais.popIndent();
1924 return renderToken(ais, tree, rbrace, space); // rbrace1967 return renderToken(r, rbrace, space); // rbrace
1925 }1968 }
19261969
1927 const src_has_trailing_comma = token_tags[rbrace - 1] == .comma;1970 const src_has_trailing_comma = token_tags[rbrace - 1] == .comma;
...@@ -1947,52 +1990,52 @@ fn renderContainerDecl(...@@ -1947,52 +1990,52 @@ fn renderContainerDecl(
1947 }1990 }
19481991
1949 // Print all the declarations on the same line.1992 // Print all the declarations on the same line.
1950 try renderToken(ais, tree, lbrace, .space); // lbrace1993 try renderToken(r, lbrace, .space); // lbrace
1951 for (container_decl.ast.members) |member| {1994 for (container_decl.ast.members) |member| {
1952 try renderMember(gpa, ais, tree, member, .space);1995 try renderMember(r, member, .space);
1953 }1996 }
1954 return renderToken(ais, tree, rbrace, space); // rbrace1997 return renderToken(r, rbrace, space); // rbrace
1955 }1998 }
19561999
1957 // One member per line.2000 // One member per line.
1958 ais.pushIndentNextLine();2001 ais.pushIndentNextLine();
1959 try renderToken(ais, tree, lbrace, .newline); // lbrace2002 try renderToken(r, lbrace, .newline); // lbrace
1960 if (token_tags[lbrace + 1] == .container_doc_comment) {2003 if (token_tags[lbrace + 1] == .container_doc_comment) {
1961 try renderContainerDocComments(ais, tree, lbrace + 1);2004 try renderContainerDocComments(r, lbrace + 1);
1962 }2005 }
1963 for (container_decl.ast.members) |member, i| {2006 for (container_decl.ast.members) |member, i| {
1964 if (i != 0) try renderExtraNewline(ais, tree, member);2007 if (i != 0) try renderExtraNewline(r, member);
1965 switch (tree.nodes.items(.tag)[member]) {2008 switch (tree.nodes.items(.tag)[member]) {
1966 // For container fields, ensure a trailing comma is added if necessary.2009 // For container fields, ensure a trailing comma is added if necessary.
1967 .container_field_init,2010 .container_field_init,
1968 .container_field_align,2011 .container_field_align,
1969 .container_field,2012 .container_field,
1970 => try renderMember(gpa, ais, tree, member, .comma),2013 => try renderMember(r, member, .comma),
19712014
1972 else => try renderMember(gpa, ais, tree, member, .newline),2015 else => try renderMember(r, member, .newline),
1973 }2016 }
1974 }2017 }
1975 ais.popIndent();2018 ais.popIndent();
19762019
1977 return renderToken(ais, tree, rbrace, space); // rbrace2020 return renderToken(r, rbrace, space); // rbrace
1978}2021}
19792022
1980fn renderAsm(2023fn renderAsm(
1981 gpa: Allocator,2024 r: Render,
1982 ais: *Ais,
1983 tree: Ast,
1984 asm_node: Ast.full.Asm,2025 asm_node: Ast.full.Asm,
1985 space: Space,2026 space: Space,
1986) Error!void {2027) Error!void {
2028 const tree = r.tree;
2029 const ais = r.ais;
1987 const token_tags = tree.tokens.items(.tag);2030 const token_tags = tree.tokens.items(.tag);
19882031
1989 try renderToken(ais, tree, asm_node.ast.asm_token, .space); // asm2032 try renderToken(r, asm_node.ast.asm_token, .space); // asm
19902033
1991 if (asm_node.volatile_token) |volatile_token| {2034 if (asm_node.volatile_token) |volatile_token| {
1992 try renderToken(ais, tree, volatile_token, .space); // volatile2035 try renderToken(r, volatile_token, .space); // volatile
1993 try renderToken(ais, tree, volatile_token + 1, .none); // lparen2036 try renderToken(r, volatile_token + 1, .none); // lparen
1994 } else {2037 } else {
1995 try renderToken(ais, tree, asm_node.ast.asm_token + 1, .none); // lparen2038 try renderToken(r, asm_node.ast.asm_token + 1, .none); // lparen
1996 }2039 }
19972040
1998 if (asm_node.ast.items.len == 0) {2041 if (asm_node.ast.items.len == 0) {
...@@ -2000,27 +2043,27 @@ fn renderAsm(...@@ -2000,27 +2043,27 @@ fn renderAsm(
2000 if (asm_node.first_clobber) |first_clobber| {2043 if (asm_node.first_clobber) |first_clobber| {
2001 // asm ("foo" ::: "a", "b")2044 // asm ("foo" ::: "a", "b")
2002 // asm ("foo" ::: "a", "b",)2045 // asm ("foo" ::: "a", "b",)
2003 try renderExpression(gpa, ais, tree, asm_node.ast.template, .space);2046 try renderExpression(r, asm_node.ast.template, .space);
2004 // Render the three colons.2047 // Render the three colons.
2005 try renderToken(ais, tree, first_clobber - 3, .none);2048 try renderToken(r, first_clobber - 3, .none);
2006 try renderToken(ais, tree, first_clobber - 2, .none);2049 try renderToken(r, first_clobber - 2, .none);
2007 try renderToken(ais, tree, first_clobber - 1, .space);2050 try renderToken(r, first_clobber - 1, .space);
20082051
2009 var tok_i = first_clobber;2052 var tok_i = first_clobber;
2010 while (true) : (tok_i += 1) {2053 while (true) : (tok_i += 1) {
2011 try renderToken(ais, tree, tok_i, .none);2054 try renderToken(r, tok_i, .none);
2012 tok_i += 1;2055 tok_i += 1;
2013 switch (token_tags[tok_i]) {2056 switch (token_tags[tok_i]) {
2014 .r_paren => {2057 .r_paren => {
2015 ais.popIndent();2058 ais.popIndent();
2016 return renderToken(ais, tree, tok_i, space);2059 return renderToken(r, tok_i, space);
2017 },2060 },
2018 .comma => {2061 .comma => {
2019 if (token_tags[tok_i + 1] == .r_paren) {2062 if (token_tags[tok_i + 1] == .r_paren) {
2020 ais.popIndent();2063 ais.popIndent();
2021 return renderToken(ais, tree, tok_i + 1, space);2064 return renderToken(r, tok_i + 1, space);
2022 } else {2065 } else {
2023 try renderToken(ais, tree, tok_i, .space);2066 try renderToken(r, tok_i, .space);
2024 }2067 }
2025 },2068 },
2026 else => unreachable,2069 else => unreachable,
...@@ -2028,40 +2071,40 @@ fn renderAsm(...@@ -2028,40 +2071,40 @@ fn renderAsm(
2028 }2071 }
2029 } else {2072 } else {
2030 // asm ("foo")2073 // asm ("foo")
2031 try renderExpression(gpa, ais, tree, asm_node.ast.template, .none);2074 try renderExpression(r, asm_node.ast.template, .none);
2032 ais.popIndent();2075 ais.popIndent();
2033 return renderToken(ais, tree, asm_node.ast.rparen, space); // rparen2076 return renderToken(r, asm_node.ast.rparen, space); // rparen
2034 }2077 }
2035 }2078 }
20362079
2037 ais.pushIndent();2080 ais.pushIndent();
2038 try renderExpression(gpa, ais, tree, asm_node.ast.template, .newline);2081 try renderExpression(r, asm_node.ast.template, .newline);
2039 ais.setIndentDelta(asm_indent_delta);2082 ais.setIndentDelta(asm_indent_delta);
2040 const colon1 = tree.lastToken(asm_node.ast.template) + 1;2083 const colon1 = tree.lastToken(asm_node.ast.template) + 1;
20412084
2042 const colon2 = if (asm_node.outputs.len == 0) colon2: {2085 const colon2 = if (asm_node.outputs.len == 0) colon2: {
2043 try renderToken(ais, tree, colon1, .newline); // :2086 try renderToken(r, colon1, .newline); // :
2044 break :colon2 colon1 + 1;2087 break :colon2 colon1 + 1;
2045 } else colon2: {2088 } else colon2: {
2046 try renderToken(ais, tree, colon1, .space); // :2089 try renderToken(r, colon1, .space); // :
20472090
2048 ais.pushIndent();2091 ais.pushIndent();
2049 for (asm_node.outputs) |asm_output, i| {2092 for (asm_node.outputs) |asm_output, i| {
2050 if (i + 1 < asm_node.outputs.len) {2093 if (i + 1 < asm_node.outputs.len) {
2051 const next_asm_output = asm_node.outputs[i + 1];2094 const next_asm_output = asm_node.outputs[i + 1];
2052 try renderAsmOutput(gpa, ais, tree, asm_output, .none);2095 try renderAsmOutput(r, asm_output, .none);
20532096
2054 const comma = tree.firstToken(next_asm_output) - 1;2097 const comma = tree.firstToken(next_asm_output) - 1;
2055 try renderToken(ais, tree, comma, .newline); // ,2098 try renderToken(r, comma, .newline); // ,
2056 try renderExtraNewlineToken(ais, tree, tree.firstToken(next_asm_output));2099 try renderExtraNewlineToken(r, tree.firstToken(next_asm_output));
2057 } else if (asm_node.inputs.len == 0 and asm_node.first_clobber == null) {2100 } else if (asm_node.inputs.len == 0 and asm_node.first_clobber == null) {
2058 try renderAsmOutput(gpa, ais, tree, asm_output, .comma);2101 try renderAsmOutput(r, asm_output, .comma);
2059 ais.popIndent();2102 ais.popIndent();
2060 ais.setIndentDelta(indent_delta);2103 ais.setIndentDelta(indent_delta);
2061 ais.popIndent();2104 ais.popIndent();
2062 return renderToken(ais, tree, asm_node.ast.rparen, space); // rparen2105 return renderToken(r, asm_node.ast.rparen, space); // rparen
2063 } else {2106 } else {
2064 try renderAsmOutput(gpa, ais, tree, asm_output, .comma);2107 try renderAsmOutput(r, asm_output, .comma);
2065 const comma_or_colon = tree.lastToken(asm_output) + 1;2108 const comma_or_colon = tree.lastToken(asm_output) + 1;
2066 ais.popIndent();2109 ais.popIndent();
2067 break :colon2 switch (token_tags[comma_or_colon]) {2110 break :colon2 switch (token_tags[comma_or_colon]) {
...@@ -2073,27 +2116,27 @@ fn renderAsm(...@@ -2073,27 +2116,27 @@ fn renderAsm(
2073 };2116 };
20742117
2075 const colon3 = if (asm_node.inputs.len == 0) colon3: {2118 const colon3 = if (asm_node.inputs.len == 0) colon3: {
2076 try renderToken(ais, tree, colon2, .newline); // :2119 try renderToken(r, colon2, .newline); // :
2077 break :colon3 colon2 + 1;2120 break :colon3 colon2 + 1;
2078 } else colon3: {2121 } else colon3: {
2079 try renderToken(ais, tree, colon2, .space); // :2122 try renderToken(r, colon2, .space); // :
2080 ais.pushIndent();2123 ais.pushIndent();
2081 for (asm_node.inputs) |asm_input, i| {2124 for (asm_node.inputs) |asm_input, i| {
2082 if (i + 1 < asm_node.inputs.len) {2125 if (i + 1 < asm_node.inputs.len) {
2083 const next_asm_input = asm_node.inputs[i + 1];2126 const next_asm_input = asm_node.inputs[i + 1];
2084 try renderAsmInput(gpa, ais, tree, asm_input, .none);2127 try renderAsmInput(r, asm_input, .none);
20852128
2086 const first_token = tree.firstToken(next_asm_input);2129 const first_token = tree.firstToken(next_asm_input);
2087 try renderToken(ais, tree, first_token - 1, .newline); // ,2130 try renderToken(r, first_token - 1, .newline); // ,
2088 try renderExtraNewlineToken(ais, tree, first_token);2131 try renderExtraNewlineToken(r, first_token);
2089 } else if (asm_node.first_clobber == null) {2132 } else if (asm_node.first_clobber == null) {
2090 try renderAsmInput(gpa, ais, tree, asm_input, .comma);2133 try renderAsmInput(r, asm_input, .comma);
2091 ais.popIndent();2134 ais.popIndent();
2092 ais.setIndentDelta(indent_delta);2135 ais.setIndentDelta(indent_delta);
2093 ais.popIndent();2136 ais.popIndent();
2094 return renderToken(ais, tree, asm_node.ast.rparen, space); // rparen2137 return renderToken(r, asm_node.ast.rparen, space); // rparen
2095 } else {2138 } else {
2096 try renderAsmInput(gpa, ais, tree, asm_input, .comma);2139 try renderAsmInput(r, asm_input, .comma);
2097 const comma_or_colon = tree.lastToken(asm_input) + 1;2140 const comma_or_colon = tree.lastToken(asm_input) + 1;
2098 ais.popIndent();2141 ais.popIndent();
2099 break :colon3 switch (token_tags[comma_or_colon]) {2142 break :colon3 switch (token_tags[comma_or_colon]) {
...@@ -2105,7 +2148,7 @@ fn renderAsm(...@@ -2105,7 +2148,7 @@ fn renderAsm(
2105 unreachable;2148 unreachable;
2106 };2149 };
21072150
2108 try renderToken(ais, tree, colon3, .space); // :2151 try renderToken(r, colon3, .space); // :
2109 const first_clobber = asm_node.first_clobber.?;2152 const first_clobber = asm_node.first_clobber.?;
2110 var tok_i = first_clobber;2153 var tok_i = first_clobber;
2111 while (true) {2154 while (true) {
...@@ -2113,20 +2156,20 @@ fn renderAsm(...@@ -2113,20 +2156,20 @@ fn renderAsm(
2113 .r_paren => {2156 .r_paren => {
2114 ais.setIndentDelta(indent_delta);2157 ais.setIndentDelta(indent_delta);
2115 ais.popIndent();2158 ais.popIndent();
2116 try renderToken(ais, tree, tok_i, .newline);2159 try renderToken(r, tok_i, .newline);
2117 return renderToken(ais, tree, tok_i + 1, space);2160 return renderToken(r, tok_i + 1, space);
2118 },2161 },
2119 .comma => {2162 .comma => {
2120 switch (token_tags[tok_i + 2]) {2163 switch (token_tags[tok_i + 2]) {
2121 .r_paren => {2164 .r_paren => {
2122 ais.setIndentDelta(indent_delta);2165 ais.setIndentDelta(indent_delta);
2123 ais.popIndent();2166 ais.popIndent();
2124 try renderToken(ais, tree, tok_i, .newline);2167 try renderToken(r, tok_i, .newline);
2125 return renderToken(ais, tree, tok_i + 2, space);2168 return renderToken(r, tok_i + 2, space);
2126 },2169 },
2127 else => {2170 else => {
2128 try renderToken(ais, tree, tok_i, .none);2171 try renderToken(r, tok_i, .none);
2129 try renderToken(ais, tree, tok_i + 1, .space);2172 try renderToken(r, tok_i + 1, .space);
2130 tok_i += 2;2173 tok_i += 2;
2131 },2174 },
2132 }2175 }
...@@ -2137,36 +2180,36 @@ fn renderAsm(...@@ -2137,36 +2180,36 @@ fn renderAsm(
2137}2180}
21382181
2139fn renderCall(2182fn renderCall(
2140 gpa: Allocator,2183 r: Render,
2141 ais: *Ais,
2142 tree: Ast,
2143 call: Ast.full.Call,2184 call: Ast.full.Call,
2144 space: Space,2185 space: Space,
2145) Error!void {2186) Error!void {
2187 const tree = r.tree;
2188 const ais = r.ais;
2146 const token_tags = tree.tokens.items(.tag);2189 const token_tags = tree.tokens.items(.tag);
21472190
2148 if (call.async_token) |async_token| {2191 if (call.async_token) |async_token| {
2149 try renderToken(ais, tree, async_token, .space);2192 try renderToken(r, async_token, .space);
2150 }2193 }
2151 try renderExpression(gpa, ais, tree, call.ast.fn_expr, .none);2194 try renderExpression(r, call.ast.fn_expr, .none);
21522195
2153 const lparen = call.ast.lparen;2196 const lparen = call.ast.lparen;
2154 const params = call.ast.params;2197 const params = call.ast.params;
2155 if (params.len == 0) {2198 if (params.len == 0) {
2156 ais.pushIndentNextLine();2199 ais.pushIndentNextLine();
2157 try renderToken(ais, tree, lparen, .none);2200 try renderToken(r, lparen, .none);
2158 ais.popIndent();2201 ais.popIndent();
2159 return renderToken(ais, tree, lparen + 1, space); // )2202 return renderToken(r, lparen + 1, space); // )
2160 }2203 }
21612204
2162 const last_param = params[params.len - 1];2205 const last_param = params[params.len - 1];
2163 const after_last_param_tok = tree.lastToken(last_param) + 1;2206 const after_last_param_tok = tree.lastToken(last_param) + 1;
2164 if (token_tags[after_last_param_tok] == .comma) {2207 if (token_tags[after_last_param_tok] == .comma) {
2165 ais.pushIndentNextLine();2208 ais.pushIndentNextLine();
2166 try renderToken(ais, tree, lparen, .newline); // (2209 try renderToken(r, lparen, .newline); // (
2167 for (params) |param_node, i| {2210 for (params) |param_node, i| {
2168 if (i + 1 < params.len) {2211 if (i + 1 < params.len) {
2169 try renderExpression(gpa, ais, tree, param_node, .none);2212 try renderExpression(r, param_node, .none);
21702213
2171 // Unindent the comma for multiline string literals.2214 // Unindent the comma for multiline string literals.
2172 const is_multiline_string =2215 const is_multiline_string =
...@@ -2174,20 +2217,20 @@ fn renderCall(...@@ -2174,20 +2217,20 @@ fn renderCall(
2174 if (is_multiline_string) ais.popIndent();2217 if (is_multiline_string) ais.popIndent();
21752218
2176 const comma = tree.lastToken(param_node) + 1;2219 const comma = tree.lastToken(param_node) + 1;
2177 try renderToken(ais, tree, comma, .newline); // ,2220 try renderToken(r, comma, .newline); // ,
21782221
2179 if (is_multiline_string) ais.pushIndent();2222 if (is_multiline_string) ais.pushIndent();
21802223
2181 try renderExtraNewline(ais, tree, params[i + 1]);2224 try renderExtraNewline(r, params[i + 1]);
2182 } else {2225 } else {
2183 try renderExpression(gpa, ais, tree, param_node, .comma);2226 try renderExpression(r, param_node, .comma);
2184 }2227 }
2185 }2228 }
2186 ais.popIndent();2229 ais.popIndent();
2187 return renderToken(ais, tree, after_last_param_tok + 1, space); // )2230 return renderToken(r, after_last_param_tok + 1, space); // )
2188 }2231 }
21892232
2190 try renderToken(ais, tree, lparen, .none); // (2233 try renderToken(r, lparen, .none); // (
21912234
2192 for (params) |param_node, i| {2235 for (params) |param_node, i| {
2193 const first_param_token = tree.firstToken(param_node);2236 const first_param_token = tree.firstToken(param_node);
...@@ -2196,23 +2239,25 @@ fn renderCall(...@@ -2196,23 +2239,25 @@ fn renderCall(
2196 {2239 {
2197 ais.pushIndentOneShot();2240 ais.pushIndentOneShot();
2198 }2241 }
2199 try renderExpression(gpa, ais, tree, param_node, .none);2242 try renderExpression(r, param_node, .none);
22002243
2201 if (i + 1 < params.len) {2244 if (i + 1 < params.len) {
2202 const comma = tree.lastToken(param_node) + 1;2245 const comma = tree.lastToken(param_node) + 1;
2203 const next_multiline_string =2246 const next_multiline_string =
2204 token_tags[tree.firstToken(params[i + 1])] == .multiline_string_literal_line;2247 token_tags[tree.firstToken(params[i + 1])] == .multiline_string_literal_line;
2205 const comma_space: Space = if (next_multiline_string) .none else .space;2248 const comma_space: Space = if (next_multiline_string) .none else .space;
2206 try renderToken(ais, tree, comma, comma_space);2249 try renderToken(r, comma, comma_space);
2207 }2250 }
2208 }2251 }
22092252
2210 return renderToken(ais, tree, after_last_param_tok, space); // )2253 return renderToken(r, after_last_param_tok, space); // )
2211}2254}
22122255
2213/// Renders the given expression indented, popping the indent before rendering2256/// Renders the given expression indented, popping the indent before rendering
2214/// any following line comments2257/// any following line comments
2215fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, space: Space) Error!void {2258fn renderExpressionIndented(r: Render, node: Ast.Node.Index, space: Space) Error!void {
2259 const tree = r.tree;
2260 const ais = r.ais;
2216 const token_starts = tree.tokens.items(.start);2261 const token_starts = tree.tokens.items(.start);
2217 const token_tags = tree.tokens.items(.tag);2262 const token_tags = tree.tokens.items(.tag);
22182263
...@@ -2226,24 +2271,24 @@ fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node...@@ -2226,24 +2271,24 @@ fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node
2226 .semicolon => token_tags[last_token + 1] == .semicolon,2271 .semicolon => token_tags[last_token + 1] == .semicolon,
2227 };2272 };
22282273
2229 try renderExpression(gpa, ais, tree, node, if (punctuation) .none else .skip);2274 try renderExpression(r, node, if (punctuation) .none else .skip);
22302275
2231 switch (space) {2276 switch (space) {
2232 .none, .space, .newline, .skip => {},2277 .none, .space, .newline, .skip => {},
2233 .comma => {2278 .comma => {
2234 if (token_tags[last_token + 1] == .comma) {2279 if (token_tags[last_token + 1] == .comma) {
2235 try renderToken(ais, tree, last_token + 1, .skip);2280 try renderToken(r, last_token + 1, .skip);
2236 last_token += 1;2281 last_token += 1;
2237 } else {2282 } else {
2238 try ais.writer().writeByte(',');2283 try ais.writer().writeByte(',');
2239 }2284 }
2240 },2285 },
2241 .comma_space => if (token_tags[last_token + 1] == .comma) {2286 .comma_space => if (token_tags[last_token + 1] == .comma) {
2242 try renderToken(ais, tree, last_token + 1, .skip);2287 try renderToken(r, last_token + 1, .skip);
2243 last_token += 1;2288 last_token += 1;
2244 },2289 },
2245 .semicolon => if (token_tags[last_token + 1] == .semicolon) {2290 .semicolon => if (token_tags[last_token + 1] == .semicolon) {
2246 try renderToken(ais, tree, last_token + 1, .skip);2291 try renderToken(r, last_token + 1, .skip);
2247 last_token += 1;2292 last_token += 1;
2248 },2293 },
2249 }2294 }
...@@ -2253,7 +2298,7 @@ fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node...@@ -2253,7 +2298,7 @@ fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node
2253 if (space == .skip) return;2298 if (space == .skip) return;
22542299
2255 const comment_start = token_starts[last_token] + tokenSliceForRender(tree, last_token).len;2300 const comment_start = token_starts[last_token] + tokenSliceForRender(tree, last_token).len;
2256 const comment = try renderComments(ais, tree, comment_start, token_starts[last_token + 1]);2301 const comment = try renderComments(r, comment_start, token_starts[last_token + 1]);
22572302
2258 if (!comment) switch (space) {2303 if (!comment) switch (space) {
2259 .none => {},2304 .none => {},
...@@ -2270,27 +2315,29 @@ fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node...@@ -2270,27 +2315,29 @@ fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node
22702315
2271/// Render an expression, and the comma that follows it, if it is present in the source.2316/// Render an expression, and the comma that follows it, if it is present in the source.
2272/// If a comma is present, and `space` is `Space.comma`, render only a single comma.2317/// If a comma is present, and `space` is `Space.comma`, render only a single comma.
2273fn renderExpressionComma(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index, space: Space) Error!void {2318fn renderExpressionComma(r: Render, node: Ast.Node.Index, space: Space) Error!void {
2319 const tree = r.tree;
2274 const token_tags = tree.tokens.items(.tag);2320 const token_tags = tree.tokens.items(.tag);
2275 const maybe_comma = tree.lastToken(node) + 1;2321 const maybe_comma = tree.lastToken(node) + 1;
2276 if (token_tags[maybe_comma] == .comma and space != .comma) {2322 if (token_tags[maybe_comma] == .comma and space != .comma) {
2277 try renderExpression(gpa, ais, tree, node, .none);2323 try renderExpression(r, node, .none);
2278 return renderToken(ais, tree, maybe_comma, space);2324 return renderToken(r, maybe_comma, space);
2279 } else {2325 } else {
2280 return renderExpression(gpa, ais, tree, node, space);2326 return renderExpression(r, node, space);
2281 }2327 }
2282}2328}
22832329
2284/// Render a token, and the comma that follows it, if it is present in the source.2330/// Render a token, and the comma that follows it, if it is present in the source.
2285/// If a comma is present, and `space` is `Space.comma`, render only a single comma.2331/// If a comma is present, and `space` is `Space.comma`, render only a single comma.
2286fn renderTokenComma(ais: *Ais, tree: Ast, token: Ast.TokenIndex, space: Space) Error!void {2332fn renderTokenComma(r: Render, token: Ast.TokenIndex, space: Space) Error!void {
2333 const tree = r.tree;
2287 const token_tags = tree.tokens.items(.tag);2334 const token_tags = tree.tokens.items(.tag);
2288 const maybe_comma = token + 1;2335 const maybe_comma = token + 1;
2289 if (token_tags[maybe_comma] == .comma and space != .comma) {2336 if (token_tags[maybe_comma] == .comma and space != .comma) {
2290 try renderToken(ais, tree, token, .none);2337 try renderToken(r, token, .none);
2291 return renderToken(ais, tree, maybe_comma, space);2338 return renderToken(r, maybe_comma, space);
2292 } else {2339 } else {
2293 return renderToken(ais, tree, token, space);2340 return renderToken(r, token, space);
2294 }2341 }
2295}2342}
22962343
...@@ -2315,13 +2362,17 @@ const Space = enum {...@@ -2315,13 +2362,17 @@ const Space = enum {
2315 skip,2362 skip,
2316};2363};
23172364
2318fn renderToken(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, space: Space) Error!void {2365fn renderToken(r: Render, token_index: Ast.TokenIndex, space: Space) Error!void {
2366 const tree = r.tree;
2367 const ais = r.ais;
2319 const lexeme = tokenSliceForRender(tree, token_index);2368 const lexeme = tokenSliceForRender(tree, token_index);
2320 try ais.writer().writeAll(lexeme);2369 try ais.writer().writeAll(lexeme);
2321 try renderSpace(ais, tree, token_index, lexeme.len, space);2370 try renderSpace(r, token_index, lexeme.len, space);
2322}2371}
23232372
2324fn renderSpace(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, lexeme_len: usize, space: Space) Error!void {2373fn renderSpace(r: Render, token_index: Ast.TokenIndex, lexeme_len: usize, space: Space) Error!void {
2374 const tree = r.tree;
2375 const ais = r.ais;
2325 const token_tags = tree.tokens.items(.tag);2376 const token_tags = tree.tokens.items(.tag);
2326 const token_starts = tree.tokens.items(.start);2377 const token_starts = tree.tokens.items(.start);
23272378
...@@ -2333,26 +2384,26 @@ fn renderSpace(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, lexeme_len: us...@@ -2333,26 +2384,26 @@ fn renderSpace(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex, lexeme_len: us
2333 try ais.writer().writeByte(',');2384 try ais.writer().writeByte(',');
2334 }2385 }
23352386
2336 const comment = try renderComments(ais, tree, token_start + lexeme_len, token_starts[token_index + 1]);2387 const comment = try renderComments(r, token_start + lexeme_len, token_starts[token_index + 1]);
2337 switch (space) {2388 switch (space) {
2338 .none => {},2389 .none => {},
2339 .space => if (!comment) try ais.writer().writeByte(' '),2390 .space => if (!comment) try ais.writer().writeByte(' '),
2340 .newline => if (!comment) try ais.insertNewline(),2391 .newline => if (!comment) try ais.insertNewline(),
23412392
2342 .comma => if (token_tags[token_index + 1] == .comma) {2393 .comma => if (token_tags[token_index + 1] == .comma) {
2343 try renderToken(ais, tree, token_index + 1, .newline);2394 try renderToken(r, token_index + 1, .newline);
2344 } else if (!comment) {2395 } else if (!comment) {
2345 try ais.insertNewline();2396 try ais.insertNewline();
2346 },2397 },
23472398
2348 .comma_space => if (token_tags[token_index + 1] == .comma) {2399 .comma_space => if (token_tags[token_index + 1] == .comma) {
2349 try renderToken(ais, tree, token_index + 1, .space);2400 try renderToken(r, token_index + 1, .space);
2350 } else if (!comment) {2401 } else if (!comment) {
2351 try ais.writer().writeByte(' ');2402 try ais.writer().writeByte(' ');
2352 },2403 },
23532404
2354 .semicolon => if (token_tags[token_index + 1] == .semicolon) {2405 .semicolon => if (token_tags[token_index + 1] == .semicolon) {
2355 try renderToken(ais, tree, token_index + 1, .newline);2406 try renderToken(r, token_index + 1, .newline);
2356 } else if (!comment) {2407 } else if (!comment) {
2357 try ais.insertNewline();2408 try ais.insertNewline();
2358 },2409 },
...@@ -2395,7 +2446,10 @@ fn hasMultilineString(tree: Ast, start_token: Ast.TokenIndex, end_token: Ast.Tok...@@ -2395,7 +2446,10 @@ fn hasMultilineString(tree: Ast, start_token: Ast.TokenIndex, end_token: Ast.Tok
23952446
2396/// Assumes that start is the first byte past the previous token and2447/// Assumes that start is the first byte past the previous token and
2397/// that end is the last byte before the next token.2448/// that end is the last byte before the next token.
2398fn renderComments(ais: *Ais, tree: Ast, start: usize, end: usize) Error!bool {2449fn renderComments(r: Render, start: usize, end: usize) Error!bool {
2450 const tree = r.tree;
2451 const ais = r.ais;
2452
2399 var index: usize = start;2453 var index: usize = start;
2400 while (mem.indexOf(u8, tree.source[index..end], "//")) |offset| {2454 while (mem.indexOf(u8, tree.source[index..end], "//")) |offset| {
2401 const comment_start = index + offset;2455 const comment_start = index + offset;
...@@ -2452,12 +2506,14 @@ fn renderComments(ais: *Ais, tree: Ast, start: usize, end: usize) Error!bool {...@@ -2452,12 +2506,14 @@ fn renderComments(ais: *Ais, tree: Ast, start: usize, end: usize) Error!bool {
2452 return index != start;2506 return index != start;
2453}2507}
24542508
2455fn renderExtraNewline(ais: *Ais, tree: Ast, node: Ast.Node.Index) Error!void {2509fn renderExtraNewline(r: Render, node: Ast.Node.Index) Error!void {
2456 return renderExtraNewlineToken(ais, tree, tree.firstToken(node));2510 return renderExtraNewlineToken(r, r.tree.firstToken(node));
2457}2511}
24582512
2459/// Check if there is an empty line immediately before the given token. If so, render it.2513/// Check if there is an empty line immediately before the given token. If so, render it.
2460fn renderExtraNewlineToken(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex) Error!void {2514fn renderExtraNewlineToken(r: Render, token_index: Ast.TokenIndex) Error!void {
2515 const tree = r.tree;
2516 const ais = r.ais;
2461 const token_starts = tree.tokens.items(.start);2517 const token_starts = tree.tokens.items(.start);
2462 const token_start = token_starts[token_index];2518 const token_start = token_starts[token_index];
2463 if (token_start == 0) return;2519 if (token_start == 0) return;
...@@ -2482,7 +2538,8 @@ fn renderExtraNewlineToken(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex) Er...@@ -2482,7 +2538,8 @@ fn renderExtraNewlineToken(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex) Er
24822538
2483/// end_token is the token one past the last doc comment token. This function2539/// end_token is the token one past the last doc comment token. This function
2484/// searches backwards from there.2540/// searches backwards from there.
2485fn renderDocComments(ais: *Ais, tree: Ast, end_token: Ast.TokenIndex) Error!void {2541fn renderDocComments(r: Render, end_token: Ast.TokenIndex) Error!void {
2542 const tree = r.tree;
2486 // Search backwards for the first doc comment.2543 // Search backwards for the first doc comment.
2487 const token_tags = tree.tokens.items(.tag);2544 const token_tags = tree.tokens.items(.tag);
2488 if (end_token == 0) return;2545 if (end_token == 0) return;
...@@ -2503,27 +2560,28 @@ fn renderDocComments(ais: *Ais, tree: Ast, end_token: Ast.TokenIndex) Error!void...@@ -2503,27 +2560,28 @@ fn renderDocComments(ais: *Ais, tree: Ast, end_token: Ast.TokenIndex) Error!void
2503 assert(prev_token_tag != .l_paren);2560 assert(prev_token_tag != .l_paren);
25042561
2505 if (prev_token_tag != .l_brace) {2562 if (prev_token_tag != .l_brace) {
2506 try renderExtraNewlineToken(ais, tree, first_tok);2563 try renderExtraNewlineToken(r, first_tok);
2507 }2564 }
2508 }2565 }
25092566
2510 while (token_tags[tok] == .doc_comment) : (tok += 1) {2567 while (token_tags[tok] == .doc_comment) : (tok += 1) {
2511 try renderToken(ais, tree, tok, .newline);2568 try renderToken(r, tok, .newline);
2512 }2569 }
2513}2570}
25142571
2515/// start_token is first container doc comment token.2572/// start_token is first container doc comment token.
2516fn renderContainerDocComments(ais: *Ais, tree: Ast, start_token: Ast.TokenIndex) Error!void {2573fn renderContainerDocComments(r: Render, start_token: Ast.TokenIndex) Error!void {
2574 const tree = r.tree;
2517 const token_tags = tree.tokens.items(.tag);2575 const token_tags = tree.tokens.items(.tag);
2518 var tok = start_token;2576 var tok = start_token;
2519 while (token_tags[tok] == .container_doc_comment) : (tok += 1) {2577 while (token_tags[tok] == .container_doc_comment) : (tok += 1) {
2520 try renderToken(ais, tree, tok, .newline);2578 try renderToken(r, tok, .newline);
2521 }2579 }
2522 // Render extra newline if there is one between final container doc comment and2580 // Render extra newline if there is one between final container doc comment and
2523 // the next token. If the next token is a doc comment, that code path2581 // the next token. If the next token is a doc comment, that code path
2524 // will have its own logic to insert a newline.2582 // will have its own logic to insert a newline.
2525 if (token_tags[tok] != .doc_comment) {2583 if (token_tags[tok] != .doc_comment) {
2526 try renderExtraNewlineToken(ais, tree, tok);2584 try renderExtraNewlineToken(r, tok);
2527 }2585 }
2528}2586}
25292587
src/Compilation.zig+3
...@@ -93,6 +93,7 @@ unwind_tables: bool,...@@ -93,6 +93,7 @@ unwind_tables: bool,
93test_evented_io: bool,93test_evented_io: bool,
94debug_compiler_runtime_libs: bool,94debug_compiler_runtime_libs: bool,
95debug_compile_errors: bool,95debug_compile_errors: bool,
96autofix: bool,
96job_queued_compiler_rt_lib: bool = false,97job_queued_compiler_rt_lib: bool = false,
97job_queued_compiler_rt_obj: bool = false,98job_queued_compiler_rt_obj: bool = false,
98alloc_failure_occurred: bool = false,99alloc_failure_occurred: bool = false,
...@@ -856,6 +857,7 @@ pub const InitOptions = struct {...@@ -856,6 +857,7 @@ pub const InitOptions = struct {
856 single_threaded: ?bool = null,857 single_threaded: ?bool = null,
857 rdynamic: bool = false,858 rdynamic: bool = false,
858 strip: bool = false,859 strip: bool = false,
860 autofix: bool = false,
859 function_sections: bool = false,861 function_sections: bool = false,
860 no_builtin: bool = false,862 no_builtin: bool = false,
861 is_native_os: bool,863 is_native_os: bool,
...@@ -1838,6 +1840,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {...@@ -1838,6 +1840,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
1838 .color = options.color,1840 .color = options.color,
1839 .time_report = options.time_report,1841 .time_report = options.time_report,
1840 .stack_report = options.stack_report,1842 .stack_report = options.stack_report,
1843 .autofix = options.autofix,
1841 .unwind_tables = unwind_tables,1844 .unwind_tables = unwind_tables,
1842 .test_filter = options.test_filter,1845 .test_filter = options.test_filter,
1843 .test_name_prefix = options.test_name_prefix,1846 .test_name_prefix = options.test_name_prefix,
src/Module.zig+125-54
...@@ -3493,7 +3493,11 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -3493,7 +3493,11 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
3493 const gpa = mod.gpa;3493 const gpa = mod.gpa;
34943494
3495 // In any case we need to examine the stat of the file to determine the course of action.3495 // In any case we need to examine the stat of the file to determine the course of action.
3496 var source_file = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{});3496 const want_autofix = comp.autofix and mod.main_pkg == file.pkg;
3497 const open_flags: std.fs.File.OpenMode = if (want_autofix) .read_write else .read_only;
3498 var source_file = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{
3499 .mode = open_flags,
3500 });
3497 defer source_file.close();3501 defer source_file.close();
34983502
3499 const stat = try source_file.stat();3503 const stat = try source_file.stat();
...@@ -3643,12 +3647,17 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -3643,12 +3647,17 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
36433647
3644 // TODO don't report compile errors until Sema @importFile3648 // TODO don't report compile errors until Sema @importFile
3645 if (file.zir.hasCompileErrors()) {3649 if (file.zir.hasCompileErrors()) {
3650 file.status = .astgen_failure;
3651
3652 // If autofix is requested, treat this is a cache miss so that
3653 // the autofix code has a chance to run.
3654 if (want_autofix) break :cached;
3655
3646 {3656 {
3647 comp.mutex.lock();3657 comp.mutex.lock();
3648 defer comp.mutex.unlock();3658 defer comp.mutex.unlock();
3649 try mod.failed_files.putNoClobber(gpa, file, null);3659 try mod.failed_files.putNoClobber(gpa, file, null);
3650 }3660 }
3651 file.status = .astgen_failure;
3652 return error.AnalysisFail;3661 return error.AnalysisFail;
3653 }3662 }
3654 return;3663 return;
...@@ -3726,72 +3735,134 @@ pub fn astGenFile(mod: *Module, file: *File) !void {...@@ -3726,72 +3735,134 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
3726 file.source = source;3735 file.source = source;
3727 file.source_loaded = true;3736 file.source_loaded = true;
37283737
3729 file.tree = try std.zig.parse(gpa, source);3738 // This is purely to detect when the autofix mechanism has a bug and
3730 defer if (!file.tree_loaded) file.tree.deinit(gpa);3739 // the autofix did not make the compile error go away.
37313740 var reparsing = false;
3732 if (file.tree.errors.len != 0) {3741 parse: while (true) {
3733 const parse_err = file.tree.errors[0];3742 file.tree = try std.zig.parse(gpa, file.source);
3743 defer if (!file.tree_loaded) file.tree.deinit(gpa);
37343744
3735 var msg = std.ArrayList(u8).init(gpa);3745 if (file.tree.errors.len != 0) {
3736 defer msg.deinit();3746 const parse_err = file.tree.errors[0];
37373747
3738 const token_starts = file.tree.tokens.items(.start);3748 var msg = std.ArrayList(u8).init(gpa);
3739 const token_tags = file.tree.tokens.items(.tag);3749 defer msg.deinit();
37403750
3741 const extra_offset = file.tree.errorOffset(parse_err);3751 const token_starts = file.tree.tokens.items(.start);
3742 try file.tree.renderError(parse_err, msg.writer());3752 const token_tags = file.tree.tokens.items(.tag);
3743 const err_msg = try gpa.create(ErrorMsg);
3744 err_msg.* = .{
3745 .src_loc = .{
3746 .file_scope = file,
3747 .parent_decl_node = 0,
3748 .lazy = if (extra_offset == 0) .{
3749 .token_abs = parse_err.token,
3750 } else .{
3751 .byte_abs = token_starts[parse_err.token] + extra_offset,
3752 },
3753 },
3754 .msg = msg.toOwnedSlice(),
3755 };
3756 if (token_tags[parse_err.token + @boolToInt(parse_err.token_is_prev)] == .invalid) {
3757 const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token + @boolToInt(parse_err.token_is_prev)).len);
3758 const byte_abs = token_starts[parse_err.token + @boolToInt(parse_err.token_is_prev)] + bad_off;
3759 try mod.errNoteNonLazy(.{
3760 .file_scope = file,
3761 .parent_decl_node = 0,
3762 .lazy = .{ .byte_abs = byte_abs },
3763 }, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(source[byte_abs..][0..1])});
3764 }
37653753
3766 for (file.tree.errors[1..]) |note| {3754 const extra_offset = file.tree.errorOffset(parse_err);
3767 if (!note.is_note) break;3755 try file.tree.renderError(parse_err, msg.writer());
37683756 const err_msg = try gpa.create(ErrorMsg);
3769 try file.tree.renderError(note, msg.writer());3757 err_msg.* = .{
3770 err_msg.notes = try mod.gpa.realloc(err_msg.notes, err_msg.notes.len + 1);
3771 err_msg.notes[err_msg.notes.len - 1] = .{
3772 .src_loc = .{3758 .src_loc = .{
3773 .file_scope = file,3759 .file_scope = file,
3774 .parent_decl_node = 0,3760 .parent_decl_node = 0,
3775 .lazy = .{ .token_abs = note.token },3761 .lazy = if (extra_offset == 0) .{
3762 .token_abs = parse_err.token,
3763 } else .{
3764 .byte_abs = token_starts[parse_err.token] + extra_offset,
3765 },
3776 },3766 },
3777 .msg = msg.toOwnedSlice(),3767 .msg = msg.toOwnedSlice(),
3778 };3768 };
3769 if (token_tags[parse_err.token + @boolToInt(parse_err.token_is_prev)] == .invalid) {
3770 const bad_off = @intCast(u32, file.tree.tokenSlice(parse_err.token + @boolToInt(parse_err.token_is_prev)).len);
3771 const byte_abs = token_starts[parse_err.token + @boolToInt(parse_err.token_is_prev)] + bad_off;
3772 try mod.errNoteNonLazy(.{
3773 .file_scope = file,
3774 .parent_decl_node = 0,
3775 .lazy = .{ .byte_abs = byte_abs },
3776 }, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(file.source[byte_abs..][0..1])});
3777 }
3778
3779 for (file.tree.errors[1..]) |note| {
3780 if (!note.is_note) break;
3781
3782 try file.tree.renderError(note, msg.writer());
3783 err_msg.notes = try mod.gpa.realloc(err_msg.notes, err_msg.notes.len + 1);
3784 err_msg.notes[err_msg.notes.len - 1] = .{
3785 .src_loc = .{
3786 .file_scope = file,
3787 .parent_decl_node = 0,
3788 .lazy = .{ .token_abs = note.token },
3789 },
3790 .msg = msg.toOwnedSlice(),
3791 };
3792 }
3793
3794 {
3795 comp.mutex.lock();
3796 defer comp.mutex.unlock();
3797 try mod.failed_files.putNoClobber(gpa, file, err_msg);
3798 }
3799 file.status = .parse_failure;
3800 return error.AnalysisFail;
3779 }3801 }
3802 file.tree_loaded = true;
37803803
3781 {3804 file.zir = try AstGen.generate(gpa, file.tree);
3782 comp.mutex.lock();3805 file.zir_loaded = true;
3783 defer comp.mutex.unlock();3806 file.status = .success_zir;
3784 try mod.failed_files.putNoClobber(gpa, file, err_msg);3807 log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
3808
3809 if (want_autofix and file.zir.hasCompileErrors()) {
3810 assert(!reparsing); // there are still compile errors after autofixing
3811 const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];
3812 assert(payload_index != 0);
3813 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
3814 const items_len = header.data.items_len;
3815 var fixups: Ast.Fixups = .{};
3816 defer fixups.deinit(gpa);
3817 var extra_index = header.end;
3818 var item_i: usize = 0;
3819 while (item_i < items_len) : (item_i += 1) {
3820 const item = file.zir.extraData(Zir.Inst.CompileErrors.Item, extra_index);
3821 extra_index = item.end;
3822 const msg = file.zir.nullTerminatedString(item.data.msg);
3823 if (mem.eql(u8, msg, "unused local constant")) {
3824 // goal: insert "_ = identifier;" after the variable declaration
3825 const ident_token = item.data.token;
3826 try fixups.unused_var_decls.put(gpa, ident_token - 1, {});
3827 } else {
3828 std.debug.print("found other ZIR error: '{s}'\n", .{msg});
3829 }
3830 }
3831
3832 if (fixups.count() > 0) {
3833 var autofixed_source = std.ArrayList(u8).init(gpa);
3834 defer autofixed_source.deinit();
3835 try file.tree.renderWithFixups(&autofixed_source, fixups);
3836
3837 // Replace the file source with the fixed up source.
3838 const new_source = try autofixed_source.toOwnedSliceSentinel(0);
3839 gpa.free(file.source);
3840 file.source = new_source;
3841
3842 // Overwrite the source file on disk with the fixed up source.
3843 try source_file.pwriteAll(file.source, 0);
3844
3845 // If the fixed up source is smaller in bytes then we need to
3846 // truncate the file.
3847 if (file.stat.size > file.source.len) {
3848 try source_file.setEndPos(file.source.len);
3849 }
3850
3851 // Redo the stat so that next time we get a cache hit.
3852 const new_stat = try source_file.stat();
3853 file.stat = .{
3854 .size = new_stat.size,
3855 .inode = new_stat.inode,
3856 .mtime = new_stat.mtime,
3857 };
3858
3859 reparsing = true;
3860 continue :parse;
3861 }
3785 }3862 }
3786 file.status = .parse_failure;
3787 return error.AnalysisFail;
3788 }
3789 file.tree_loaded = true;
37903863
3791 file.zir = try AstGen.generate(gpa, file.tree);3864 break :parse;
3792 file.zir_loaded = true;3865 }
3793 file.status = .success_zir;
3794 log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
37953866
3796 const safety_buffer = if (data_has_safety_tag)3867 const safety_buffer = if (data_has_safety_tag)
3797 try gpa.alloc([8]u8, file.zir.instructions.len)3868 try gpa.alloc([8]u8, file.zir.instructions.len)
src/main.zig+5
...@@ -403,6 +403,7 @@ const usage_build_generic =...@@ -403,6 +403,7 @@ const usage_build_generic =
403 \\ -ffunction-sections Places each function in a separate section403 \\ -ffunction-sections Places each function in a separate section
404 \\ -fno-function-sections All functions go into same section404 \\ -fno-function-sections All functions go into same section
405 \\ --strip Omit debug symbols405 \\ --strip Omit debug symbols
406 \\ --autofix Avoid some errors by allowing Zig to edit your code
406 \\ -ofmt=[mode] Override target object format407 \\ -ofmt=[mode] Override target object format
407 \\ elf Executable and Linking Format408 \\ elf Executable and Linking Format
408 \\ c C source code409 \\ c C source code
...@@ -629,6 +630,7 @@ fn buildOutputType(...@@ -629,6 +630,7 @@ fn buildOutputType(
629 var have_version = false;630 var have_version = false;
630 var compatibility_version: ?std.builtin.Version = null;631 var compatibility_version: ?std.builtin.Version = null;
631 var strip = false;632 var strip = false;
633 var autofix = false;
632 var function_sections = false;634 var function_sections = false;
633 var no_builtin = false;635 var no_builtin = false;
634 var watch = false;636 var watch = false;
...@@ -1286,6 +1288,8 @@ fn buildOutputType(...@@ -1286,6 +1288,8 @@ fn buildOutputType(
1286 emit_bin = .no;1288 emit_bin = .no;
1287 } else if (mem.eql(u8, arg, "--strip")) {1289 } else if (mem.eql(u8, arg, "--strip")) {
1288 strip = true;1290 strip = true;
1291 } else if (mem.eql(u8, arg, "--autofix")) {
1292 autofix = true;
1289 } else if (mem.eql(u8, arg, "-fsingle-threaded")) {1293 } else if (mem.eql(u8, arg, "-fsingle-threaded")) {
1290 single_threaded = true;1294 single_threaded = true;
1291 } else if (mem.eql(u8, arg, "-fno-single-threaded")) {1295 } else if (mem.eql(u8, arg, "-fno-single-threaded")) {
...@@ -2944,6 +2948,7 @@ fn buildOutputType(...@@ -2944,6 +2948,7 @@ fn buildOutputType(
2944 .stack_size_override = stack_size_override,2948 .stack_size_override = stack_size_override,
2945 .image_base_override = image_base_override,2949 .image_base_override = image_base_override,
2946 .strip = strip,2950 .strip = strip,
2951 .autofix = autofix,
2947 .single_threaded = single_threaded,2952 .single_threaded = single_threaded,
2948 .function_sections = function_sections,2953 .function_sections = function_sections,
2949 .no_builtin = no_builtin,2954 .no_builtin = no_builtin,