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;
1717const mem = std.mem;
1818const Token = std.zig.Token;
1919const Ast = @This();
20const private_render = @import("./render.zig");
2021
2122pub const TokenIndex = u32;
2223pub const ByteOffset = u32;
......@@ -60,8 +61,14 @@ pub fn render(tree: Ast, gpa: mem.Allocator) RenderError![]u8 {
6061 return buffer.toOwnedSlice();
6162}
6263
64pub const Fixups = private_render.Fixups;
65
6366pub 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);
6572}
6673
6774/// 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;
1313
1414const 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 {
1739 assert(tree.errors.len == 0); // Cannot render an invalid tree.
1840 var auto_indenting_stream = Ais{
1941 .indent_delta = indent_delta,
2042 .underlying_writer = buffer.writer(),
2143 };
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
2451 // Render all the line comments at the beginning of the file.
2552 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
2855 if (tree.tokens.items(.tag)[0] == .container_doc_comment) {
29 try renderContainerDocComments(ais, tree, 0);
56 try renderContainerDocComments(r, 0);
3057 }
3158
32 try renderMembers(buffer.allocator, ais, tree, tree.rootDecls());
59 try renderMembers(r, tree.rootDecls());
3360
34 if (ais.disabled_offset) |disabled_offset| {
35 try writeFixingWhitespace(ais.underlying_writer, tree.source[disabled_offset..]);
61 if (r.ais.disabled_offset) |disabled_offset| {
62 try writeFixingWhitespace(r.ais.underlying_writer, tree.source[disabled_offset..]);
3663 }
3764}
3865
3966/// 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 {
4168 if (members.len == 0) return;
42 try renderMember(gpa, ais, tree, members[0], .newline);
69 try renderMember(r, members[0], .newline);
4370 for (members[1..]) |member| {
44 try renderExtraNewline(ais, tree, member);
45 try renderMember(gpa, ais, tree, member, .newline);
71 try renderExtraNewline(r, member);
72 try renderMember(r, member, .newline);
4673 }
4774}
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;
5079 const token_tags = tree.tokens.items(.tag);
5180 const main_tokens = tree.nodes.items(.main_token);
5281 const datas = tree.nodes.items(.data);
53 try renderDocComments(ais, tree, tree.firstToken(decl));
82 try renderDocComments(r, tree.firstToken(decl));
5483 switch (tree.nodes.items(.tag)[decl]) {
5584 .fn_decl => {
5685 // Some examples:
......@@ -78,7 +107,7 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac
78107 }
79108 }
80109 while (i < fn_token) : (i += 1) {
81 try renderToken(ais, tree, i, .space);
110 try renderToken(r, i, .space);
82111 }
83112 switch (tree.nodes.items(.tag)[fn_proto]) {
84113 .fn_proto_one, .fn_proto => {
......@@ -96,8 +125,8 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac
96125 else => unreachable,
97126 }
98127 assert(datas[decl].rhs != 0);
99 try renderExpression(gpa, ais, tree, fn_proto, .space);
100 return renderExpression(gpa, ais, tree, datas[decl].rhs, space);
128 try renderExpression(r, fn_proto, .space);
129 return renderExpression(r, datas[decl].rhs, space);
101130 },
102131 .fn_proto_simple,
103132 .fn_proto_multi,
......@@ -126,42 +155,42 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac
126155 }
127156 }
128157 while (i < fn_token) : (i += 1) {
129 try renderToken(ais, tree, i, .space);
158 try renderToken(r, i, .space);
130159 }
131 try renderExpression(gpa, ais, tree, decl, .none);
132 return renderToken(ais, tree, tree.lastToken(decl) + 1, space); // semicolon
160 try renderExpression(r, decl, .none);
161 return renderToken(r, tree.lastToken(decl) + 1, space); // semicolon
133162 },
134163
135164 .@"usingnamespace" => {
136165 const main_token = main_tokens[decl];
137166 const expr = datas[decl].lhs;
138167 if (main_token > 0 and token_tags[main_token - 1] == .keyword_pub) {
139 try renderToken(ais, tree, main_token - 1, .space); // pub
168 try renderToken(r, main_token - 1, .space); // pub
140169 }
141 try renderToken(ais, tree, main_token, .space); // usingnamespace
142 try renderExpression(gpa, ais, tree, expr, .none);
143 return renderToken(ais, tree, tree.lastToken(expr) + 1, space); // ;
170 try renderToken(r, main_token, .space); // usingnamespace
171 try renderExpression(r, expr, .none);
172 return renderToken(r, tree.lastToken(expr) + 1, space); // ;
144173 },
145174
146 .global_var_decl => return renderVarDecl(gpa, ais, tree, tree.globalVarDecl(decl)),
147 .local_var_decl => return renderVarDecl(gpa, ais, tree, tree.localVarDecl(decl)),
148 .simple_var_decl => return renderVarDecl(gpa, ais, tree, tree.simpleVarDecl(decl)),
149 .aligned_var_decl => return renderVarDecl(gpa, ais, tree, tree.alignedVarDecl(decl)),
175 .global_var_decl => return renderVarDecl(r, tree.globalVarDecl(decl)),
176 .local_var_decl => return renderVarDecl(r, tree.localVarDecl(decl)),
177 .simple_var_decl => return renderVarDecl(r, tree.simpleVarDecl(decl)),
178 .aligned_var_decl => return renderVarDecl(r, tree.alignedVarDecl(decl)),
150179
151180 .test_decl => {
152181 const test_token = main_tokens[decl];
153 try renderToken(ais, tree, test_token, .space);
182 try renderToken(r, test_token, .space);
154183 const test_name_tag = token_tags[test_token + 1];
155184 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);
157186 }
158 try renderExpression(gpa, ais, tree, datas[decl].rhs, space);
187 try renderExpression(r, datas[decl].rhs, space);
159188 },
160189
161 .container_field_init => return renderContainerField(gpa, ais, tree, tree.containerFieldInit(decl), space),
162 .container_field_align => return renderContainerField(gpa, ais, tree, tree.containerFieldAlign(decl), space),
163 .container_field => return renderContainerField(gpa, ais, tree, tree.containerField(decl), space),
164 .@"comptime" => return renderExpression(gpa, ais, tree, decl, space),
190 .container_field_init => return renderContainerField(r, tree.containerFieldInit(decl), space),
191 .container_field_align => return renderContainerField(r, tree.containerFieldAlign(decl), space),
192 .container_field => return renderContainerField(r, tree.containerField(decl), space),
193 .@"comptime" => return renderExpression(r, decl, space),
165194
166195 .root => unreachable,
167196 else => unreachable,
......@@ -169,16 +198,18 @@ fn renderMember(gpa: Allocator, ais: *Ais, tree: Ast, decl: Ast.Node.Index, spac
169198}
170199
171200/// 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 {
173202 if (expressions.len == 0) return;
174 try renderExpression(gpa, ais, tree, expressions[0], space);
203 try renderExpression(r, expressions[0], space);
175204 for (expressions[1..]) |expression| {
176 try renderExtraNewline(ais, tree, expression);
177 try renderExpression(gpa, ais, tree, expression, space);
205 try renderExtraNewline(r, expression);
206 try renderExpression(r, expression, space);
178207 }
179208}
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;
182213 const token_tags = tree.tokens.items(.tag);
183214 const main_tokens = tree.nodes.items(.main_token);
184215 const node_tags = tree.nodes.items(.tag);
......@@ -196,7 +227,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
196227 try ais.writer().writeAll(lexeme);
197228 }
198229
199 return renderSpace(ais, tree, token_index, lexeme.len, space);
230 return renderSpace(r, token_index, lexeme.len, space);
200231 },
201232
202233 .integer_literal,
......@@ -205,29 +236,29 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
205236 .unreachable_literal,
206237 .anyframe_literal,
207238 .string_literal,
208 => return renderToken(ais, tree, main_tokens[node], space),
239 => return renderToken(r, main_tokens[node], space),
209240
210241 .multiline_string_literal => {
211242 var locked_indents = ais.lockOneShotIndent();
212243 try ais.maybeInsertNewline();
213244
214245 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
217248 while (locked_indents > 0) : (locked_indents -= 1) ais.popIndent();
218249
219250 switch (space) {
220251 .none, .space, .newline, .skip => {},
221 .semicolon => if (token_tags[i] == .semicolon) try renderToken(ais, tree, i, .newline),
222 .comma => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .newline),
223 .comma_space => if (token_tags[i] == .comma) try renderToken(ais, tree, i, .space),
252 .semicolon => if (token_tags[i] == .semicolon) try renderToken(r, i, .newline),
253 .comma => if (token_tags[i] == .comma) try renderToken(r, i, .newline),
254 .comma_space => if (token_tags[i] == .comma) try renderToken(r, i, .space),
224255 }
225256 },
226257
227258 .error_value => {
228 try renderToken(ais, tree, main_tokens[node], .none);
229 try renderToken(ais, tree, main_tokens[node] + 1, .none);
230 return renderToken(ais, tree, main_tokens[node] + 2, space);
259 try renderToken(r, main_tokens[node], .none);
260 try renderToken(r, main_tokens[node] + 1, .none);
261 return renderToken(r, main_tokens[node] + 2, space);
231262 },
232263
233264 .block_two,
......@@ -235,18 +266,18 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
235266 => {
236267 const statements = [2]Ast.Node.Index{ datas[node].lhs, datas[node].rhs };
237268 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);
239270 } 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);
241272 } else {
242 return renderBlock(gpa, ais, tree, node, statements[0..2], space);
273 return renderBlock(r, node, statements[0..2], space);
243274 }
244275 },
245276 .block,
246277 .block_semicolon,
247278 => {
248279 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);
250281 },
251282
252283 .@"errdefer" => {
......@@ -254,33 +285,33 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
254285 const payload_token = datas[node].lhs;
255286 const expr = datas[node].rhs;
256287
257 try renderToken(ais, tree, defer_token, .space);
288 try renderToken(r, defer_token, .space);
258289 if (payload_token != 0) {
259 try renderToken(ais, tree, payload_token - 1, .none); // |
260 try renderToken(ais, tree, payload_token, .none); // identifier
261 try renderToken(ais, tree, payload_token + 1, .space); // |
290 try renderToken(r, payload_token - 1, .none); // |
291 try renderToken(r, payload_token, .none); // identifier
292 try renderToken(r, payload_token + 1, .space); // |
262293 }
263 return renderExpression(gpa, ais, tree, expr, space);
294 return renderExpression(r, expr, space);
264295 },
265296
266297 .@"defer" => {
267298 const defer_token = main_tokens[node];
268299 const expr = datas[node].rhs;
269 try renderToken(ais, tree, defer_token, .space);
270 return renderExpression(gpa, ais, tree, expr, space);
300 try renderToken(r, defer_token, .space);
301 return renderExpression(r, expr, space);
271302 },
272303 .@"comptime", .@"nosuspend" => {
273304 const comptime_token = main_tokens[node];
274305 const block = datas[node].lhs;
275 try renderToken(ais, tree, comptime_token, .space);
276 return renderExpression(gpa, ais, tree, block, space);
306 try renderToken(r, comptime_token, .space);
307 return renderExpression(r, block, space);
277308 },
278309
279310 .@"suspend" => {
280311 const suspend_token = main_tokens[node];
281312 const body = datas[node].lhs;
282 try renderToken(ais, tree, suspend_token, .space);
283 return renderExpression(gpa, ais, tree, body, space);
313 try renderToken(r, suspend_token, .space);
314 return renderExpression(r, body, space);
284315 },
285316
286317 .@"catch" => {
......@@ -290,27 +321,27 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
290321 const same_line = tree.tokensOnSameLine(main_token, fallback_first);
291322 const after_op_space = if (same_line) Space.space else Space.newline;
292323
293 try renderExpression(gpa, ais, tree, datas[node].lhs, .space); // target
324 try renderExpression(r, datas[node].lhs, .space); // target
294325
295326 if (token_tags[fallback_first - 1] == .pipe) {
296 try renderToken(ais, tree, main_token, .space); // catch keyword
297 try renderToken(ais, tree, main_token + 1, .none); // pipe
298 try renderToken(ais, tree, main_token + 2, .none); // payload identifier
299 try renderToken(ais, tree, main_token + 3, after_op_space); // pipe
327 try renderToken(r, main_token, .space); // catch keyword
328 try renderToken(r, main_token + 1, .none); // pipe
329 try renderToken(r, main_token + 2, .none); // payload identifier
330 try renderToken(r, main_token + 3, after_op_space); // pipe
300331 } else {
301332 assert(token_tags[fallback_first - 1] == .keyword_catch);
302 try renderToken(ais, tree, main_token, after_op_space); // catch keyword
333 try renderToken(r, main_token, after_op_space); // catch keyword
303334 }
304335
305336 ais.pushIndentOneShot();
306 try renderExpression(gpa, ais, tree, datas[node].rhs, space); // fallback
337 try renderExpression(r, datas[node].rhs, space); // fallback
307338 },
308339
309340 .field_access => {
310341 const main_token = main_tokens[node];
311342 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
315346 // Allow a line break between the lhs and the dot if the lhs and rhs
316347 // are on different lines.
......@@ -321,7 +352,7 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
321352 ais.pushIndentOneShot();
322353 }
323354
324 try renderToken(ais, tree, main_token, .none);
355 try renderToken(r, main_token, .none);
325356
326357 // This check ensures that zag() is indented in the following example:
327358 // const x = foo
......@@ -332,16 +363,16 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
332363 ais.pushIndentOneShot();
333364 }
334365
335 return renderToken(ais, tree, field_access.rhs, space);
366 return renderToken(r, field_access.rhs, space);
336367 },
337368
338369 .error_union,
339370 .switch_range,
340371 => {
341372 const infix = datas[node];
342 try renderExpression(gpa, ais, tree, infix.lhs, .none);
343 try renderToken(ais, tree, main_tokens[node], .none);
344 return renderExpression(gpa, ais, tree, infix.rhs, space);
373 try renderExpression(r, infix.lhs, .none);
374 try renderToken(r, main_tokens[node], .none);
375 return renderExpression(r, infix.rhs, space);
345376 },
346377
347378 .add,
......@@ -393,17 +424,17 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
393424 .@"orelse",
394425 => {
395426 const infix = datas[node];
396 try renderExpression(gpa, ais, tree, infix.lhs, .space);
427 try renderExpression(r, infix.lhs, .space);
397428 const op_token = main_tokens[node];
398429 if (tree.tokensOnSameLine(op_token, op_token + 1)) {
399 try renderToken(ais, tree, op_token, .space);
430 try renderToken(r, op_token, .space);
400431 } else {
401432 ais.pushIndent();
402 try renderToken(ais, tree, op_token, .newline);
433 try renderToken(r, op_token, .newline);
403434 ais.popIndent();
404435 }
405436 ais.pushIndentOneShot();
406 return renderExpression(gpa, ais, tree, infix.rhs, space);
437 return renderExpression(r, infix.rhs, space);
407438 },
408439
409440 .bit_not,
......@@ -413,66 +444,66 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
413444 .optional_type,
414445 .address_of,
415446 => {
416 try renderToken(ais, tree, main_tokens[node], .none);
417 return renderExpression(gpa, ais, tree, datas[node].lhs, space);
447 try renderToken(r, main_tokens[node], .none);
448 return renderExpression(r, datas[node].lhs, space);
418449 },
419450
420451 .@"try",
421452 .@"resume",
422453 .@"await",
423454 => {
424 try renderToken(ais, tree, main_tokens[node], .space);
425 return renderExpression(gpa, ais, tree, datas[node].lhs, space);
455 try renderToken(r, main_tokens[node], .space);
456 return renderExpression(r, datas[node].lhs, space);
426457 },
427458
428 .array_type => return renderArrayType(gpa, ais, tree, tree.arrayType(node), space),
429 .array_type_sentinel => return renderArrayType(gpa, ais, tree, tree.arrayTypeSentinel(node), space),
459 .array_type => return renderArrayType(r, tree.arrayType(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),
432 .ptr_type_sentinel => return renderPtrType(gpa, ais, tree, tree.ptrTypeSentinel(node), space),
433 .ptr_type => return renderPtrType(gpa, ais, tree, tree.ptrType(node), space),
434 .ptr_type_bit_range => return renderPtrType(gpa, ais, tree, tree.ptrTypeBitRange(node), space),
462 .ptr_type_aligned => return renderPtrType(r, tree.ptrTypeAligned(node), space),
463 .ptr_type_sentinel => return renderPtrType(r, tree.ptrTypeSentinel(node), space),
464 .ptr_type => return renderPtrType(r, tree.ptrType(node), space),
465 .ptr_type_bit_range => return renderPtrType(r, tree.ptrTypeBitRange(node), space),
435466
436467 .array_init_one, .array_init_one_comma => {
437468 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);
439470 },
440471 .array_init_dot_two, .array_init_dot_two_comma => {
441472 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);
443474 },
444475 .array_init_dot,
445476 .array_init_dot_comma,
446 => return renderArrayInit(gpa, ais, tree, tree.arrayInitDot(node), space),
477 => return renderArrayInit(r, tree.arrayInitDot(node), space),
447478 .array_init,
448479 .array_init_comma,
449 => return renderArrayInit(gpa, ais, tree, tree.arrayInit(node), space),
480 => return renderArrayInit(r, tree.arrayInit(node), space),
450481
451482 .struct_init_one, .struct_init_one_comma => {
452483 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);
454485 },
455486 .struct_init_dot_two, .struct_init_dot_two_comma => {
456487 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);
458489 },
459490 .struct_init_dot,
460491 .struct_init_dot_comma,
461 => return renderStructInit(gpa, ais, tree, node, tree.structInitDot(node), space),
492 => return renderStructInit(r, node, tree.structInitDot(node), space),
462493 .struct_init,
463494 .struct_init_comma,
464 => return renderStructInit(gpa, ais, tree, node, tree.structInit(node), space),
495 => return renderStructInit(r, node, tree.structInit(node), space),
465496
466497 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => {
467498 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);
469500 },
470501
471502 .call,
472503 .call_comma,
473504 .async_call,
474505 .async_call_comma,
475 => return renderCall(gpa, ais, tree, tree.callFull(node), space),
506 => return renderCall(r, tree.callFull(node), space),
476507
477508 .array_access => {
478509 const suffix = datas[node];
......@@ -480,27 +511,27 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
480511 const rbracket = tree.lastToken(suffix.rhs) + 1;
481512 const one_line = tree.tokensOnSameLine(lbracket, rbracket);
482513 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);
484515 ais.pushIndentNextLine();
485 try renderToken(ais, tree, lbracket, inner_space); // [
486 try renderExpression(gpa, ais, tree, suffix.rhs, inner_space);
516 try renderToken(r, lbracket, inner_space); // [
517 try renderExpression(r, suffix.rhs, inner_space);
487518 ais.popIndent();
488 return renderToken(ais, tree, rbracket, space); // ]
519 return renderToken(r, rbracket, space); // ]
489520 },
490521
491 .slice_open => return renderSlice(gpa, ais, tree, node, tree.sliceOpen(node), space),
492 .slice => return renderSlice(gpa, ais, tree, node, tree.slice(node), space),
493 .slice_sentinel => return renderSlice(gpa, ais, tree, node, tree.sliceSentinel(node), space),
522 .slice_open => return renderSlice(r, node, tree.sliceOpen(node), space),
523 .slice => return renderSlice(r, node, tree.slice(node), space),
524 .slice_sentinel => return renderSlice(r, node, tree.sliceSentinel(node), space),
494525
495526 .deref => {
496 try renderExpression(gpa, ais, tree, datas[node].lhs, .none);
497 return renderToken(ais, tree, main_tokens[node], space);
527 try renderExpression(r, datas[node].lhs, .none);
528 return renderToken(r, main_tokens[node], space);
498529 },
499530
500531 .unwrap_optional => {
501 try renderExpression(gpa, ais, tree, datas[node].lhs, .none);
502 try renderToken(ais, tree, main_tokens[node], .none);
503 return renderToken(ais, tree, datas[node].rhs, space);
532 try renderExpression(r, datas[node].lhs, .none);
533 try renderToken(r, main_tokens[node], .none);
534 return renderToken(r, datas[node].rhs, space);
504535 },
505536
506537 .@"break" => {
......@@ -508,19 +539,19 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
508539 const label_token = datas[node].lhs;
509540 const target = datas[node].rhs;
510541 if (label_token == 0 and target == 0) {
511 try renderToken(ais, tree, main_token, space); // break keyword
542 try renderToken(r, main_token, space); // break keyword
512543 } else if (label_token == 0 and target != 0) {
513 try renderToken(ais, tree, main_token, .space); // break keyword
514 try renderExpression(gpa, ais, tree, target, space);
544 try renderToken(r, main_token, .space); // break keyword
545 try renderExpression(r, target, space);
515546 } else if (label_token != 0 and target == 0) {
516 try renderToken(ais, tree, main_token, .space); // break keyword
517 try renderToken(ais, tree, label_token - 1, .none); // colon
518 try renderToken(ais, tree, label_token, space); // identifier
547 try renderToken(r, main_token, .space); // break keyword
548 try renderToken(r, label_token - 1, .none); // colon
549 try renderToken(r, label_token, space); // identifier
519550 } else if (label_token != 0 and target != 0) {
520 try renderToken(ais, tree, main_token, .space); // break keyword
521 try renderToken(ais, tree, label_token - 1, .none); // colon
522 try renderToken(ais, tree, label_token, .space); // identifier
523 try renderExpression(gpa, ais, tree, target, space);
551 try renderToken(r, main_token, .space); // break keyword
552 try renderToken(r, label_token - 1, .none); // colon
553 try renderToken(r, label_token, .space); // identifier
554 try renderExpression(r, target, space);
524555 }
525556 },
526557
......@@ -528,136 +559,136 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
528559 const main_token = main_tokens[node];
529560 const label = datas[node].lhs;
530561 if (label != 0) {
531 try renderToken(ais, tree, main_token, .space); // continue
532 try renderToken(ais, tree, label - 1, .none); // :
533 return renderToken(ais, tree, label, space); // label
562 try renderToken(r, main_token, .space); // continue
563 try renderToken(r, label - 1, .none); // :
564 return renderToken(r, label, space); // label
534565 } else {
535 return renderToken(ais, tree, main_token, space); // continue
566 return renderToken(r, main_token, space); // continue
536567 }
537568 },
538569
539570 .@"return" => {
540571 if (datas[node].lhs != 0) {
541 try renderToken(ais, tree, main_tokens[node], .space);
542 try renderExpression(gpa, ais, tree, datas[node].lhs, space);
572 try renderToken(r, main_tokens[node], .space);
573 try renderExpression(r, datas[node].lhs, space);
543574 } else {
544 try renderToken(ais, tree, main_tokens[node], space);
575 try renderToken(r, main_tokens[node], space);
545576 }
546577 },
547578
548579 .grouped_expression => {
549 try renderToken(ais, tree, main_tokens[node], .none); // lparen
580 try renderToken(r, main_tokens[node], .none); // lparen
550581 ais.pushIndentOneShot();
551 try renderExpression(gpa, ais, tree, datas[node].lhs, .none);
552 return renderToken(ais, tree, datas[node].rhs, space); // rparen
582 try renderExpression(r, datas[node].lhs, .none);
583 return renderToken(r, datas[node].rhs, space); // rparen
553584 },
554585
555586 .container_decl,
556587 .container_decl_trailing,
557 => return renderContainerDecl(gpa, ais, tree, node, tree.containerDecl(node), space),
588 => return renderContainerDecl(r, node, tree.containerDecl(node), space),
558589
559590 .container_decl_two, .container_decl_two_trailing => {
560591 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);
562593 },
563594 .container_decl_arg,
564595 .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
567598 .tagged_union,
568599 .tagged_union_trailing,
569 => return renderContainerDecl(gpa, ais, tree, node, tree.taggedUnion(node), space),
600 => return renderContainerDecl(r, node, tree.taggedUnion(node), space),
570601
571602 .tagged_union_two, .tagged_union_two_trailing => {
572603 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);
574605 },
575606 .tagged_union_enum_tag,
576607 .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
579610 .error_set_decl => {
580611 const error_token = main_tokens[node];
581612 const lbrace = error_token + 1;
582613 const rbrace = datas[node].rhs;
583614
584 try renderToken(ais, tree, error_token, .none);
615 try renderToken(r, error_token, .none);
585616
586617 if (lbrace + 1 == rbrace) {
587618 // There is nothing between the braces so render condensed: `error{}`
588 try renderToken(ais, tree, lbrace, .none);
589 return renderToken(ais, tree, rbrace, space);
619 try renderToken(r, lbrace, .none);
620 return renderToken(r, rbrace, space);
590621 } else if (lbrace + 2 == rbrace and token_tags[lbrace + 1] == .identifier) {
591622 // There is exactly one member and no trailing comma or
592623 // comments, so render without surrounding spaces: `error{Foo}`
593 try renderToken(ais, tree, lbrace, .none);
594 try renderToken(ais, tree, lbrace + 1, .none); // identifier
595 return renderToken(ais, tree, rbrace, space);
624 try renderToken(r, lbrace, .none);
625 try renderToken(r, lbrace + 1, .none); // identifier
626 return renderToken(r, rbrace, space);
596627 } else if (token_tags[rbrace - 1] == .comma) {
597628 // There is a trailing comma so render each member on a new line.
598629 ais.pushIndentNextLine();
599 try renderToken(ais, tree, lbrace, .newline);
630 try renderToken(r, lbrace, .newline);
600631 var i = lbrace + 1;
601632 while (i < rbrace) : (i += 1) {
602 if (i > lbrace + 1) try renderExtraNewlineToken(ais, tree, i);
633 if (i > lbrace + 1) try renderExtraNewlineToken(r, i);
603634 switch (token_tags[i]) {
604 .doc_comment => try renderToken(ais, tree, i, .newline),
605 .identifier => try renderToken(ais, tree, i, .comma),
635 .doc_comment => try renderToken(r, i, .newline),
636 .identifier => try renderToken(r, i, .comma),
606637 .comma => {},
607638 else => unreachable,
608639 }
609640 }
610641 ais.popIndent();
611 return renderToken(ais, tree, rbrace, space);
642 return renderToken(r, rbrace, space);
612643 } else {
613644 // There is no trailing comma so render everything on one line.
614 try renderToken(ais, tree, lbrace, .space);
645 try renderToken(r, lbrace, .space);
615646 var i = lbrace + 1;
616647 while (i < rbrace) : (i += 1) {
617648 switch (token_tags[i]) {
618649 .doc_comment => unreachable, // TODO
619 .identifier => try renderToken(ais, tree, i, .comma_space),
650 .identifier => try renderToken(r, i, .comma_space),
620651 .comma => {},
621652 else => unreachable,
622653 }
623654 }
624 return renderToken(ais, tree, rbrace, space);
655 return renderToken(r, rbrace, space);
625656 }
626657 },
627658
628659 .builtin_call_two, .builtin_call_two_comma => {
629660 if (datas[node].lhs == 0) {
630 return renderBuiltinCall(gpa, ais, tree, main_tokens[node], &.{}, space);
661 return renderBuiltinCall(r, main_tokens[node], &.{}, space);
631662 } 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);
633664 } 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);
635666 }
636667 },
637668 .builtin_call, .builtin_call_comma => {
638669 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);
640671 },
641672
642673 .fn_proto_simple => {
643674 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);
645676 },
646 .fn_proto_multi => return renderFnProto(gpa, ais, tree, tree.fnProtoMulti(node), space),
677 .fn_proto_multi => return renderFnProto(r, tree.fnProtoMulti(node), space),
647678 .fn_proto_one => {
648679 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);
650681 },
651 .fn_proto => return renderFnProto(gpa, ais, tree, tree.fnProto(node), space),
682 .fn_proto => return renderFnProto(r, tree.fnProto(node), space),
652683
653684 .anyframe_type => {
654685 const main_token = main_tokens[node];
655686 if (datas[node].rhs != 0) {
656 try renderToken(ais, tree, main_token, .none); // anyframe
657 try renderToken(ais, tree, main_token + 1, .none); // ->
658 return renderExpression(gpa, ais, tree, datas[node].rhs, space);
687 try renderToken(r, main_token, .none); // anyframe
688 try renderToken(r, main_token + 1, .none); // ->
689 return renderExpression(r, datas[node].rhs, space);
659690 } else {
660 return renderToken(ais, tree, main_token, space); // anyframe
691 return renderToken(r, main_token, space); // anyframe
661692 }
662693 },
663694
......@@ -670,40 +701,40 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
670701 const cases = tree.extra_data[extra.start..extra.end];
671702 const rparen = tree.lastToken(condition) + 1;
672703
673 try renderToken(ais, tree, switch_token, .space); // switch keyword
674 try renderToken(ais, tree, switch_token + 1, .none); // lparen
675 try renderExpression(gpa, ais, tree, condition, .none); // condtion expression
676 try renderToken(ais, tree, rparen, .space); // rparen
704 try renderToken(r, switch_token, .space); // switch keyword
705 try renderToken(r, switch_token + 1, .none); // lparen
706 try renderExpression(r, condition, .none); // condtion expression
707 try renderToken(r, rparen, .space); // rparen
677708
678709 ais.pushIndentNextLine();
679710 if (cases.len == 0) {
680 try renderToken(ais, tree, rparen + 1, .none); // lbrace
711 try renderToken(r, rparen + 1, .none); // lbrace
681712 } else {
682 try renderToken(ais, tree, rparen + 1, .newline); // lbrace
683 try renderExpressions(gpa, ais, tree, cases, .comma);
713 try renderToken(r, rparen + 1, .newline); // lbrace
714 try renderExpressions(r, cases, .comma);
684715 }
685716 ais.popIndent();
686 return renderToken(ais, tree, tree.lastToken(node), space); // rbrace
717 return renderToken(r, tree.lastToken(node), space); // rbrace
687718 },
688719
689 .switch_case_one => return renderSwitchCase(gpa, ais, tree, tree.switchCaseOne(node), space),
690 .switch_case => return renderSwitchCase(gpa, ais, tree, tree.switchCase(node), space),
720 .switch_case_one => return renderSwitchCase(r, tree.switchCaseOne(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),
693 .while_cont => return renderWhile(gpa, ais, tree, tree.whileCont(node), space),
694 .@"while" => return renderWhile(gpa, ais, tree, tree.whileFull(node), space),
695 .for_simple => return renderWhile(gpa, ais, tree, tree.forSimple(node), space),
696 .@"for" => return renderWhile(gpa, ais, tree, tree.forFull(node), space),
723 .while_simple => return renderWhile(r, tree.whileSimple(node), space),
724 .while_cont => return renderWhile(r, tree.whileCont(node), space),
725 .@"while" => return renderWhile(r, tree.whileFull(node), space),
726 .for_simple => return renderWhile(r, tree.forSimple(node), space),
727 .@"for" => return renderWhile(r, tree.forFull(node), space),
697728
698 .if_simple => return renderIf(gpa, ais, tree, tree.ifSimple(node), space),
699 .@"if" => return renderIf(gpa, ais, tree, tree.ifFull(node), space),
729 .if_simple => return renderIf(r, tree.ifSimple(node), space),
730 .@"if" => return renderIf(r, tree.ifFull(node), space),
700731
701 .asm_simple => return renderAsm(gpa, ais, tree, tree.asmSimple(node), space),
702 .@"asm" => return renderAsm(gpa, ais, tree, tree.asmFull(node), space),
732 .asm_simple => return renderAsm(r, tree.asmSimple(node), space),
733 .@"asm" => return renderAsm(r, tree.asmFull(node), space),
703734
704735 .enum_literal => {
705 try renderToken(ais, tree, main_tokens[node] - 1, .none); // .
706 return renderToken(ais, tree, main_tokens[node], space); // name
736 try renderToken(r, main_tokens[node] - 1, .none); // .
737 return renderToken(r, main_tokens[node], space); // name
707738 },
708739
709740 .fn_decl => unreachable,
......@@ -723,34 +754,29 @@ fn renderExpression(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node.Index,
723754}
724755
725756fn renderArrayType(
726 gpa: Allocator,
727 ais: *Ais,
728 tree: Ast,
757 r: Render,
729758 array_type: Ast.full.ArrayType,
730759 space: Space,
731760) Error!void {
761 const tree = r.tree;
762 const ais = r.ais;
732763 const rbracket = tree.firstToken(array_type.ast.elem_type) - 1;
733764 const one_line = tree.tokensOnSameLine(array_type.ast.lbracket, rbracket);
734765 const inner_space = if (one_line) Space.none else Space.newline;
735766 ais.pushIndentNextLine();
736 try renderToken(ais, tree, array_type.ast.lbracket, inner_space); // lbracket
737 try renderExpression(gpa, ais, tree, array_type.ast.elem_count, inner_space);
767 try renderToken(r, array_type.ast.lbracket, inner_space); // lbracket
768 try renderExpression(r, array_type.ast.elem_count, inner_space);
738769 if (array_type.ast.sentinel != 0) {
739 try renderToken(ais, tree, tree.firstToken(array_type.ast.sentinel) - 1, inner_space); // colon
740 try renderExpression(gpa, ais, tree, array_type.ast.sentinel, inner_space);
770 try renderToken(r, tree.firstToken(array_type.ast.sentinel) - 1, inner_space); // colon
771 try renderExpression(r, array_type.ast.sentinel, inner_space);
741772 }
742773 ais.popIndent();
743 try renderToken(ais, tree, rbracket, .none); // rbracket
744 return renderExpression(gpa, ais, tree, array_type.ast.elem_type, space);
774 try renderToken(r, rbracket, .none); // rbracket
775 return renderExpression(r, array_type.ast.elem_type, space);
745776}
746777
747fn renderPtrType(
748 gpa: Allocator,
749 ais: *Ais,
750 tree: Ast,
751 ptr_type: Ast.full.PtrType,
752 space: Space,
753) Error!void {
778fn renderPtrType(r: Render, ptr_type: Ast.full.PtrType, space: Space) Error!void {
779 const tree = r.tree;
754780 switch (ptr_type.size) {
755781 .One => {
756782 // Since ** tokens exist and the same token is shared by two
......@@ -761,90 +787,89 @@ fn renderPtrType(
761787 if (tree.tokens.items(.tag)[ptr_type.ast.main_token] == .asterisk_asterisk and
762788 ptr_type.ast.main_token == tree.nodes.items(.main_token)[ptr_type.ast.child_type])
763789 {
764 return renderExpression(gpa, ais, tree, ptr_type.ast.child_type, space);
790 return renderExpression(r, ptr_type.ast.child_type, space);
765791 }
766 try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk
792 try renderToken(r, ptr_type.ast.main_token, .none); // asterisk
767793 },
768794 .Many => {
769795 if (ptr_type.ast.sentinel == 0) {
770 try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket
771 try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk
772 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // rbracket
796 try renderToken(r, ptr_type.ast.main_token - 1, .none); // lbracket
797 try renderToken(r, ptr_type.ast.main_token, .none); // asterisk
798 try renderToken(r, ptr_type.ast.main_token + 1, .none); // rbracket
773799 } else {
774 try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket
775 try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk
776 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // colon
777 try renderExpression(gpa, ais, tree, ptr_type.ast.sentinel, .none);
778 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket
800 try renderToken(r, ptr_type.ast.main_token - 1, .none); // lbracket
801 try renderToken(r, ptr_type.ast.main_token, .none); // asterisk
802 try renderToken(r, ptr_type.ast.main_token + 1, .none); // colon
803 try renderExpression(r, ptr_type.ast.sentinel, .none);
804 try renderToken(r, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket
779805 }
780806 },
781807 .C => {
782 try renderToken(ais, tree, ptr_type.ast.main_token - 1, .none); // lbracket
783 try renderToken(ais, tree, ptr_type.ast.main_token, .none); // asterisk
784 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // c
785 try renderToken(ais, tree, ptr_type.ast.main_token + 2, .none); // rbracket
808 try renderToken(r, ptr_type.ast.main_token - 1, .none); // lbracket
809 try renderToken(r, ptr_type.ast.main_token, .none); // asterisk
810 try renderToken(r, ptr_type.ast.main_token + 1, .none); // c
811 try renderToken(r, ptr_type.ast.main_token + 2, .none); // rbracket
786812 },
787813 .Slice => {
788814 if (ptr_type.ast.sentinel == 0) {
789 try renderToken(ais, tree, ptr_type.ast.main_token, .none); // lbracket
790 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // rbracket
815 try renderToken(r, ptr_type.ast.main_token, .none); // lbracket
816 try renderToken(r, ptr_type.ast.main_token + 1, .none); // rbracket
791817 } else {
792 try renderToken(ais, tree, ptr_type.ast.main_token, .none); // lbracket
793 try renderToken(ais, tree, ptr_type.ast.main_token + 1, .none); // colon
794 try renderExpression(gpa, ais, tree, ptr_type.ast.sentinel, .none);
795 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket
818 try renderToken(r, ptr_type.ast.main_token, .none); // lbracket
819 try renderToken(r, ptr_type.ast.main_token + 1, .none); // colon
820 try renderExpression(r, ptr_type.ast.sentinel, .none);
821 try renderToken(r, tree.lastToken(ptr_type.ast.sentinel) + 1, .none); // rbracket
796822 }
797823 },
798824 }
799825
800826 if (ptr_type.allowzero_token) |allowzero_token| {
801 try renderToken(ais, tree, allowzero_token, .space);
827 try renderToken(r, allowzero_token, .space);
802828 }
803829
804830 if (ptr_type.ast.align_node != 0) {
805831 const align_first = tree.firstToken(ptr_type.ast.align_node);
806 try renderToken(ais, tree, align_first - 2, .none); // align
807 try renderToken(ais, tree, align_first - 1, .none); // lparen
808 try renderExpression(gpa, ais, tree, ptr_type.ast.align_node, .none);
832 try renderToken(r, align_first - 2, .none); // align
833 try renderToken(r, align_first - 1, .none); // lparen
834 try renderExpression(r, ptr_type.ast.align_node, .none);
809835 if (ptr_type.ast.bit_range_start != 0) {
810836 assert(ptr_type.ast.bit_range_end != 0);
811 try renderToken(ais, tree, tree.firstToken(ptr_type.ast.bit_range_start) - 1, .none); // colon
812 try renderExpression(gpa, ais, tree, ptr_type.ast.bit_range_start, .none);
813 try renderToken(ais, tree, tree.firstToken(ptr_type.ast.bit_range_end) - 1, .none); // colon
814 try renderExpression(gpa, ais, tree, ptr_type.ast.bit_range_end, .none);
815 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.bit_range_end) + 1, .space); // rparen
837 try renderToken(r, tree.firstToken(ptr_type.ast.bit_range_start) - 1, .none); // colon
838 try renderExpression(r, ptr_type.ast.bit_range_start, .none);
839 try renderToken(r, tree.firstToken(ptr_type.ast.bit_range_end) - 1, .none); // colon
840 try renderExpression(r, ptr_type.ast.bit_range_end, .none);
841 try renderToken(r, tree.lastToken(ptr_type.ast.bit_range_end) + 1, .space); // rparen
816842 } else {
817 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.align_node) + 1, .space); // rparen
843 try renderToken(r, tree.lastToken(ptr_type.ast.align_node) + 1, .space); // rparen
818844 }
819845 }
820846
821847 if (ptr_type.ast.addrspace_node != 0) {
822848 const addrspace_first = tree.firstToken(ptr_type.ast.addrspace_node);
823 try renderToken(ais, tree, addrspace_first - 2, .none); // addrspace
824 try renderToken(ais, tree, addrspace_first - 1, .none); // lparen
825 try renderExpression(gpa, ais, tree, ptr_type.ast.addrspace_node, .none);
826 try renderToken(ais, tree, tree.lastToken(ptr_type.ast.addrspace_node) + 1, .space); // rparen
849 try renderToken(r, addrspace_first - 2, .none); // addrspace
850 try renderToken(r, addrspace_first - 1, .none); // lparen
851 try renderExpression(r, ptr_type.ast.addrspace_node, .none);
852 try renderToken(r, tree.lastToken(ptr_type.ast.addrspace_node) + 1, .space); // rparen
827853 }
828854
829855 if (ptr_type.const_token) |const_token| {
830 try renderToken(ais, tree, const_token, .space);
856 try renderToken(r, const_token, .space);
831857 }
832858
833859 if (ptr_type.volatile_token) |volatile_token| {
834 try renderToken(ais, tree, volatile_token, .space);
860 try renderToken(r, volatile_token, .space);
835861 }
836862
837 try renderExpression(gpa, ais, tree, ptr_type.ast.child_type, space);
863 try renderExpression(r, ptr_type.ast.child_type, space);
838864}
839865
840866fn renderSlice(
841 gpa: Allocator,
842 ais: *Ais,
843 tree: Ast,
867 r: Render,
844868 slice_node: Ast.Node.Index,
845869 slice: Ast.full.Slice,
846870 space: Space,
847871) Error!void {
872 const tree = r.tree;
848873 const node_tags = tree.nodes.items(.tag);
849874 const after_start_space_bool = nodeCausesSliceOpSpace(node_tags[slice.ast.start]) or
850875 if (slice.ast.end != 0) nodeCausesSliceOpSpace(node_tags[slice.ast.end]) else false;
......@@ -853,33 +878,32 @@ fn renderSlice(
853878 after_start_space
854879 else if (slice.ast.sentinel != 0) Space.space else Space.none;
855880
856 try renderExpression(gpa, ais, tree, slice.ast.sliced, .none);
857 try renderToken(ais, tree, slice.ast.lbracket, .none); // lbracket
881 try renderExpression(r, slice.ast.sliced, .none);
882 try renderToken(r, slice.ast.lbracket, .none); // lbracket
858883
859884 const start_last = tree.lastToken(slice.ast.start);
860 try renderExpression(gpa, ais, tree, slice.ast.start, after_start_space);
861 try renderToken(ais, tree, start_last + 1, after_dots_space); // ellipsis2 ("..")
885 try renderExpression(r, slice.ast.start, after_start_space);
886 try renderToken(r, start_last + 1, after_dots_space); // ellipsis2 ("..")
862887
863888 if (slice.ast.end != 0) {
864889 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);
866891 }
867892
868893 if (slice.ast.sentinel != 0) {
869 try renderToken(ais, tree, tree.firstToken(slice.ast.sentinel) - 1, .none); // colon
870 try renderExpression(gpa, ais, tree, slice.ast.sentinel, .none);
894 try renderToken(r, tree.firstToken(slice.ast.sentinel) - 1, .none); // colon
895 try renderExpression(r, slice.ast.sentinel, .none);
871896 }
872897
873 try renderToken(ais, tree, tree.lastToken(slice_node), space); // rbracket
898 try renderToken(r, tree.lastToken(slice_node), space); // rbracket
874899}
875900
876901fn renderAsmOutput(
877 gpa: Allocator,
878 ais: *Ais,
879 tree: Ast,
902 r: Render,
880903 asm_output: Ast.Node.Index,
881904 space: Space,
882905) Error!void {
906 const tree = r.tree;
883907 const token_tags = tree.tokens.items(.tag);
884908 const node_tags = tree.nodes.items(.tag);
885909 const main_tokens = tree.nodes.items(.main_token);
......@@ -887,66 +911,79 @@ fn renderAsmOutput(
887911 assert(node_tags[asm_output] == .asm_output);
888912 const symbolic_name = main_tokens[asm_output];
889913
890 try renderToken(ais, tree, symbolic_name - 1, .none); // lbracket
891 try renderToken(ais, tree, symbolic_name, .none); // ident
892 try renderToken(ais, tree, symbolic_name + 1, .space); // rbracket
893 try renderToken(ais, tree, symbolic_name + 2, .space); // "constraint"
894 try renderToken(ais, tree, symbolic_name + 3, .none); // lparen
914 try renderToken(r, symbolic_name - 1, .none); // lbracket
915 try renderToken(r, symbolic_name, .none); // ident
916 try renderToken(r, symbolic_name + 1, .space); // rbracket
917 try renderToken(r, symbolic_name + 2, .space); // "constraint"
918 try renderToken(r, symbolic_name + 3, .none); // lparen
895919
896920 if (token_tags[symbolic_name + 4] == .arrow) {
897 try renderToken(ais, tree, symbolic_name + 4, .space); // ->
898 try renderExpression(gpa, ais, tree, datas[asm_output].lhs, Space.none);
899 return renderToken(ais, tree, datas[asm_output].rhs, space); // rparen
921 try renderToken(r, symbolic_name + 4, .space); // ->
922 try renderExpression(r, datas[asm_output].lhs, Space.none);
923 return renderToken(r, datas[asm_output].rhs, space); // rparen
900924 } else {
901 try renderToken(ais, tree, symbolic_name + 4, .none); // ident
902 return renderToken(ais, tree, symbolic_name + 5, space); // rparen
925 try renderToken(r, symbolic_name + 4, .none); // ident
926 return renderToken(r, symbolic_name + 5, space); // rparen
903927 }
904928}
905929
906930fn renderAsmInput(
907 gpa: Allocator,
908 ais: *Ais,
909 tree: Ast,
931 r: Render,
910932 asm_input: Ast.Node.Index,
911933 space: Space,
912934) Error!void {
935 const tree = r.tree;
913936 const node_tags = tree.nodes.items(.tag);
914937 const main_tokens = tree.nodes.items(.main_token);
915938 const datas = tree.nodes.items(.data);
916939 assert(node_tags[asm_input] == .asm_input);
917940 const symbolic_name = main_tokens[asm_input];
918941
919 try renderToken(ais, tree, symbolic_name - 1, .none); // lbracket
920 try renderToken(ais, tree, symbolic_name, .none); // ident
921 try renderToken(ais, tree, symbolic_name + 1, .space); // rbracket
922 try renderToken(ais, tree, symbolic_name + 2, .space); // "constraint"
923 try renderToken(ais, tree, symbolic_name + 3, .none); // lparen
924 try renderExpression(gpa, ais, tree, datas[asm_input].lhs, Space.none);
925 return renderToken(ais, tree, datas[asm_input].rhs, space); // rparen
942 try renderToken(r, symbolic_name - 1, .none); // lbracket
943 try renderToken(r, symbolic_name, .none); // ident
944 try renderToken(r, symbolic_name + 1, .space); // rbracket
945 try renderToken(r, symbolic_name + 2, .space); // "constraint"
946 try renderToken(r, symbolic_name + 3, .none); // lparen
947 try renderExpression(r, datas[asm_input].lhs, Space.none);
948 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 }
926960}
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
929966 if (var_decl.visib_token) |visib_token| {
930 try renderToken(ais, tree, visib_token, Space.space); // pub
967 try renderToken(r, visib_token, Space.space); // pub
931968 }
932969
933970 if (var_decl.extern_export_token) |extern_export_token| {
934 try renderToken(ais, tree, extern_export_token, Space.space); // extern
971 try renderToken(r, extern_export_token, Space.space); // extern
935972
936973 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"
938975 }
939976 }
940977
941978 if (var_decl.threadlocal_token) |thread_local_token| {
942 try renderToken(ais, tree, thread_local_token, Space.space); // threadlocal
979 try renderToken(r, thread_local_token, Space.space); // threadlocal
943980 }
944981
945982 if (var_decl.comptime_token) |comptime_token| {
946 try renderToken(ais, tree, comptime_token, Space.space); // comptime
983 try renderToken(r, comptime_token, Space.space); // comptime
947984 }
948985
949 try renderToken(ais, tree, var_decl.ast.mut_token, .space); // var
986 try renderToken(r, var_decl.ast.mut_token, .space); // var
950987
951988 const name_space = if (var_decl.ast.type_node == 0 and
952989 (var_decl.ast.align_node != 0 or
......@@ -956,18 +993,18 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec
956993 Space.space
957994 else
958995 Space.none;
959 try renderToken(ais, tree, var_decl.ast.mut_token + 1, name_space); // name
996 try renderToken(r, var_decl.ast.mut_token + 1, name_space); // name
960997
961998 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); // :
9631000 if (var_decl.ast.align_node != 0 or var_decl.ast.addrspace_node != 0 or
9641001 var_decl.ast.section_node != 0 or var_decl.ast.init_node != 0)
9651002 {
966 try renderExpression(gpa, ais, tree, var_decl.ast.type_node, .space);
1003 try renderExpression(r, var_decl.ast.type_node, .space);
9671004 } else {
968 try renderExpression(gpa, ais, tree, var_decl.ast.type_node, .none);
1005 try renderExpression(r, var_decl.ast.type_node, .none);
9691006 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); // ;
9711008 }
9721009 }
9731010
......@@ -975,16 +1012,16 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec
9751012 const lparen = tree.firstToken(var_decl.ast.align_node) - 1;
9761013 const align_kw = lparen - 1;
9771014 const rparen = tree.lastToken(var_decl.ast.align_node) + 1;
978 try renderToken(ais, tree, align_kw, Space.none); // align
979 try renderToken(ais, tree, lparen, Space.none); // (
980 try renderExpression(gpa, ais, tree, var_decl.ast.align_node, Space.none);
1015 try renderToken(r, align_kw, Space.none); // align
1016 try renderToken(r, lparen, Space.none); // (
1017 try renderExpression(r, var_decl.ast.align_node, Space.none);
9811018 if (var_decl.ast.addrspace_node != 0 or var_decl.ast.section_node != 0 or
9821019 var_decl.ast.init_node != 0)
9831020 {
984 try renderToken(ais, tree, rparen, .space); // )
1021 try renderToken(r, rparen, .space); // )
9851022 } else {
986 try renderToken(ais, tree, rparen, .none); // )
987 return renderToken(ais, tree, rparen + 1, Space.newline); // ;
1023 try renderToken(r, rparen, .none); // )
1024 return renderToken(r, rparen + 1, Space.newline); // ;
9881025 }
9891026 }
9901027
......@@ -992,14 +1029,14 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec
9921029 const lparen = tree.firstToken(var_decl.ast.addrspace_node) - 1;
9931030 const addrspace_kw = lparen - 1;
9941031 const rparen = tree.lastToken(var_decl.ast.addrspace_node) + 1;
995 try renderToken(ais, tree, addrspace_kw, Space.none); // addrspace
996 try renderToken(ais, tree, lparen, Space.none); // (
997 try renderExpression(gpa, ais, tree, var_decl.ast.addrspace_node, Space.none);
1032 try renderToken(r, addrspace_kw, Space.none); // addrspace
1033 try renderToken(r, lparen, Space.none); // (
1034 try renderExpression(r, var_decl.ast.addrspace_node, Space.none);
9981035 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); // )
10001037 } else {
1001 try renderToken(ais, tree, rparen, .none); // )
1002 return renderToken(ais, tree, rparen + 1, Space.newline); // ;
1038 try renderToken(r, rparen, .none); // )
1039 return renderToken(r, rparen + 1, Space.newline); // ;
10031040 }
10041041 }
10051042
......@@ -1007,14 +1044,14 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec
10071044 const lparen = tree.firstToken(var_decl.ast.section_node) - 1;
10081045 const section_kw = lparen - 1;
10091046 const rparen = tree.lastToken(var_decl.ast.section_node) + 1;
1010 try renderToken(ais, tree, section_kw, Space.none); // linksection
1011 try renderToken(ais, tree, lparen, Space.none); // (
1012 try renderExpression(gpa, ais, tree, var_decl.ast.section_node, Space.none);
1047 try renderToken(r, section_kw, Space.none); // linksection
1048 try renderToken(r, lparen, Space.none); // (
1049 try renderExpression(r, var_decl.ast.section_node, Space.none);
10131050 if (var_decl.ast.init_node != 0) {
1014 try renderToken(ais, tree, rparen, .space); // )
1051 try renderToken(r, rparen, .space); // )
10151052 } else {
1016 try renderToken(ais, tree, rparen, .none); // )
1017 return renderToken(ais, tree, rparen + 1, Space.newline); // ;
1053 try renderToken(r, rparen, .none); // )
1054 return renderToken(r, rparen + 1, Space.newline); // ;
10181055 }
10191056 }
10201057
......@@ -1023,17 +1060,17 @@ fn renderVarDecl(gpa: Allocator, ais: *Ais, tree: Ast, var_decl: Ast.full.VarDec
10231060 const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline;
10241061 {
10251062 ais.pushIndent();
1026 try renderToken(ais, tree, eq_token, eq_space); // =
1063 try renderToken(r, eq_token, eq_space); // =
10271064 ais.popIndent();
10281065 }
10291066 ais.pushIndentOneShot();
1030 return renderExpression(gpa, ais, tree, var_decl.ast.init_node, .semicolon); // ;
1067 return renderExpression(r, var_decl.ast.init_node, .semicolon); // ;
10311068 }
1032 return renderToken(ais, tree, var_decl.ast.mut_token + 2, .newline); // ;
1069 return renderToken(r, var_decl.ast.mut_token + 2, .newline); // ;
10331070}
10341071
1035fn renderIf(gpa: Allocator, ais: *Ais, tree: Ast, if_node: Ast.full.If, space: Space) Error!void {
1036 return renderWhile(gpa, ais, tree, .{
1072fn renderIf(r: Render, if_node: Ast.full.If, space: Space) Error!void {
1073 return renderWhile(r, .{
10371074 .ast = .{
10381075 .while_token = if_node.ast.if_token,
10391076 .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
10511088
10521089/// Note that this function is additionally used to render if and for expressions, with
10531090/// 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;
10551094 const node_tags = tree.nodes.items(.tag);
10561095 const token_tags = tree.tokens.items(.tag);
10571096
10581097 if (while_node.label_token) |label| {
1059 try renderToken(ais, tree, label, .none); // label
1060 try renderToken(ais, tree, label + 1, .space); // :
1098 try renderToken(r, label, .none); // label
1099 try renderToken(r, label + 1, .space); // :
10611100 }
10621101
10631102 if (while_node.inline_token) |inline_token| {
1064 try renderToken(ais, tree, inline_token, .space); // inline
1103 try renderToken(r, inline_token, .space); // inline
10651104 }
10661105
1067 try renderToken(ais, tree, while_node.ast.while_token, .space); // if/for/while
1068 try renderToken(ais, tree, while_node.ast.while_token + 1, .none); // lparen
1069 try renderExpression(gpa, ais, tree, while_node.ast.cond_expr, .none); // condition
1106 try renderToken(r, while_node.ast.while_token, .space); // if/for/while
1107 try renderToken(r, while_node.ast.while_token + 1, .none); // lparen
1108 try renderExpression(r, while_node.ast.cond_expr, .none); // condition
10701109
10711110 var last_prefix_token = tree.lastToken(while_node.ast.cond_expr) + 1; // rparen
10721111
10731112 if (while_node.payload_token) |payload_token| {
1074 try renderToken(ais, tree, last_prefix_token, .space);
1075 try renderToken(ais, tree, payload_token - 1, .none); // |
1113 try renderToken(r, last_prefix_token, .space);
1114 try renderToken(r, payload_token - 1, .none); // |
10761115 const ident = blk: {
10771116 if (token_tags[payload_token] == .asterisk) {
1078 try renderToken(ais, tree, payload_token, .none); // *
1117 try renderToken(r, payload_token, .none); // *
10791118 break :blk payload_token + 1;
10801119 } else {
10811120 break :blk payload_token;
10821121 }
10831122 };
1084 try renderToken(ais, tree, ident, .none); // identifier
1123 try renderToken(r, ident, .none); // identifier
10851124 const pipe = blk: {
10861125 if (token_tags[ident + 1] == .comma) {
1087 try renderToken(ais, tree, ident + 1, .space); // ,
1088 try renderToken(ais, tree, ident + 2, .none); // index
1126 try renderToken(r, ident + 1, .space); // ,
1127 try renderToken(r, ident + 2, .none); // index
10891128 break :blk ident + 3;
10901129 } else {
10911130 break :blk ident + 1;
......@@ -1095,11 +1134,11 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While,
10951134 }
10961135
10971136 if (while_node.ast.cont_expr != 0) {
1098 try renderToken(ais, tree, last_prefix_token, .space);
1137 try renderToken(r, last_prefix_token, .space);
10991138 const lparen = tree.firstToken(while_node.ast.cont_expr) - 1;
1100 try renderToken(ais, tree, lparen - 1, .space); // :
1101 try renderToken(ais, tree, lparen, .none); // lparen
1102 try renderExpression(gpa, ais, tree, while_node.ast.cont_expr, .none);
1139 try renderToken(r, lparen - 1, .space); // :
1140 try renderToken(r, lparen, .none); // lparen
1141 try renderExpression(r, while_node.ast.cont_expr, .none);
11031142 last_prefix_token = tree.lastToken(while_node.ast.cont_expr) + 1; // rparen
11041143 }
11051144
......@@ -1108,27 +1147,27 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While,
11081147 !tree.tokensOnSameLine(last_prefix_token, tree.firstToken(while_node.ast.then_expr));
11091148 if (indent_then_expr or (then_expr_is_block and ais.isLineOverIndented())) {
11101149 ais.pushIndentNextLine();
1111 try renderToken(ais, tree, last_prefix_token, .newline);
1150 try renderToken(r, last_prefix_token, .newline);
11121151 ais.popIndent();
11131152 } else {
1114 try renderToken(ais, tree, last_prefix_token, .space);
1153 try renderToken(r, last_prefix_token, .space);
11151154 }
11161155
11171156 if (while_node.ast.else_expr != 0) {
11181157 if (indent_then_expr) {
11191158 ais.pushIndent();
1120 try renderExpression(gpa, ais, tree, while_node.ast.then_expr, .newline);
1159 try renderExpression(r, while_node.ast.then_expr, .newline);
11211160 ais.popIndent();
11221161 } else {
1123 try renderExpression(gpa, ais, tree, while_node.ast.then_expr, .space);
1162 try renderExpression(r, while_node.ast.then_expr, .space);
11241163 }
11251164
11261165 var last_else_token = while_node.else_token;
11271166
11281167 if (while_node.error_token) |error_token| {
1129 try renderToken(ais, tree, while_node.else_token, .space); // else
1130 try renderToken(ais, tree, error_token - 1, .none); // |
1131 try renderToken(ais, tree, error_token, .none); // identifier
1168 try renderToken(r, while_node.else_token, .space); // else
1169 try renderToken(r, error_token - 1, .none); // |
1170 try renderToken(r, error_token, .none); // identifier
11321171 last_else_token = error_token + 1; // |
11331172 }
11341173
......@@ -1137,111 +1176,107 @@ fn renderWhile(gpa: Allocator, ais: *Ais, tree: Ast, while_node: Ast.full.While,
11371176 !nodeIsIfForWhileSwitch(node_tags[while_node.ast.else_expr]);
11381177 if (indent_else_expr) {
11391178 ais.pushIndentNextLine();
1140 try renderToken(ais, tree, last_else_token, .newline);
1179 try renderToken(r, last_else_token, .newline);
11411180 ais.popIndent();
1142 try renderExpressionIndented(gpa, ais, tree, while_node.ast.else_expr, space);
1181 try renderExpressionIndented(r, while_node.ast.else_expr, space);
11431182 } else {
1144 try renderToken(ais, tree, last_else_token, .space);
1145 try renderExpression(gpa, ais, tree, while_node.ast.else_expr, space);
1183 try renderToken(r, last_else_token, .space);
1184 try renderExpression(r, while_node.ast.else_expr, space);
11461185 }
11471186 } else {
11481187 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);
11501189 } else {
1151 try renderExpression(gpa, ais, tree, while_node.ast.then_expr, space);
1190 try renderExpression(r, while_node.ast.then_expr, space);
11521191 }
11531192 }
11541193}
11551194
1156fn renderContainerField(
1157 gpa: Allocator,
1158 ais: *Ais,
1159 tree: Ast,
1160 field: Ast.full.ContainerField,
1161 space: Space,
1162) Error!void {
1195fn renderContainerField(r: Render, field: Ast.full.ContainerField, space: Space) Error!void {
1196 const tree = r.tree;
1197 const ais = r.ais;
11631198 if (field.comptime_token) |t| {
1164 try renderToken(ais, tree, t, .space); // comptime
1199 try renderToken(r, t, .space); // comptime
11651200 }
11661201 if (field.ast.type_expr == 0 and field.ast.value_expr == 0) {
1167 return renderTokenComma(ais, tree, field.ast.name_token, space); // name
1202 return renderTokenComma(r, field.ast.name_token, space); // name
11681203 }
11691204 if (field.ast.type_expr != 0 and field.ast.value_expr == 0) {
1170 try renderToken(ais, tree, field.ast.name_token, .none); // name
1171 try renderToken(ais, tree, field.ast.name_token + 1, .space); // :
1205 try renderToken(r, field.ast.name_token, .none); // name
1206 try renderToken(r, field.ast.name_token + 1, .space); // :
11721207
11731208 if (field.ast.align_expr != 0) {
1174 try renderExpression(gpa, ais, tree, field.ast.type_expr, .space); // type
1209 try renderExpression(r, field.ast.type_expr, .space); // type
11751210 const align_token = tree.firstToken(field.ast.align_expr) - 2;
1176 try renderToken(ais, tree, align_token, .none); // align
1177 try renderToken(ais, tree, align_token + 1, .none); // (
1178 try renderExpression(gpa, ais, tree, field.ast.align_expr, .none); // alignment
1211 try renderToken(r, align_token, .none); // align
1212 try renderToken(r, align_token + 1, .none); // (
1213 try renderExpression(r, field.ast.align_expr, .none); // alignment
11791214 const rparen = tree.lastToken(field.ast.align_expr) + 1;
1180 return renderTokenComma(ais, tree, rparen, space); // )
1215 return renderTokenComma(r, rparen, space); // )
11811216 } else {
1182 return renderExpressionComma(gpa, ais, tree, field.ast.type_expr, space); // type
1217 return renderExpressionComma(r, field.ast.type_expr, space); // type
11831218 }
11841219 }
11851220 if (field.ast.type_expr == 0 and field.ast.value_expr != 0) {
1186 try renderToken(ais, tree, field.ast.name_token, .space); // name
1187 try renderToken(ais, tree, field.ast.name_token + 1, .space); // =
1188 return renderExpressionComma(gpa, ais, tree, field.ast.value_expr, space); // value
1221 try renderToken(r, field.ast.name_token, .space); // name
1222 try renderToken(r, field.ast.name_token + 1, .space); // =
1223 return renderExpressionComma(r, field.ast.value_expr, space); // value
11891224 }
11901225
1191 try renderToken(ais, tree, field.ast.name_token, .none); // name
1192 try renderToken(ais, tree, field.ast.name_token + 1, .space); // :
1193 try renderExpression(gpa, ais, tree, field.ast.type_expr, .space); // type
1226 try renderToken(r, field.ast.name_token, .none); // name
1227 try renderToken(r, field.ast.name_token + 1, .space); // :
1228 try renderExpression(r, field.ast.type_expr, .space); // type
11941229
11951230 if (field.ast.align_expr != 0) {
11961231 const lparen_token = tree.firstToken(field.ast.align_expr) - 1;
11971232 const align_kw = lparen_token - 1;
11981233 const rparen_token = tree.lastToken(field.ast.align_expr) + 1;
1199 try renderToken(ais, tree, align_kw, .none); // align
1200 try renderToken(ais, tree, lparen_token, .none); // (
1201 try renderExpression(gpa, ais, tree, field.ast.align_expr, .none); // alignment
1202 try renderToken(ais, tree, rparen_token, .space); // )
1234 try renderToken(r, align_kw, .none); // align
1235 try renderToken(r, lparen_token, .none); // (
1236 try renderExpression(r, field.ast.align_expr, .none); // alignment
1237 try renderToken(r, rparen_token, .space); // )
12031238 }
12041239 const eq_token = tree.firstToken(field.ast.value_expr) - 1;
12051240 const eq_space: Space = if (tree.tokensOnSameLine(eq_token, eq_token + 1)) .space else .newline;
12061241 {
12071242 ais.pushIndent();
1208 try renderToken(ais, tree, eq_token, eq_space); // =
1243 try renderToken(r, eq_token, eq_space); // =
12091244 ais.popIndent();
12101245 }
12111246
12121247 if (eq_space == .space)
1213 return renderExpressionComma(gpa, ais, tree, field.ast.value_expr, space); // value
1248 return renderExpressionComma(r, field.ast.value_expr, space); // value
12141249
12151250 const token_tags = tree.tokens.items(.tag);
12161251 const maybe_comma = tree.lastToken(field.ast.value_expr) + 1;
12171252
12181253 if (token_tags[maybe_comma] == .comma) {
12191254 ais.pushIndent();
1220 try renderExpression(gpa, ais, tree, field.ast.value_expr, .none); // value
1255 try renderExpression(r, field.ast.value_expr, .none); // value
12211256 ais.popIndent();
1222 try renderToken(ais, tree, maybe_comma, .newline);
1257 try renderToken(r, maybe_comma, .newline);
12231258 } else {
12241259 ais.pushIndent();
1225 try renderExpression(gpa, ais, tree, field.ast.value_expr, space); // value
1260 try renderExpression(r, field.ast.value_expr, space); // value
12261261 ais.popIndent();
12271262 }
12281263}
12291264
12301265fn renderBuiltinCall(
1231 gpa: Allocator,
1232 ais: *Ais,
1233 tree: Ast,
1266 r: Render,
12341267 builtin_token: Ast.TokenIndex,
12351268 params: []const Ast.Node.Index,
12361269 space: Space,
12371270) Error!void {
1271 const tree = r.tree;
1272 const ais = r.ais;
12381273 const token_tags = tree.tokens.items(.tag);
12391274
1240 try renderToken(ais, tree, builtin_token, .none); // @name
1275 try renderToken(r, builtin_token, .none); // @name
12411276
12421277 if (params.len == 0) {
1243 try renderToken(ais, tree, builtin_token + 1, .none); // (
1244 return renderToken(ais, tree, builtin_token + 2, space); // )
1278 try renderToken(r, builtin_token + 1, .none); // (
1279 return renderToken(r, builtin_token + 2, space); // )
12451280 }
12461281
12471282 const last_param = params[params.len - 1];
......@@ -1249,7 +1284,7 @@ fn renderBuiltinCall(
12491284
12501285 if (token_tags[after_last_param_token] != .comma) {
12511286 // 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
12541289 for (params) |param_node, i| {
12551290 const first_param_token = tree.firstToken(param_node);
......@@ -1258,39 +1293,41 @@ fn renderBuiltinCall(
12581293 {
12591294 ais.pushIndentOneShot();
12601295 }
1261 try renderExpression(gpa, ais, tree, param_node, .none);
1296 try renderExpression(r, param_node, .none);
12621297
12631298 if (i + 1 < params.len) {
12641299 const comma_token = tree.lastToken(param_node) + 1;
1265 try renderToken(ais, tree, comma_token, .space); // ,
1300 try renderToken(r, comma_token, .space); // ,
12661301 }
12671302 }
1268 return renderToken(ais, tree, after_last_param_token, space); // )
1303 return renderToken(r, after_last_param_token, space); // )
12691304 } else {
12701305 // Render one param per line.
12711306 ais.pushIndent();
1272 try renderToken(ais, tree, builtin_token + 1, Space.newline); // (
1307 try renderToken(r, builtin_token + 1, Space.newline); // (
12731308
12741309 for (params) |param_node| {
1275 try renderExpression(gpa, ais, tree, param_node, .comma);
1310 try renderExpression(r, param_node, .comma);
12761311 }
12771312 ais.popIndent();
12781313
1279 return renderToken(ais, tree, after_last_param_token + 1, space); // )
1314 return renderToken(r, after_last_param_token + 1, space); // )
12801315 }
12811316}
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;
12841321 const token_tags = tree.tokens.items(.tag);
12851322 const token_starts = tree.tokens.items(.start);
12861323
12871324 const after_fn_token = fn_proto.ast.fn_token + 1;
12881325 const lparen = if (token_tags[after_fn_token] == .identifier) blk: {
1289 try renderToken(ais, tree, fn_proto.ast.fn_token, .space); // fn
1290 try renderToken(ais, tree, after_fn_token, .none); // name
1326 try renderToken(r, fn_proto.ast.fn_token, .space); // fn
1327 try renderToken(r, after_fn_token, .none); // name
12911328 break :blk after_fn_token + 1;
12921329 } else blk: {
1293 try renderToken(ais, tree, fn_proto.ast.fn_token, .space); // fn
1330 try renderToken(r, fn_proto.ast.fn_token, .space); // fn
12941331 break :blk fn_proto.ast.fn_token + 1;
12951332 };
12961333 assert(token_tags[lparen] == .l_paren);
......@@ -1342,7 +1379,7 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt
13421379 const trailing_comma = token_tags[rparen - 1] == .comma;
13431380 if (!trailing_comma and !hasComment(tree, lparen, rparen)) {
13441381 // Render all on one line, no trailing comma.
1345 try renderToken(ais, tree, lparen, .none); // (
1382 try renderToken(r, lparen, .none); // (
13461383
13471384 var param_i: usize = 0;
13481385 var last_param_token = lparen;
......@@ -1350,25 +1387,25 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt
13501387 last_param_token += 1;
13511388 switch (token_tags[last_param_token]) {
13521389 .doc_comment => {
1353 try renderToken(ais, tree, last_param_token, .newline);
1390 try renderToken(r, last_param_token, .newline);
13541391 continue;
13551392 },
13561393 .ellipsis3 => {
1357 try renderToken(ais, tree, last_param_token, .none); // ...
1394 try renderToken(r, last_param_token, .none); // ...
13581395 break;
13591396 },
13601397 .keyword_noalias, .keyword_comptime => {
1361 try renderToken(ais, tree, last_param_token, .space);
1398 try renderToken(r, last_param_token, .space);
13621399 last_param_token += 1;
13631400 },
13641401 .identifier => {},
13651402 .keyword_anytype => {
1366 try renderToken(ais, tree, last_param_token, .none); // anytype
1403 try renderToken(r, last_param_token, .none); // anytype
13671404 continue;
13681405 },
13691406 .r_paren => break,
13701407 .comma => {
1371 try renderToken(ais, tree, last_param_token, .space); // ,
1408 try renderToken(r, last_param_token, .space); // ,
13721409 continue;
13731410 },
13741411 else => {}, // Parameter type without a name.
......@@ -1376,24 +1413,24 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt
13761413 if (token_tags[last_param_token] == .identifier and
13771414 token_tags[last_param_token + 1] == .colon)
13781415 {
1379 try renderToken(ais, tree, last_param_token, .none); // name
1416 try renderToken(r, last_param_token, .none); // name
13801417 last_param_token += 1;
1381 try renderToken(ais, tree, last_param_token, .space); // :
1418 try renderToken(r, last_param_token, .space); // :
13821419 last_param_token += 1;
13831420 }
13841421 if (token_tags[last_param_token] == .keyword_anytype) {
1385 try renderToken(ais, tree, last_param_token, .none); // anytype
1422 try renderToken(r, last_param_token, .none); // anytype
13861423 continue;
13871424 }
13881425 const param = fn_proto.ast.params[param_i];
13891426 param_i += 1;
1390 try renderExpression(gpa, ais, tree, param, .none);
1427 try renderExpression(r, param, .none);
13911428 last_param_token = tree.lastToken(param);
13921429 }
13931430 } else {
13941431 // One param per line.
13951432 ais.pushIndent();
1396 try renderToken(ais, tree, lparen, .newline); // (
1433 try renderToken(r, lparen, .newline); // (
13971434
13981435 var param_i: usize = 0;
13991436 var last_param_token = lparen;
......@@ -1401,20 +1438,20 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt
14011438 last_param_token += 1;
14021439 switch (token_tags[last_param_token]) {
14031440 .doc_comment => {
1404 try renderToken(ais, tree, last_param_token, .newline);
1441 try renderToken(r, last_param_token, .newline);
14051442 continue;
14061443 },
14071444 .ellipsis3 => {
1408 try renderToken(ais, tree, last_param_token, .comma); // ...
1445 try renderToken(r, last_param_token, .comma); // ...
14091446 break;
14101447 },
14111448 .keyword_noalias, .keyword_comptime => {
1412 try renderToken(ais, tree, last_param_token, .space);
1449 try renderToken(r, last_param_token, .space);
14131450 last_param_token += 1;
14141451 },
14151452 .identifier => {},
14161453 .keyword_anytype => {
1417 try renderToken(ais, tree, last_param_token, .comma); // anytype
1454 try renderToken(r, last_param_token, .comma); // anytype
14181455 if (token_tags[last_param_token + 1] == .comma)
14191456 last_param_token += 1;
14201457 continue;
......@@ -1425,56 +1462,56 @@ fn renderFnProto(gpa: Allocator, ais: *Ais, tree: Ast, fn_proto: Ast.full.FnProt
14251462 if (token_tags[last_param_token] == .identifier and
14261463 token_tags[last_param_token + 1] == .colon)
14271464 {
1428 try renderToken(ais, tree, last_param_token, .none); // name
1465 try renderToken(r, last_param_token, .none); // name
14291466 last_param_token += 1;
1430 try renderToken(ais, tree, last_param_token, .space); // :
1467 try renderToken(r, last_param_token, .space); // :
14311468 last_param_token += 1;
14321469 }
14331470 if (token_tags[last_param_token] == .keyword_anytype) {
1434 try renderToken(ais, tree, last_param_token, .comma); // anytype
1471 try renderToken(r, last_param_token, .comma); // anytype
14351472 if (token_tags[last_param_token + 1] == .comma)
14361473 last_param_token += 1;
14371474 continue;
14381475 }
14391476 const param = fn_proto.ast.params[param_i];
14401477 param_i += 1;
1441 try renderExpression(gpa, ais, tree, param, .comma);
1478 try renderExpression(r, param, .comma);
14421479 last_param_token = tree.lastToken(param);
14431480 if (token_tags[last_param_token + 1] == .comma) last_param_token += 1;
14441481 }
14451482 ais.popIndent();
14461483 }
14471484
1448 try renderToken(ais, tree, rparen, .space); // )
1485 try renderToken(r, rparen, .space); // )
14491486
14501487 if (fn_proto.ast.align_expr != 0) {
14511488 const align_lparen = tree.firstToken(fn_proto.ast.align_expr) - 1;
14521489 const align_rparen = tree.lastToken(fn_proto.ast.align_expr) + 1;
14531490
1454 try renderToken(ais, tree, align_lparen - 1, .none); // align
1455 try renderToken(ais, tree, align_lparen, .none); // (
1456 try renderExpression(gpa, ais, tree, fn_proto.ast.align_expr, .none);
1457 try renderToken(ais, tree, align_rparen, .space); // )
1491 try renderToken(r, align_lparen - 1, .none); // align
1492 try renderToken(r, align_lparen, .none); // (
1493 try renderExpression(r, fn_proto.ast.align_expr, .none);
1494 try renderToken(r, align_rparen, .space); // )
14581495 }
14591496
14601497 if (fn_proto.ast.addrspace_expr != 0) {
14611498 const align_lparen = tree.firstToken(fn_proto.ast.addrspace_expr) - 1;
14621499 const align_rparen = tree.lastToken(fn_proto.ast.addrspace_expr) + 1;
14631500
1464 try renderToken(ais, tree, align_lparen - 1, .none); // addrspace
1465 try renderToken(ais, tree, align_lparen, .none); // (
1466 try renderExpression(gpa, ais, tree, fn_proto.ast.addrspace_expr, .none);
1467 try renderToken(ais, tree, align_rparen, .space); // )
1501 try renderToken(r, align_lparen - 1, .none); // addrspace
1502 try renderToken(r, align_lparen, .none); // (
1503 try renderExpression(r, fn_proto.ast.addrspace_expr, .none);
1504 try renderToken(r, align_rparen, .space); // )
14681505 }
14691506
14701507 if (fn_proto.ast.section_expr != 0) {
14711508 const section_lparen = tree.firstToken(fn_proto.ast.section_expr) - 1;
14721509 const section_rparen = tree.lastToken(fn_proto.ast.section_expr) + 1;
14731510
1474 try renderToken(ais, tree, section_lparen - 1, .none); // section
1475 try renderToken(ais, tree, section_lparen, .none); // (
1476 try renderExpression(gpa, ais, tree, fn_proto.ast.section_expr, .none);
1477 try renderToken(ais, tree, section_rparen, .space); // )
1511 try renderToken(r, section_lparen - 1, .none); // section
1512 try renderToken(r, section_lparen, .none); // (
1513 try renderExpression(r, fn_proto.ast.section_expr, .none);
1514 try renderToken(r, section_rparen, .space); // )
14781515 }
14791516
14801517 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
14831520 const callconv_lparen = tree.firstToken(fn_proto.ast.callconv_expr) - 1;
14841521 const callconv_rparen = tree.lastToken(fn_proto.ast.callconv_expr) + 1;
14851522
1486 try renderToken(ais, tree, callconv_lparen - 1, .none); // callconv
1487 try renderToken(ais, tree, callconv_lparen, .none); // (
1488 try renderExpression(gpa, ais, tree, fn_proto.ast.callconv_expr, .none);
1489 try renderToken(ais, tree, callconv_rparen, .space); // )
1523 try renderToken(r, callconv_lparen - 1, .none); // callconv
1524 try renderToken(r, callconv_lparen, .none); // (
1525 try renderExpression(r, fn_proto.ast.callconv_expr, .none);
1526 try renderToken(r, callconv_rparen, .space); // )
14901527 }
14911528
14921529 if (token_tags[maybe_bang] == .bang) {
1493 try renderToken(ais, tree, maybe_bang, .none); // !
1530 try renderToken(r, maybe_bang, .none); // !
14941531 }
1495 return renderExpression(gpa, ais, tree, fn_proto.ast.return_type, space);
1532 return renderExpression(r, fn_proto.ast.return_type, space);
14961533}
14971534
14981535fn renderSwitchCase(
1499 gpa: Allocator,
1500 ais: *Ais,
1501 tree: Ast,
1536 r: Render,
15021537 switch_case: Ast.full.SwitchCase,
15031538 space: Space,
15041539) Error!void {
1540 const tree = r.tree;
15051541 const node_tags = tree.nodes.items(.tag);
15061542 const token_tags = tree.tokens.items(.tag);
15071543 const trailing_comma = token_tags[switch_case.ast.arrow_token - 1] == .comma;
......@@ -1512,17 +1548,17 @@ fn renderSwitchCase(
15121548
15131549 // Render everything before the arrow
15141550 if (switch_case.ast.values.len == 0) {
1515 try renderToken(ais, tree, switch_case.ast.arrow_token - 1, .space); // else keyword
1551 try renderToken(r, switch_case.ast.arrow_token - 1, .space); // else keyword
15161552 } else if (switch_case.ast.values.len == 1 and !has_comment_before_arrow) {
15171553 // 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);
15191555 } else if (trailing_comma or has_comment_before_arrow) {
15201556 // 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);
15221558 } else {
15231559 // Render on one line
15241560 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);
15261562 }
15271563 }
15281564
......@@ -1533,31 +1569,31 @@ fn renderSwitchCase(
15331569 else
15341570 Space.space;
15351571 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
15381574 if (switch_case.payload_token) |payload_token| {
1539 try renderToken(ais, tree, payload_token - 1, .none); // pipe
1575 try renderToken(r, payload_token - 1, .none); // pipe
15401576 if (token_tags[payload_token] == .asterisk) {
1541 try renderToken(ais, tree, payload_token, .none); // asterisk
1542 try renderToken(ais, tree, payload_token + 1, .none); // identifier
1543 try renderToken(ais, tree, payload_token + 2, pre_target_space); // pipe
1577 try renderToken(r, payload_token, .none); // asterisk
1578 try renderToken(r, payload_token + 1, .none); // identifier
1579 try renderToken(r, payload_token + 2, pre_target_space); // pipe
15441580 } else {
1545 try renderToken(ais, tree, payload_token, .none); // identifier
1546 try renderToken(ais, tree, payload_token + 1, pre_target_space); // pipe
1581 try renderToken(r, payload_token, .none); // identifier
1582 try renderToken(r, payload_token + 1, pre_target_space); // pipe
15471583 }
15481584 }
15491585
1550 try renderExpression(gpa, ais, tree, switch_case.ast.target_expr, space);
1586 try renderExpression(r, switch_case.ast.target_expr, space);
15511587}
15521588
15531589fn renderBlock(
1554 gpa: Allocator,
1555 ais: *Ais,
1556 tree: Ast,
1590 r: Render,
15571591 block_node: Ast.Node.Index,
15581592 statements: []const Ast.Node.Index,
15591593 space: Space,
15601594) Error!void {
1595 const tree = r.tree;
1596 const ais = r.ais;
15611597 const token_tags = tree.tokens.items(.tag);
15621598 const node_tags = tree.nodes.items(.tag);
15631599 const lbrace = tree.nodes.items(.main_token)[block_node];
......@@ -1565,50 +1601,50 @@ fn renderBlock(
15651601 if (token_tags[lbrace - 1] == .colon and
15661602 token_tags[lbrace - 2] == .identifier)
15671603 {
1568 try renderToken(ais, tree, lbrace - 2, .none);
1569 try renderToken(ais, tree, lbrace - 1, .space);
1604 try renderToken(r, lbrace - 2, .none);
1605 try renderToken(r, lbrace - 1, .space);
15701606 }
15711607
15721608 ais.pushIndentNextLine();
15731609 if (statements.len == 0) {
1574 try renderToken(ais, tree, lbrace, .none);
1610 try renderToken(r, lbrace, .none);
15751611 } else {
1576 try renderToken(ais, tree, lbrace, .newline);
1612 try renderToken(r, lbrace, .newline);
15771613 for (statements) |stmt, i| {
1578 if (i != 0) try renderExtraNewline(ais, tree, stmt);
1614 if (i != 0) try renderExtraNewline(r, stmt);
15791615 switch (node_tags[stmt]) {
1580 .global_var_decl => try renderVarDecl(gpa, ais, tree, tree.globalVarDecl(stmt)),
1581 .local_var_decl => try renderVarDecl(gpa, ais, tree, tree.localVarDecl(stmt)),
1582 .simple_var_decl => try renderVarDecl(gpa, ais, tree, tree.simpleVarDecl(stmt)),
1583 .aligned_var_decl => try renderVarDecl(gpa, ais, tree, tree.alignedVarDecl(stmt)),
1584 else => try renderExpression(gpa, ais, tree, stmt, .semicolon),
1616 .global_var_decl => try renderVarDecl(r, tree.globalVarDecl(stmt)),
1617 .local_var_decl => try renderVarDecl(r, tree.localVarDecl(stmt)),
1618 .simple_var_decl => try renderVarDecl(r, tree.simpleVarDecl(stmt)),
1619 .aligned_var_decl => try renderVarDecl(r, tree.alignedVarDecl(stmt)),
1620 else => try renderExpression(r, stmt, .semicolon),
15851621 }
15861622 }
15871623 }
15881624 ais.popIndent();
15891625
1590 try renderToken(ais, tree, tree.lastToken(block_node), space); // rbrace
1626 try renderToken(r, tree.lastToken(block_node), space); // rbrace
15911627}
15921628
15931629fn renderStructInit(
1594 gpa: Allocator,
1595 ais: *Ais,
1596 tree: Ast,
1630 r: Render,
15971631 struct_node: Ast.Node.Index,
15981632 struct_init: Ast.full.StructInit,
15991633 space: Space,
16001634) Error!void {
1635 const tree = r.tree;
1636 const ais = r.ais;
16011637 const token_tags = tree.tokens.items(.tag);
16021638 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); // .
16041640 } else {
1605 try renderExpression(gpa, ais, tree, struct_init.ast.type_expr, .none); // T
1641 try renderExpression(r, struct_init.ast.type_expr, .none); // T
16061642 }
16071643 if (struct_init.ast.fields.len == 0) {
16081644 ais.pushIndentNextLine();
1609 try renderToken(ais, tree, struct_init.ast.lbrace, .none); // lbrace
1645 try renderToken(r, struct_init.ast.lbrace, .none); // lbrace
16101646 ais.popIndent();
1611 return renderToken(ais, tree, struct_init.ast.lbrace + 1, space); // rbrace
1647 return renderToken(r, struct_init.ast.lbrace + 1, space); // rbrace
16121648 }
16131649
16141650 const rbrace = tree.lastToken(struct_node);
......@@ -1616,59 +1652,60 @@ fn renderStructInit(
16161652 if (trailing_comma or hasComment(tree, struct_init.ast.lbrace, rbrace)) {
16171653 // Render one field init per line.
16181654 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); // .
1622 try renderToken(ais, tree, struct_init.ast.lbrace + 2, .space); // name
1623 try renderToken(ais, tree, struct_init.ast.lbrace + 3, .space); // =
1624 try renderExpression(gpa, ais, tree, struct_init.ast.fields[0], .comma);
1657 try renderToken(r, struct_init.ast.lbrace + 1, .none); // .
1658 try renderToken(r, struct_init.ast.lbrace + 2, .space); // name
1659 try renderToken(r, struct_init.ast.lbrace + 3, .space); // =
1660 try renderExpression(r, struct_init.ast.fields[0], .comma);
16251661
16261662 for (struct_init.ast.fields[1..]) |field_init| {
16271663 const init_token = tree.firstToken(field_init);
1628 try renderExtraNewlineToken(ais, tree, init_token - 3);
1629 try renderToken(ais, tree, init_token - 3, .none); // .
1630 try renderToken(ais, tree, init_token - 2, .space); // name
1631 try renderToken(ais, tree, init_token - 1, .space); // =
1632 try renderExpression(gpa, ais, tree, field_init, .comma);
1664 try renderExtraNewlineToken(r, init_token - 3);
1665 try renderToken(r, init_token - 3, .none); // .
1666 try renderToken(r, init_token - 2, .space); // name
1667 try renderToken(r, init_token - 1, .space); // =
1668 try renderExpression(r, field_init, .comma);
16331669 }
16341670
16351671 ais.popIndent();
16361672 } else {
16371673 // 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
16401676 for (struct_init.ast.fields) |field_init| {
16411677 const init_token = tree.firstToken(field_init);
1642 try renderToken(ais, tree, init_token - 3, .none); // .
1643 try renderToken(ais, tree, init_token - 2, .space); // name
1644 try renderToken(ais, tree, init_token - 1, .space); // =
1645 try renderExpression(gpa, ais, tree, field_init, .comma_space);
1678 try renderToken(r, init_token - 3, .none); // .
1679 try renderToken(r, init_token - 2, .space); // name
1680 try renderToken(r, init_token - 1, .space); // =
1681 try renderExpression(r, field_init, .comma_space);
16461682 }
16471683 }
16481684
1649 return renderToken(ais, tree, rbrace, space);
1685 return renderToken(r, rbrace, space);
16501686}
16511687
16521688fn renderArrayInit(
1653 gpa: Allocator,
1654 ais: *Ais,
1655 tree: Ast,
1689 r: Render,
16561690 array_init: Ast.full.ArrayInit,
16571691 space: Space,
16581692) Error!void {
1693 const tree = r.tree;
1694 const ais = r.ais;
1695 const gpa = r.gpa;
16591696 const token_tags = tree.tokens.items(.tag);
16601697
16611698 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); // .
16631700 } else {
1664 try renderExpression(gpa, ais, tree, array_init.ast.type_expr, .none); // T
1701 try renderExpression(r, array_init.ast.type_expr, .none); // T
16651702 }
16661703
16671704 if (array_init.ast.elements.len == 0) {
16681705 ais.pushIndentNextLine();
1669 try renderToken(ais, tree, array_init.ast.lbrace, .none); // lbrace
1706 try renderToken(r, array_init.ast.lbrace, .none); // lbrace
16701707 ais.popIndent();
1671 return renderToken(ais, tree, array_init.ast.lbrace + 1, space); // rbrace
1708 return renderToken(r, array_init.ast.lbrace + 1, space); // rbrace
16721709 }
16731710
16741711 const last_elem = array_init.ast.elements[array_init.ast.elements.len - 1];
......@@ -1683,9 +1720,9 @@ fn renderArrayInit(
16831720 if (token_tags[first_token] != .multiline_string_literal_line and
16841721 !anythingBetween(tree, last_elem_token, rbrace))
16851722 {
1686 try renderToken(ais, tree, array_init.ast.lbrace, .none);
1687 try renderExpression(gpa, ais, tree, only_elem, .none);
1688 return renderToken(ais, tree, rbrace, space);
1723 try renderToken(r, array_init.ast.lbrace, .none);
1724 try renderExpression(r, only_elem, .none);
1725 return renderToken(r, rbrace, space);
16891726 }
16901727 }
16911728
......@@ -1696,19 +1733,19 @@ fn renderArrayInit(
16961733 // Render all on one line, no trailing comma.
16971734 if (array_init.ast.elements.len == 1) {
16981735 // If there is only one element, we don't use spaces
1699 try renderToken(ais, tree, array_init.ast.lbrace, .none);
1700 try renderExpression(gpa, ais, tree, array_init.ast.elements[0], .none);
1736 try renderToken(r, array_init.ast.lbrace, .none);
1737 try renderExpression(r, array_init.ast.elements[0], .none);
17011738 } else {
1702 try renderToken(ais, tree, array_init.ast.lbrace, .space);
1739 try renderToken(r, array_init.ast.lbrace, .space);
17031740 for (array_init.ast.elements) |elem| {
1704 try renderExpression(gpa, ais, tree, elem, .comma_space);
1741 try renderExpression(r, elem, .comma_space);
17051742 }
17061743 }
1707 return renderToken(ais, tree, last_elem_token + 1, space); // rbrace
1744 return renderToken(r, last_elem_token + 1, space); // rbrace
17081745 }
17091746
17101747 ais.pushIndentNextLine();
1711 try renderToken(ais, tree, array_init.ast.lbrace, .newline);
1748 try renderToken(r, array_init.ast.lbrace, .newline);
17121749
17131750 var expr_index: usize = 0;
17141751 while (true) {
......@@ -1764,6 +1801,12 @@ fn renderArrayInit(
17641801 .indent_delta = indent_delta,
17651802 .underlying_writer = sub_expr_buffer.writer(),
17661803 };
1804 var sub_render: Render = .{
1805 .gpa = r.gpa,
1806 .ais = &auto_indenting_stream,
1807 .tree = r.tree,
1808 .fixups = r.fixups,
1809 };
17671810
17681811 // Calculate size of columns in current section
17691812 var column_counter: usize = 0;
......@@ -1774,7 +1817,7 @@ fn renderArrayInit(
17741817 sub_expr_buffer_starts[i] = start;
17751818
17761819 if (i + 1 < section_exprs.len) {
1777 try renderExpression(gpa, &auto_indenting_stream, tree, expr, .none);
1820 try renderExpression(sub_render, expr, .none);
17781821 const width = sub_expr_buffer.items.len - start;
17791822 const this_contains_newline = mem.indexOfScalar(u8, sub_expr_buffer.items[start..], '\n') != null;
17801823 contains_newline = contains_newline or this_contains_newline;
......@@ -1794,7 +1837,7 @@ fn renderArrayInit(
17941837 column_counter = 0;
17951838 }
17961839 } else {
1797 try renderExpression(gpa, &auto_indenting_stream, tree, expr, .comma);
1840 try renderExpression(sub_render, expr, .comma);
17981841 const width = sub_expr_buffer.items.len - start - 2;
17991842 const this_contains_newline = mem.indexOfScalar(u8, sub_expr_buffer.items[start .. sub_expr_buffer.items.len - 1], '\n') != null;
18001843 contains_newline = contains_newline or this_contains_newline;
......@@ -1839,7 +1882,7 @@ fn renderArrayInit(
18391882 if (column_counter != row_size - 1) {
18401883 if (!expr_newlines[i] and !expr_newlines[i + 1]) {
18411884 // Neither the current or next expression is multiline
1842 try renderToken(ais, tree, comma, .space); // ,
1885 try renderToken(r, comma, .space); // ,
18431886 assert(column_widths[column_counter % row_size] >= expr_widths[i]);
18441887 const padding = column_widths[column_counter % row_size] - expr_widths[i];
18451888 try ais.writer().writeByteNTimes(' ', padding);
......@@ -1850,13 +1893,13 @@ fn renderArrayInit(
18501893 }
18511894
18521895 if (single_line and row_size != 1) {
1853 try renderToken(ais, tree, comma, .space); // ,
1896 try renderToken(r, comma, .space); // ,
18541897 continue;
18551898 }
18561899
18571900 column_counter = 0;
1858 try renderToken(ais, tree, comma, .newline); // ,
1859 try renderExtraNewline(ais, tree, next_expr);
1901 try renderToken(r, comma, .newline); // ,
1902 try renderExtraNewline(r, next_expr);
18601903 }
18611904 }
18621905
......@@ -1865,49 +1908,49 @@ fn renderArrayInit(
18651908 }
18661909
18671910 ais.popIndent();
1868 return renderToken(ais, tree, rbrace, space); // rbrace
1911 return renderToken(r, rbrace, space); // rbrace
18691912}
18701913
18711914fn renderContainerDecl(
1872 gpa: Allocator,
1873 ais: *Ais,
1874 tree: Ast,
1915 r: Render,
18751916 container_decl_node: Ast.Node.Index,
18761917 container_decl: Ast.full.ContainerDecl,
18771918 space: Space,
18781919) Error!void {
1920 const tree = r.tree;
1921 const ais = r.ais;
18791922 const token_tags = tree.tokens.items(.tag);
18801923 const node_tags = tree.nodes.items(.tag);
18811924
18821925 if (container_decl.layout_token) |layout_token| {
1883 try renderToken(ais, tree, layout_token, .space);
1926 try renderToken(r, layout_token, .space);
18841927 }
18851928
18861929 var lbrace: Ast.TokenIndex = undefined;
18871930 if (container_decl.ast.enum_token) |enum_token| {
1888 try renderToken(ais, tree, container_decl.ast.main_token, .none); // union
1889 try renderToken(ais, tree, enum_token - 1, .none); // lparen
1890 try renderToken(ais, tree, enum_token, .none); // enum
1931 try renderToken(r, container_decl.ast.main_token, .none); // union
1932 try renderToken(r, enum_token - 1, .none); // lparen
1933 try renderToken(r, enum_token, .none); // enum
18911934 if (container_decl.ast.arg != 0) {
1892 try renderToken(ais, tree, enum_token + 1, .none); // lparen
1893 try renderExpression(gpa, ais, tree, container_decl.ast.arg, .none);
1935 try renderToken(r, enum_token + 1, .none); // lparen
1936 try renderExpression(r, container_decl.ast.arg, .none);
18941937 const rparen = tree.lastToken(container_decl.ast.arg) + 1;
1895 try renderToken(ais, tree, rparen, .none); // rparen
1896 try renderToken(ais, tree, rparen + 1, .space); // rparen
1938 try renderToken(r, rparen, .none); // rparen
1939 try renderToken(r, rparen + 1, .space); // rparen
18971940 lbrace = rparen + 2;
18981941 } else {
1899 try renderToken(ais, tree, enum_token + 1, .space); // rparen
1942 try renderToken(r, enum_token + 1, .space); // rparen
19001943 lbrace = enum_token + 2;
19011944 }
19021945 } else if (container_decl.ast.arg != 0) {
1903 try renderToken(ais, tree, container_decl.ast.main_token, .none); // union
1904 try renderToken(ais, tree, container_decl.ast.main_token + 1, .none); // lparen
1905 try renderExpression(gpa, ais, tree, container_decl.ast.arg, .none);
1946 try renderToken(r, container_decl.ast.main_token, .none); // union
1947 try renderToken(r, container_decl.ast.main_token + 1, .none); // lparen
1948 try renderExpression(r, container_decl.ast.arg, .none);
19061949 const rparen = tree.lastToken(container_decl.ast.arg) + 1;
1907 try renderToken(ais, tree, rparen, .space); // rparen
1950 try renderToken(r, rparen, .space); // rparen
19081951 lbrace = rparen + 1;
19091952 } else {
1910 try renderToken(ais, tree, container_decl.ast.main_token, .space); // union
1953 try renderToken(r, container_decl.ast.main_token, .space); // union
19111954 lbrace = container_decl.ast.main_token + 1;
19121955 }
19131956
......@@ -1915,13 +1958,13 @@ fn renderContainerDecl(
19151958 if (container_decl.ast.members.len == 0) {
19161959 ais.pushIndentNextLine();
19171960 if (token_tags[lbrace + 1] == .container_doc_comment) {
1918 try renderToken(ais, tree, lbrace, .newline); // lbrace
1919 try renderContainerDocComments(ais, tree, lbrace + 1);
1961 try renderToken(r, lbrace, .newline); // lbrace
1962 try renderContainerDocComments(r, lbrace + 1);
19201963 } else {
1921 try renderToken(ais, tree, lbrace, .none); // lbrace
1964 try renderToken(r, lbrace, .none); // lbrace
19221965 }
19231966 ais.popIndent();
1924 return renderToken(ais, tree, rbrace, space); // rbrace
1967 return renderToken(r, rbrace, space); // rbrace
19251968 }
19261969
19271970 const src_has_trailing_comma = token_tags[rbrace - 1] == .comma;
......@@ -1947,52 +1990,52 @@ fn renderContainerDecl(
19471990 }
19481991
19491992 // Print all the declarations on the same line.
1950 try renderToken(ais, tree, lbrace, .space); // lbrace
1993 try renderToken(r, lbrace, .space); // lbrace
19511994 for (container_decl.ast.members) |member| {
1952 try renderMember(gpa, ais, tree, member, .space);
1995 try renderMember(r, member, .space);
19531996 }
1954 return renderToken(ais, tree, rbrace, space); // rbrace
1997 return renderToken(r, rbrace, space); // rbrace
19551998 }
19561999
19572000 // One member per line.
19582001 ais.pushIndentNextLine();
1959 try renderToken(ais, tree, lbrace, .newline); // lbrace
2002 try renderToken(r, lbrace, .newline); // lbrace
19602003 if (token_tags[lbrace + 1] == .container_doc_comment) {
1961 try renderContainerDocComments(ais, tree, lbrace + 1);
2004 try renderContainerDocComments(r, lbrace + 1);
19622005 }
19632006 for (container_decl.ast.members) |member, i| {
1964 if (i != 0) try renderExtraNewline(ais, tree, member);
2007 if (i != 0) try renderExtraNewline(r, member);
19652008 switch (tree.nodes.items(.tag)[member]) {
19662009 // For container fields, ensure a trailing comma is added if necessary.
19672010 .container_field_init,
19682011 .container_field_align,
19692012 .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),
19732016 }
19742017 }
19752018 ais.popIndent();
19762019
1977 return renderToken(ais, tree, rbrace, space); // rbrace
2020 return renderToken(r, rbrace, space); // rbrace
19782021}
19792022
19802023fn renderAsm(
1981 gpa: Allocator,
1982 ais: *Ais,
1983 tree: Ast,
2024 r: Render,
19842025 asm_node: Ast.full.Asm,
19852026 space: Space,
19862027) Error!void {
2028 const tree = r.tree;
2029 const ais = r.ais;
19872030 const token_tags = tree.tokens.items(.tag);
19882031
1989 try renderToken(ais, tree, asm_node.ast.asm_token, .space); // asm
2032 try renderToken(r, asm_node.ast.asm_token, .space); // asm
19902033
19912034 if (asm_node.volatile_token) |volatile_token| {
1992 try renderToken(ais, tree, volatile_token, .space); // volatile
1993 try renderToken(ais, tree, volatile_token + 1, .none); // lparen
2035 try renderToken(r, volatile_token, .space); // volatile
2036 try renderToken(r, volatile_token + 1, .none); // lparen
19942037 } else {
1995 try renderToken(ais, tree, asm_node.ast.asm_token + 1, .none); // lparen
2038 try renderToken(r, asm_node.ast.asm_token + 1, .none); // lparen
19962039 }
19972040
19982041 if (asm_node.ast.items.len == 0) {
......@@ -2000,27 +2043,27 @@ fn renderAsm(
20002043 if (asm_node.first_clobber) |first_clobber| {
20012044 // asm ("foo" ::: "a", "b")
20022045 // asm ("foo" ::: "a", "b",)
2003 try renderExpression(gpa, ais, tree, asm_node.ast.template, .space);
2046 try renderExpression(r, asm_node.ast.template, .space);
20042047 // Render the three colons.
2005 try renderToken(ais, tree, first_clobber - 3, .none);
2006 try renderToken(ais, tree, first_clobber - 2, .none);
2007 try renderToken(ais, tree, first_clobber - 1, .space);
2048 try renderToken(r, first_clobber - 3, .none);
2049 try renderToken(r, first_clobber - 2, .none);
2050 try renderToken(r, first_clobber - 1, .space);
20082051
20092052 var tok_i = first_clobber;
20102053 while (true) : (tok_i += 1) {
2011 try renderToken(ais, tree, tok_i, .none);
2054 try renderToken(r, tok_i, .none);
20122055 tok_i += 1;
20132056 switch (token_tags[tok_i]) {
20142057 .r_paren => {
20152058 ais.popIndent();
2016 return renderToken(ais, tree, tok_i, space);
2059 return renderToken(r, tok_i, space);
20172060 },
20182061 .comma => {
20192062 if (token_tags[tok_i + 1] == .r_paren) {
20202063 ais.popIndent();
2021 return renderToken(ais, tree, tok_i + 1, space);
2064 return renderToken(r, tok_i + 1, space);
20222065 } else {
2023 try renderToken(ais, tree, tok_i, .space);
2066 try renderToken(r, tok_i, .space);
20242067 }
20252068 },
20262069 else => unreachable,
......@@ -2028,40 +2071,40 @@ fn renderAsm(
20282071 }
20292072 } else {
20302073 // asm ("foo")
2031 try renderExpression(gpa, ais, tree, asm_node.ast.template, .none);
2074 try renderExpression(r, asm_node.ast.template, .none);
20322075 ais.popIndent();
2033 return renderToken(ais, tree, asm_node.ast.rparen, space); // rparen
2076 return renderToken(r, asm_node.ast.rparen, space); // rparen
20342077 }
20352078 }
20362079
20372080 ais.pushIndent();
2038 try renderExpression(gpa, ais, tree, asm_node.ast.template, .newline);
2081 try renderExpression(r, asm_node.ast.template, .newline);
20392082 ais.setIndentDelta(asm_indent_delta);
20402083 const colon1 = tree.lastToken(asm_node.ast.template) + 1;
20412084
20422085 const colon2 = if (asm_node.outputs.len == 0) colon2: {
2043 try renderToken(ais, tree, colon1, .newline); // :
2086 try renderToken(r, colon1, .newline); // :
20442087 break :colon2 colon1 + 1;
20452088 } else colon2: {
2046 try renderToken(ais, tree, colon1, .space); // :
2089 try renderToken(r, colon1, .space); // :
20472090
20482091 ais.pushIndent();
20492092 for (asm_node.outputs) |asm_output, i| {
20502093 if (i + 1 < asm_node.outputs.len) {
20512094 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
20542097 const comma = tree.firstToken(next_asm_output) - 1;
2055 try renderToken(ais, tree, comma, .newline); // ,
2056 try renderExtraNewlineToken(ais, tree, tree.firstToken(next_asm_output));
2098 try renderToken(r, comma, .newline); // ,
2099 try renderExtraNewlineToken(r, tree.firstToken(next_asm_output));
20572100 } 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);
20592102 ais.popIndent();
20602103 ais.setIndentDelta(indent_delta);
20612104 ais.popIndent();
2062 return renderToken(ais, tree, asm_node.ast.rparen, space); // rparen
2105 return renderToken(r, asm_node.ast.rparen, space); // rparen
20632106 } else {
2064 try renderAsmOutput(gpa, ais, tree, asm_output, .comma);
2107 try renderAsmOutput(r, asm_output, .comma);
20652108 const comma_or_colon = tree.lastToken(asm_output) + 1;
20662109 ais.popIndent();
20672110 break :colon2 switch (token_tags[comma_or_colon]) {
......@@ -2073,27 +2116,27 @@ fn renderAsm(
20732116 };
20742117
20752118 const colon3 = if (asm_node.inputs.len == 0) colon3: {
2076 try renderToken(ais, tree, colon2, .newline); // :
2119 try renderToken(r, colon2, .newline); // :
20772120 break :colon3 colon2 + 1;
20782121 } else colon3: {
2079 try renderToken(ais, tree, colon2, .space); // :
2122 try renderToken(r, colon2, .space); // :
20802123 ais.pushIndent();
20812124 for (asm_node.inputs) |asm_input, i| {
20822125 if (i + 1 < asm_node.inputs.len) {
20832126 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
20862129 const first_token = tree.firstToken(next_asm_input);
2087 try renderToken(ais, tree, first_token - 1, .newline); // ,
2088 try renderExtraNewlineToken(ais, tree, first_token);
2130 try renderToken(r, first_token - 1, .newline); // ,
2131 try renderExtraNewlineToken(r, first_token);
20892132 } else if (asm_node.first_clobber == null) {
2090 try renderAsmInput(gpa, ais, tree, asm_input, .comma);
2133 try renderAsmInput(r, asm_input, .comma);
20912134 ais.popIndent();
20922135 ais.setIndentDelta(indent_delta);
20932136 ais.popIndent();
2094 return renderToken(ais, tree, asm_node.ast.rparen, space); // rparen
2137 return renderToken(r, asm_node.ast.rparen, space); // rparen
20952138 } else {
2096 try renderAsmInput(gpa, ais, tree, asm_input, .comma);
2139 try renderAsmInput(r, asm_input, .comma);
20972140 const comma_or_colon = tree.lastToken(asm_input) + 1;
20982141 ais.popIndent();
20992142 break :colon3 switch (token_tags[comma_or_colon]) {
......@@ -2105,7 +2148,7 @@ fn renderAsm(
21052148 unreachable;
21062149 };
21072150
2108 try renderToken(ais, tree, colon3, .space); // :
2151 try renderToken(r, colon3, .space); // :
21092152 const first_clobber = asm_node.first_clobber.?;
21102153 var tok_i = first_clobber;
21112154 while (true) {
......@@ -2113,20 +2156,20 @@ fn renderAsm(
21132156 .r_paren => {
21142157 ais.setIndentDelta(indent_delta);
21152158 ais.popIndent();
2116 try renderToken(ais, tree, tok_i, .newline);
2117 return renderToken(ais, tree, tok_i + 1, space);
2159 try renderToken(r, tok_i, .newline);
2160 return renderToken(r, tok_i + 1, space);
21182161 },
21192162 .comma => {
21202163 switch (token_tags[tok_i + 2]) {
21212164 .r_paren => {
21222165 ais.setIndentDelta(indent_delta);
21232166 ais.popIndent();
2124 try renderToken(ais, tree, tok_i, .newline);
2125 return renderToken(ais, tree, tok_i + 2, space);
2167 try renderToken(r, tok_i, .newline);
2168 return renderToken(r, tok_i + 2, space);
21262169 },
21272170 else => {
2128 try renderToken(ais, tree, tok_i, .none);
2129 try renderToken(ais, tree, tok_i + 1, .space);
2171 try renderToken(r, tok_i, .none);
2172 try renderToken(r, tok_i + 1, .space);
21302173 tok_i += 2;
21312174 },
21322175 }
......@@ -2137,36 +2180,36 @@ fn renderAsm(
21372180}
21382181
21392182fn renderCall(
2140 gpa: Allocator,
2141 ais: *Ais,
2142 tree: Ast,
2183 r: Render,
21432184 call: Ast.full.Call,
21442185 space: Space,
21452186) Error!void {
2187 const tree = r.tree;
2188 const ais = r.ais;
21462189 const token_tags = tree.tokens.items(.tag);
21472190
21482191 if (call.async_token) |async_token| {
2149 try renderToken(ais, tree, async_token, .space);
2192 try renderToken(r, async_token, .space);
21502193 }
2151 try renderExpression(gpa, ais, tree, call.ast.fn_expr, .none);
2194 try renderExpression(r, call.ast.fn_expr, .none);
21522195
21532196 const lparen = call.ast.lparen;
21542197 const params = call.ast.params;
21552198 if (params.len == 0) {
21562199 ais.pushIndentNextLine();
2157 try renderToken(ais, tree, lparen, .none);
2200 try renderToken(r, lparen, .none);
21582201 ais.popIndent();
2159 return renderToken(ais, tree, lparen + 1, space); // )
2202 return renderToken(r, lparen + 1, space); // )
21602203 }
21612204
21622205 const last_param = params[params.len - 1];
21632206 const after_last_param_tok = tree.lastToken(last_param) + 1;
21642207 if (token_tags[after_last_param_tok] == .comma) {
21652208 ais.pushIndentNextLine();
2166 try renderToken(ais, tree, lparen, .newline); // (
2209 try renderToken(r, lparen, .newline); // (
21672210 for (params) |param_node, i| {
21682211 if (i + 1 < params.len) {
2169 try renderExpression(gpa, ais, tree, param_node, .none);
2212 try renderExpression(r, param_node, .none);
21702213
21712214 // Unindent the comma for multiline string literals.
21722215 const is_multiline_string =
......@@ -2174,20 +2217,20 @@ fn renderCall(
21742217 if (is_multiline_string) ais.popIndent();
21752218
21762219 const comma = tree.lastToken(param_node) + 1;
2177 try renderToken(ais, tree, comma, .newline); // ,
2220 try renderToken(r, comma, .newline); // ,
21782221
21792222 if (is_multiline_string) ais.pushIndent();
21802223
2181 try renderExtraNewline(ais, tree, params[i + 1]);
2224 try renderExtraNewline(r, params[i + 1]);
21822225 } else {
2183 try renderExpression(gpa, ais, tree, param_node, .comma);
2226 try renderExpression(r, param_node, .comma);
21842227 }
21852228 }
21862229 ais.popIndent();
2187 return renderToken(ais, tree, after_last_param_tok + 1, space); // )
2230 return renderToken(r, after_last_param_tok + 1, space); // )
21882231 }
21892232
2190 try renderToken(ais, tree, lparen, .none); // (
2233 try renderToken(r, lparen, .none); // (
21912234
21922235 for (params) |param_node, i| {
21932236 const first_param_token = tree.firstToken(param_node);
......@@ -2196,23 +2239,25 @@ fn renderCall(
21962239 {
21972240 ais.pushIndentOneShot();
21982241 }
2199 try renderExpression(gpa, ais, tree, param_node, .none);
2242 try renderExpression(r, param_node, .none);
22002243
22012244 if (i + 1 < params.len) {
22022245 const comma = tree.lastToken(param_node) + 1;
22032246 const next_multiline_string =
22042247 token_tags[tree.firstToken(params[i + 1])] == .multiline_string_literal_line;
22052248 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);
22072250 }
22082251 }
22092252
2210 return renderToken(ais, tree, after_last_param_tok, space); // )
2253 return renderToken(r, after_last_param_tok, space); // )
22112254}
22122255
22132256/// Renders the given expression indented, popping the indent before rendering
22142257/// 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;
22162261 const token_starts = tree.tokens.items(.start);
22172262 const token_tags = tree.tokens.items(.tag);
22182263
......@@ -2226,24 +2271,24 @@ fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node
22262271 .semicolon => token_tags[last_token + 1] == .semicolon,
22272272 };
22282273
2229 try renderExpression(gpa, ais, tree, node, if (punctuation) .none else .skip);
2274 try renderExpression(r, node, if (punctuation) .none else .skip);
22302275
22312276 switch (space) {
22322277 .none, .space, .newline, .skip => {},
22332278 .comma => {
22342279 if (token_tags[last_token + 1] == .comma) {
2235 try renderToken(ais, tree, last_token + 1, .skip);
2280 try renderToken(r, last_token + 1, .skip);
22362281 last_token += 1;
22372282 } else {
22382283 try ais.writer().writeByte(',');
22392284 }
22402285 },
22412286 .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);
22432288 last_token += 1;
22442289 },
22452290 .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);
22472292 last_token += 1;
22482293 },
22492294 }
......@@ -2253,7 +2298,7 @@ fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node
22532298 if (space == .skip) return;
22542299
22552300 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
22582303 if (!comment) switch (space) {
22592304 .none => {},
......@@ -2270,27 +2315,29 @@ fn renderExpressionIndented(gpa: Allocator, ais: *Ais, tree: Ast, node: Ast.Node
22702315
22712316/// Render an expression, and the comma that follows it, if it is present in the source.
22722317/// 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;
22742320 const token_tags = tree.tokens.items(.tag);
22752321 const maybe_comma = tree.lastToken(node) + 1;
22762322 if (token_tags[maybe_comma] == .comma and space != .comma) {
2277 try renderExpression(gpa, ais, tree, node, .none);
2278 return renderToken(ais, tree, maybe_comma, space);
2323 try renderExpression(r, node, .none);
2324 return renderToken(r, maybe_comma, space);
22792325 } else {
2280 return renderExpression(gpa, ais, tree, node, space);
2326 return renderExpression(r, node, space);
22812327 }
22822328}
22832329
22842330/// Render a token, and the comma that follows it, if it is present in the source.
22852331/// 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;
22872334 const token_tags = tree.tokens.items(.tag);
22882335 const maybe_comma = token + 1;
22892336 if (token_tags[maybe_comma] == .comma and space != .comma) {
2290 try renderToken(ais, tree, token, .none);
2291 return renderToken(ais, tree, maybe_comma, space);
2337 try renderToken(r, token, .none);
2338 return renderToken(r, maybe_comma, space);
22922339 } else {
2293 return renderToken(ais, tree, token, space);
2340 return renderToken(r, token, space);
22942341 }
22952342}
22962343
......@@ -2315,13 +2362,17 @@ const Space = enum {
23152362 skip,
23162363};
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;
23192368 const lexeme = tokenSliceForRender(tree, token_index);
23202369 try ais.writer().writeAll(lexeme);
2321 try renderSpace(ais, tree, token_index, lexeme.len, space);
2370 try renderSpace(r, token_index, lexeme.len, space);
23222371}
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;
23252376 const token_tags = tree.tokens.items(.tag);
23262377 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
23332384 try ais.writer().writeByte(',');
23342385 }
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]);
23372388 switch (space) {
23382389 .none => {},
23392390 .space => if (!comment) try ais.writer().writeByte(' '),
23402391 .newline => if (!comment) try ais.insertNewline(),
23412392
23422393 .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);
23442395 } else if (!comment) {
23452396 try ais.insertNewline();
23462397 },
23472398
23482399 .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);
23502401 } else if (!comment) {
23512402 try ais.writer().writeByte(' ');
23522403 },
23532404
23542405 .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);
23562407 } else if (!comment) {
23572408 try ais.insertNewline();
23582409 },
......@@ -2395,7 +2446,10 @@ fn hasMultilineString(tree: Ast, start_token: Ast.TokenIndex, end_token: Ast.Tok
23952446
23962447/// Assumes that start is the first byte past the previous token and
23972448/// 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
23992453 var index: usize = start;
24002454 while (mem.indexOf(u8, tree.source[index..end], "//")) |offset| {
24012455 const comment_start = index + offset;
......@@ -2452,12 +2506,14 @@ fn renderComments(ais: *Ais, tree: Ast, start: usize, end: usize) Error!bool {
24522506 return index != start;
24532507}
24542508
2455fn renderExtraNewline(ais: *Ais, tree: Ast, node: Ast.Node.Index) Error!void {
2456 return renderExtraNewlineToken(ais, tree, tree.firstToken(node));
2509fn renderExtraNewline(r: Render, node: Ast.Node.Index) Error!void {
2510 return renderExtraNewlineToken(r, r.tree.firstToken(node));
24572511}
24582512
24592513/// 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;
24612517 const token_starts = tree.tokens.items(.start);
24622518 const token_start = token_starts[token_index];
24632519 if (token_start == 0) return;
......@@ -2482,7 +2538,8 @@ fn renderExtraNewlineToken(ais: *Ais, tree: Ast, token_index: Ast.TokenIndex) Er
24822538
24832539/// end_token is the token one past the last doc comment token. This function
24842540/// 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;
24862543 // Search backwards for the first doc comment.
24872544 const token_tags = tree.tokens.items(.tag);
24882545 if (end_token == 0) return;
......@@ -2503,27 +2560,28 @@ fn renderDocComments(ais: *Ais, tree: Ast, end_token: Ast.TokenIndex) Error!void
25032560 assert(prev_token_tag != .l_paren);
25042561
25052562 if (prev_token_tag != .l_brace) {
2506 try renderExtraNewlineToken(ais, tree, first_tok);
2563 try renderExtraNewlineToken(r, first_tok);
25072564 }
25082565 }
25092566
25102567 while (token_tags[tok] == .doc_comment) : (tok += 1) {
2511 try renderToken(ais, tree, tok, .newline);
2568 try renderToken(r, tok, .newline);
25122569 }
25132570}
25142571
25152572/// 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;
25172575 const token_tags = tree.tokens.items(.tag);
25182576 var tok = start_token;
25192577 while (token_tags[tok] == .container_doc_comment) : (tok += 1) {
2520 try renderToken(ais, tree, tok, .newline);
2578 try renderToken(r, tok, .newline);
25212579 }
25222580 // Render extra newline if there is one between final container doc comment and
25232581 // the next token. If the next token is a doc comment, that code path
25242582 // will have its own logic to insert a newline.
25252583 if (token_tags[tok] != .doc_comment) {
2526 try renderExtraNewlineToken(ais, tree, tok);
2584 try renderExtraNewlineToken(r, tok);
25272585 }
25282586}
25292587
src/Compilation.zig+3
......@@ -93,6 +93,7 @@ unwind_tables: bool,
9393test_evented_io: bool,
9494debug_compiler_runtime_libs: bool,
9595debug_compile_errors: bool,
96autofix: bool,
9697job_queued_compiler_rt_lib: bool = false,
9798job_queued_compiler_rt_obj: bool = false,
9899alloc_failure_occurred: bool = false,
......@@ -856,6 +857,7 @@ pub const InitOptions = struct {
856857 single_threaded: ?bool = null,
857858 rdynamic: bool = false,
858859 strip: bool = false,
860 autofix: bool = false,
859861 function_sections: bool = false,
860862 no_builtin: bool = false,
861863 is_native_os: bool,
......@@ -1838,6 +1840,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation {
18381840 .color = options.color,
18391841 .time_report = options.time_report,
18401842 .stack_report = options.stack_report,
1843 .autofix = options.autofix,
18411844 .unwind_tables = unwind_tables,
18421845 .test_filter = options.test_filter,
18431846 .test_name_prefix = options.test_name_prefix,
src/Module.zig+125-54
......@@ -3493,7 +3493,11 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
34933493 const gpa = mod.gpa;
34943494
34953495 // 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 });
34973501 defer source_file.close();
34983502
34993503 const stat = try source_file.stat();
......@@ -3643,12 +3647,17 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
36433647
36443648 // TODO don't report compile errors until Sema @importFile
36453649 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
36463656 {
36473657 comp.mutex.lock();
36483658 defer comp.mutex.unlock();
36493659 try mod.failed_files.putNoClobber(gpa, file, null);
36503660 }
3651 file.status = .astgen_failure;
36523661 return error.AnalysisFail;
36533662 }
36543663 return;
......@@ -3726,72 +3735,134 @@ pub fn astGenFile(mod: *Module, file: *File) !void {
37263735 file.source = source;
37273736 file.source_loaded = true;
37283737
3729 file.tree = try std.zig.parse(gpa, source);
3730 defer if (!file.tree_loaded) file.tree.deinit(gpa);
3731
3732 if (file.tree.errors.len != 0) {
3733 const parse_err = file.tree.errors[0];
3738 // This is purely to detect when the autofix mechanism has a bug and
3739 // the autofix did not make the compile error go away.
3740 var reparsing = false;
3741 parse: while (true) {
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);
3736 defer msg.deinit();
3745 if (file.tree.errors.len != 0) {
3746 const parse_err = file.tree.errors[0];
37373747
3738 const token_starts = file.tree.tokens.items(.start);
3739 const token_tags = file.tree.tokens.items(.tag);
3748 var msg = std.ArrayList(u8).init(gpa);
3749 defer msg.deinit();
37403750
3741 const extra_offset = file.tree.errorOffset(parse_err);
3742 try file.tree.renderError(parse_err, msg.writer());
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 }
3751 const token_starts = file.tree.tokens.items(.start);
3752 const token_tags = file.tree.tokens.items(.tag);
37653753
3766 for (file.tree.errors[1..]) |note| {
3767 if (!note.is_note) break;
3768
3769 try file.tree.renderError(note, msg.writer());
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] = .{
3754 const extra_offset = file.tree.errorOffset(parse_err);
3755 try file.tree.renderError(parse_err, msg.writer());
3756 const err_msg = try gpa.create(ErrorMsg);
3757 err_msg.* = .{
37723758 .src_loc = .{
37733759 .file_scope = file,
37743760 .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 },
37763766 },
37773767 .msg = msg.toOwnedSlice(),
37783768 };
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;
37793801 }
3802 file.tree_loaded = true;
37803803
3781 {
3782 comp.mutex.lock();
3783 defer comp.mutex.unlock();
3784 try mod.failed_files.putNoClobber(gpa, file, err_msg);
3804 file.zir = try AstGen.generate(gpa, file.tree);
3805 file.zir_loaded = true;
3806 file.status = .success_zir;
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 }
37853862 }
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);
3792 file.zir_loaded = true;
3793 file.status = .success_zir;
3794 log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
3864 break :parse;
3865 }
37953866
37963867 const safety_buffer = if (data_has_safety_tag)
37973868 try gpa.alloc([8]u8, file.zir.instructions.len)
src/main.zig+5
......@@ -403,6 +403,7 @@ const usage_build_generic =
403403 \\ -ffunction-sections Places each function in a separate section
404404 \\ -fno-function-sections All functions go into same section
405405 \\ --strip Omit debug symbols
406 \\ --autofix Avoid some errors by allowing Zig to edit your code
406407 \\ -ofmt=[mode] Override target object format
407408 \\ elf Executable and Linking Format
408409 \\ c C source code
......@@ -629,6 +630,7 @@ fn buildOutputType(
629630 var have_version = false;
630631 var compatibility_version: ?std.builtin.Version = null;
631632 var strip = false;
633 var autofix = false;
632634 var function_sections = false;
633635 var no_builtin = false;
634636 var watch = false;
......@@ -1286,6 +1288,8 @@ fn buildOutputType(
12861288 emit_bin = .no;
12871289 } else if (mem.eql(u8, arg, "--strip")) {
12881290 strip = true;
1291 } else if (mem.eql(u8, arg, "--autofix")) {
1292 autofix = true;
12891293 } else if (mem.eql(u8, arg, "-fsingle-threaded")) {
12901294 single_threaded = true;
12911295 } else if (mem.eql(u8, arg, "-fno-single-threaded")) {
......@@ -2944,6 +2948,7 @@ fn buildOutputType(
29442948 .stack_size_override = stack_size_override,
29452949 .image_base_override = image_base_override,
29462950 .strip = strip,
2951 .autofix = autofix,
29472952 .single_threaded = single_threaded,
29482953 .function_sections = function_sections,
29492954 .no_builtin = no_builtin,