authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-12 23:06:54-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-05-12 23:06:54-04:00
log7cdc9d98c7134be5edd18eb6f94dd8cfc55bb764
treeecffa4a5c8e6f2c6057692650d2f17f5969b7e79
parent911cbf57cd10159176950285feb9ee14fb88a803

refactor std.zig.render to be recursive

See #1006

1 files changed, 1057 insertions(+), 1100 deletions(-)

std/zig/render.zig+1057-1100
......@@ -1,29 +1,23 @@
11const std = @import("../index.zig");
2const builtin = @import("builtin");
23const assert = std.debug.assert;
34const mem = std.mem;
45const ast = std.zig.ast;
56const Token = std.zig.Token;
67
7const RenderState = union(enum) {
8 TopLevelDecl: &ast.Node,
9 ParamDecl: &ast.Node,
10 Text: []const u8,
11 Expression: &ast.Node,
12 VarDecl: &ast.Node.VarDecl,
13 Statement: &ast.Node,
14 PrintIndent,
15 Indent: usize,
16 MaybeSemiColon: &ast.Node,
17 Token: ast.TokenIndex,
18 NonBreakToken: ast.TokenIndex,
8const indent_delta = 4;
9
10pub const Error = error {
11 /// Ran out of memory allocating call stack frames to complete rendering.
12 OutOfMemory,
1913};
2014
21const indent_delta = 4;
15pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) (@typeOf(stream).Child.Error || Error)!void {
16 comptime assert(@typeId(@typeOf(stream)) == builtin.TypeId.Pointer);
2217
23pub fn render(allocator: &mem.Allocator, stream: var, tree: &ast.Tree) !void {
2418 var it = tree.root_node.decls.iterator(0);
2519 while (it.next()) |decl| {
26 try renderTopLevelDecl(allocator, stream, tree, *decl);
20 try renderTopLevelDecl(allocator, stream, tree, 0, *decl);
2721 if (it.peek()) |next_decl| {
2822 const n = if (nodeLineOffset(tree, *decl, *next_decl) >= 2) u8(2) else u8(1);
2923 try stream.writeByteNTimes('\n', n);
......@@ -38,1202 +32,1165 @@ fn nodeLineOffset(tree: &ast.Tree, a: &ast.Node, b: &ast.Node) usize {
3832 return loc.line;
3933}
4034
41fn renderTopLevelDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, decl_ptr: &ast.Node) !void {
42 var stack = std.ArrayList(RenderState).init(allocator);
43 defer stack.deinit();
35fn renderTopLevelDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, decl: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
36 switch (decl.id) {
37 ast.Node.Id.FnProto => {
38 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
4439
45 try stack.append(RenderState {.TopLevelDecl = decl_ptr});
40 try renderComments(tree, stream, fn_proto, indent);
41 try renderExpression(allocator, stream, tree, indent, decl);
4642
47 var indent: usize = 0;
48 while (stack.popOrNull()) |state| {
49 switch (state) {
50 RenderState.TopLevelDecl => |decl| {
51 switch (decl.id) {
52 ast.Node.Id.FnProto => {
53 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
54 try renderComments(tree, stream, fn_proto, indent);
43 if (fn_proto.body_node) |body_node| {
44 try stream.write(" ");
45 try renderExpression(allocator, stream, tree, indent, body_node);
46 } else {
47 try stream.write(";");
48 }
49 },
50 ast.Node.Id.Use => {
51 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
5552
56 if (fn_proto.body_node) |body_node| {
57 stack.append(RenderState { .Expression = body_node}) catch unreachable;
58 try stack.append(RenderState { .Text = " "});
59 } else {
60 stack.append(RenderState { .Text = ";" }) catch unreachable;
61 }
53 if (use_decl.visib_token) |visib_token| {
54 try stream.print("{} ", tree.tokenSlice(visib_token));
55 }
56 try stream.write("use ");
57 try renderExpression(allocator, stream, tree, indent, use_decl.expr);
58 try stream.write(";");
59 },
60 ast.Node.Id.VarDecl => {
61 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
62
63 try renderComments(tree, stream, var_decl, indent);
64 try renderVarDecl(allocator, stream, tree, indent, var_decl);
65 },
66 ast.Node.Id.TestDecl => {
67 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
68
69 try renderComments(tree, stream, test_decl, indent);
70 try stream.write("test ");
71 try renderExpression(allocator, stream, tree, indent, test_decl.name);
72 try stream.write(" ");
73 try renderExpression(allocator, stream, tree, indent, test_decl.body_node);
74 },
75 ast.Node.Id.StructField => {
76 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
77
78 try renderComments(tree, stream, field, indent);
79 if (field.visib_token) |visib_token| {
80 try stream.print("{} ", tree.tokenSlice(visib_token));
81 }
82 try stream.print("{}: ", tree.tokenSlice(field.name_token));
83 try renderExpression(allocator, stream, tree, indent, field.type_expr);
84 try renderToken(tree, stream, field.lastToken() + 1, indent, true);
85 },
86 ast.Node.Id.UnionTag => {
87 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
88
89 try renderComments(tree, stream, tag, indent);
90 try stream.print("{}", tree.tokenSlice(tag.name_token));
91
92 if (tag.type_expr) |type_expr| {
93 try stream.print(": ");
94 try renderExpression(allocator, stream, tree, indent, type_expr);
95 }
6296
63 try stack.append(RenderState { .Expression = decl });
64 },
65 ast.Node.Id.Use => {
66 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
67 if (use_decl.visib_token) |visib_token| {
68 try stream.print("{} ", tree.tokenSlice(visib_token));
69 }
70 try stream.print("use ");
71 try stack.append(RenderState { .Text = ";" });
72 try stack.append(RenderState { .Expression = use_decl.expr });
73 },
74 ast.Node.Id.VarDecl => {
75 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", decl);
76 try renderComments(tree, stream, var_decl, indent);
77 try stack.append(RenderState { .VarDecl = var_decl});
78 },
79 ast.Node.Id.TestDecl => {
80 const test_decl = @fieldParentPtr(ast.Node.TestDecl, "base", decl);
81 try renderComments(tree, stream, test_decl, indent);
82 try stream.print("test ");
83 try stack.append(RenderState { .Expression = test_decl.body_node });
84 try stack.append(RenderState { .Text = " " });
85 try stack.append(RenderState { .Expression = test_decl.name });
86 },
87 ast.Node.Id.StructField => {
88 const field = @fieldParentPtr(ast.Node.StructField, "base", decl);
89 try renderComments(tree, stream, field, indent);
90 if (field.visib_token) |visib_token| {
91 try stream.print("{} ", tree.tokenSlice(visib_token));
92 }
93 try stream.print("{}: ", tree.tokenSlice(field.name_token));
94 try stack.append(RenderState { .Token = field.lastToken() + 1 });
95 try stack.append(RenderState { .Expression = field.type_expr});
96 },
97 ast.Node.Id.UnionTag => {
98 const tag = @fieldParentPtr(ast.Node.UnionTag, "base", decl);
99 try renderComments(tree, stream, tag, indent);
100 try stream.print("{}", tree.tokenSlice(tag.name_token));
101
102 try stack.append(RenderState { .Text = "," });
103
104 if (tag.value_expr) |value_expr| {
105 try stack.append(RenderState { .Expression = value_expr });
106 try stack.append(RenderState { .Text = " = " });
107 }
97 if (tag.value_expr) |value_expr| {
98 try stream.print(" = ");
99 try renderExpression(allocator, stream, tree, indent, value_expr);
100 }
108101
109 if (tag.type_expr) |type_expr| {
110 try stream.print(": ");
111 try stack.append(RenderState { .Expression = type_expr});
112 }
113 },
114 ast.Node.Id.EnumTag => {
115 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
116 try renderComments(tree, stream, tag, indent);
117 try stream.print("{}", tree.tokenSlice(tag.name_token));
118
119 try stack.append(RenderState { .Text = "," });
120 if (tag.value) |value| {
121 try stream.print(" = ");
122 try stack.append(RenderState { .Expression = value});
123 }
124 },
125 ast.Node.Id.ErrorTag => {
126 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
127 try renderComments(tree, stream, tag, indent);
128 try stream.print("{}", tree.tokenSlice(tag.name_token));
129 },
130 ast.Node.Id.Comptime => {
131 try stack.append(RenderState { .MaybeSemiColon = decl });
132 try stack.append(RenderState { .Expression = decl });
133 },
134 ast.Node.Id.LineComment => {
135 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", decl);
136 try stream.write(tree.tokenSlice(line_comment_node.token));
137 },
138 else => unreachable,
139 }
140 },
141
142 RenderState.VarDecl => |var_decl| {
143 try stack.append(RenderState { .Token = var_decl.semicolon_token });
144 if (var_decl.init_node) |init_node| {
145 try stack.append(RenderState { .Expression = init_node });
146 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
147 try stack.append(RenderState { .Text = text });
148 }
149 if (var_decl.align_node) |align_node| {
150 try stack.append(RenderState { .Text = ")" });
151 try stack.append(RenderState { .Expression = align_node });
152 try stack.append(RenderState { .Text = " align(" });
153 }
154 if (var_decl.type_node) |type_node| {
155 try stack.append(RenderState { .Expression = type_node });
156 try stack.append(RenderState { .Text = ": " });
157 }
158 try stack.append(RenderState { .Text = tree.tokenSlice(var_decl.name_token) });
159 try stack.append(RenderState { .Text = " " });
160 try stack.append(RenderState { .Text = tree.tokenSlice(var_decl.mut_token) });
102 try stream.write(",");
103 },
104 ast.Node.Id.EnumTag => {
105 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
161106
162 if (var_decl.comptime_token) |comptime_token| {
163 try stack.append(RenderState { .Text = " " });
164 try stack.append(RenderState { .Text = tree.tokenSlice(comptime_token) });
165 }
107 try renderComments(tree, stream, tag, indent);
108 try stream.print("{}", tree.tokenSlice(tag.name_token));
166109
167 if (var_decl.extern_export_token) |extern_export_token| {
168 if (var_decl.lib_name != null) {
169 try stack.append(RenderState { .Text = " " });
170 try stack.append(RenderState { .Expression = ??var_decl.lib_name });
110 if (tag.value) |value| {
111 try stream.print(" = ");
112 try renderExpression(allocator, stream, tree, indent, value);
113 }
114
115 try stream.write(",");
116 },
117 ast.Node.Id.ErrorTag => {
118 const tag = @fieldParentPtr(ast.Node.ErrorTag, "base", decl);
119
120 try renderComments(tree, stream, tag, indent);
121 try stream.print("{}", tree.tokenSlice(tag.name_token));
122 },
123 ast.Node.Id.Comptime => {
124 try renderExpression(allocator, stream, tree, indent, decl);
125 try maybeRenderSemicolon(stream, tree, indent, decl);
126 },
127 ast.Node.Id.LineComment => {
128 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", decl);
129
130 try stream.write(tree.tokenSlice(line_comment_node.token));
131 },
132 else => unreachable,
133 }
134}
135
136fn renderExpression(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
137 switch (base.id) {
138 ast.Node.Id.Identifier => {
139 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
140 try stream.print("{}", tree.tokenSlice(identifier.token));
141 },
142 ast.Node.Id.Block => {
143 const block = @fieldParentPtr(ast.Node.Block, "base", base);
144 if (block.label) |label| {
145 try stream.print("{}: ", tree.tokenSlice(label));
146 }
147
148 if (block.statements.len == 0) {
149 try stream.write("{}");
150 } else {
151 try stream.write("{\n");
152 const block_indent = indent + indent_delta;
153
154 var it = block.statements.iterator(0);
155 while (it.next()) |statement| {
156 try stream.writeByteNTimes(' ', block_indent);
157 try renderStatement(allocator, stream, tree, block_indent, *statement);
158
159 if (it.peek()) |next_statement| {
160 const n = if (nodeLineOffset(tree, *statement, *next_statement) >= 2) u8(2) else u8(1);
161 try stream.writeByteNTimes('\n', n);
171162 }
172 try stack.append(RenderState { .Text = " " });
173 try stack.append(RenderState { .Text = tree.tokenSlice(extern_export_token) });
174163 }
175164
176 if (var_decl.visib_token) |visib_token| {
177 try stack.append(RenderState { .Text = " " });
178 try stack.append(RenderState { .Text = tree.tokenSlice(visib_token) });
179 }
180 },
165 try stream.write("\n");
166 try stream.writeByteNTimes(' ', indent);
167 try stream.write("}");
168 }
169 },
170 ast.Node.Id.Defer => {
171 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
172 try stream.print("{} ", tree.tokenSlice(defer_node.defer_token));
173 try renderExpression(allocator, stream, tree, indent, defer_node.expr);
174 },
175 ast.Node.Id.Comptime => {
176 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
177 try stream.print("{} ", tree.tokenSlice(comptime_node.comptime_token));
178 try renderExpression(allocator, stream, tree, indent, comptime_node.expr);
179 },
180 ast.Node.Id.AsyncAttribute => {
181 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
182 try stream.print("{}", tree.tokenSlice(async_attr.async_token));
183
184 if (async_attr.allocator_type) |allocator_type| {
185 try stream.write("<");
186 try renderExpression(allocator, stream, tree, indent, allocator_type);
187 try stream.write(">");
188 }
189 },
190 ast.Node.Id.Suspend => {
191 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
192 if (suspend_node.label) |label| {
193 try stream.print("{}: ", tree.tokenSlice(label));
194 }
195 try stream.print("{}", tree.tokenSlice(suspend_node.suspend_token));
181196
182 RenderState.ParamDecl => |base| {
183 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
184 if (param_decl.comptime_token) |comptime_token| {
185 try stream.print("{} ", tree.tokenSlice(comptime_token));
186 }
187 if (param_decl.noalias_token) |noalias_token| {
188 try stream.print("{} ", tree.tokenSlice(noalias_token));
189 }
190 if (param_decl.name_token) |name_token| {
191 try stream.print("{}: ", tree.tokenSlice(name_token));
192 }
193 if (param_decl.var_args_token) |var_args_token| {
194 try stream.print("{}", tree.tokenSlice(var_args_token));
195 } else {
196 try stack.append(RenderState { .Expression = param_decl.type_node});
197 }
198 },
199 RenderState.Text => |bytes| {
200 try stream.write(bytes);
201 },
202 RenderState.Expression => |base| switch (base.id) {
203 ast.Node.Id.Identifier => {
204 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", base);
205 try stream.print("{}", tree.tokenSlice(identifier.token));
206 },
207 ast.Node.Id.Block => {
208 const block = @fieldParentPtr(ast.Node.Block, "base", base);
209 if (block.label) |label| {
210 try stream.print("{}: ", tree.tokenSlice(label));
211 }
197 if (suspend_node.payload) |payload| {
198 try stream.write(" ");
199 try renderExpression(allocator, stream, tree, indent, payload);
200 }
212201
213 if (block.statements.len == 0) {
214 try stream.write("{}");
215 } else {
216 try stream.write("{");
217 try stack.append(RenderState { .Text = "}"});
218 try stack.append(RenderState.PrintIndent);
219 try stack.append(RenderState { .Indent = indent});
220 try stack.append(RenderState { .Text = "\n"});
221 var i = block.statements.len;
222 while (i != 0) {
223 i -= 1;
224 const statement_node = *block.statements.at(i);
225 try stack.append(RenderState { .Statement = statement_node});
226 try stack.append(RenderState.PrintIndent);
227 try stack.append(RenderState { .Indent = indent + indent_delta});
228 try stack.append(RenderState {
229 .Text = blk: {
230 if (i != 0) {
231 const prev_node = *block.statements.at(i - 1);
232 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
233 const loc = tree.tokenLocation(prev_node_last_token_end, statement_node.firstToken());
234 if (loc.line >= 2) {
235 break :blk "\n\n";
236 }
237 }
238 break :blk "\n";
239 },
240 });
241 }
242 }
243 },
244 ast.Node.Id.Defer => {
245 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);
246 try stream.print("{} ", tree.tokenSlice(defer_node.defer_token));
247 try stack.append(RenderState { .Expression = defer_node.expr });
248 },
249 ast.Node.Id.Comptime => {
250 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);
251 try stream.print("{} ", tree.tokenSlice(comptime_node.comptime_token));
252 try stack.append(RenderState { .Expression = comptime_node.expr });
253 },
254 ast.Node.Id.AsyncAttribute => {
255 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);
256 try stream.print("{}", tree.tokenSlice(async_attr.async_token));
257
258 if (async_attr.allocator_type) |allocator_type| {
259 try stack.append(RenderState { .Text = ">" });
260 try stack.append(RenderState { .Expression = allocator_type });
261 try stack.append(RenderState { .Text = "<" });
202 if (suspend_node.body) |body| {
203 try stream.write(" ");
204 try renderExpression(allocator, stream, tree, indent, body);
205 }
206
207 },
208
209 ast.Node.Id.InfixOp => {
210 const infix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
211
212 try renderExpression(allocator, stream, tree, indent, infix_op_node.lhs);
213
214 const text = switch (infix_op_node.op) {
215 ast.Node.InfixOp.Op.Add => " + ",
216 ast.Node.InfixOp.Op.AddWrap => " +% ",
217 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
218 ast.Node.InfixOp.Op.ArrayMult => " ** ",
219 ast.Node.InfixOp.Op.Assign => " = ",
220 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
221 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
222 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
223 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
224 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
225 ast.Node.InfixOp.Op.AssignDiv => " /= ",
226 ast.Node.InfixOp.Op.AssignMinus => " -= ",
227 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
228 ast.Node.InfixOp.Op.AssignMod => " %= ",
229 ast.Node.InfixOp.Op.AssignPlus => " += ",
230 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
231 ast.Node.InfixOp.Op.AssignTimes => " *= ",
232 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
233 ast.Node.InfixOp.Op.BangEqual => " != ",
234 ast.Node.InfixOp.Op.BitAnd => " & ",
235 ast.Node.InfixOp.Op.BitOr => " | ",
236 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
237 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
238 ast.Node.InfixOp.Op.BitXor => " ^ ",
239 ast.Node.InfixOp.Op.BoolAnd => " and ",
240 ast.Node.InfixOp.Op.BoolOr => " or ",
241 ast.Node.InfixOp.Op.Div => " / ",
242 ast.Node.InfixOp.Op.EqualEqual => " == ",
243 ast.Node.InfixOp.Op.ErrorUnion => "!",
244 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
245 ast.Node.InfixOp.Op.GreaterThan => " > ",
246 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
247 ast.Node.InfixOp.Op.LessThan => " < ",
248 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
249 ast.Node.InfixOp.Op.Mod => " % ",
250 ast.Node.InfixOp.Op.Mult => " * ",
251 ast.Node.InfixOp.Op.MultWrap => " *% ",
252 ast.Node.InfixOp.Op.Period => ".",
253 ast.Node.InfixOp.Op.Sub => " - ",
254 ast.Node.InfixOp.Op.SubWrap => " -% ",
255 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
256 ast.Node.InfixOp.Op.Range => " ... ",
257 ast.Node.InfixOp.Op.Catch => |maybe_payload| blk: {
258 try stream.write(" catch ");
259 if (maybe_payload) |payload| {
260 try renderExpression(allocator, stream, tree, indent, payload);
261 try stream.write(" ");
262262 }
263 break :blk "";
263264 },
264 ast.Node.Id.Suspend => {
265 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);
266 if (suspend_node.label) |label| {
267 try stream.print("{}: ", tree.tokenSlice(label));
265 };
266
267 try stream.write(text);
268 try renderExpression(allocator, stream, tree, indent, infix_op_node.rhs);
269 },
270
271 ast.Node.Id.PrefixOp => {
272 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
273
274 switch (prefix_op_node.op) {
275 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
276 try stream.write("&");
277 if (addr_of_info.align_expr) |align_expr| {
278 try stream.write("align(");
279 try renderExpression(allocator, stream, tree, indent, align_expr);
280 try stream.write(") ");
268281 }
269 try stream.print("{}", tree.tokenSlice(suspend_node.suspend_token));
270
271 if (suspend_node.body) |body| {
272 try stack.append(RenderState { .Expression = body });
273 try stack.append(RenderState { .Text = " " });
282 if (addr_of_info.const_token != null) {
283 try stream.write("const ");
274284 }
275
276 if (suspend_node.payload) |payload| {
277 try stack.append(RenderState { .Expression = payload });
278 try stack.append(RenderState { .Text = " " });
285 if (addr_of_info.volatile_token != null) {
286 try stream.write("volatile ");
279287 }
280288 },
281 ast.Node.Id.InfixOp => {
282 const prefix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
283 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
284
285 if (prefix_op_node.op == ast.Node.InfixOp.Op.Catch) {
286 if (prefix_op_node.op.Catch) |payload| {
287 try stack.append(RenderState { .Text = " " });
288 try stack.append(RenderState { .Expression = payload });
289 }
290 try stack.append(RenderState { .Text = " catch " });
291 } else {
292 const text = switch (prefix_op_node.op) {
293 ast.Node.InfixOp.Op.Add => " + ",
294 ast.Node.InfixOp.Op.AddWrap => " +% ",
295 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
296 ast.Node.InfixOp.Op.ArrayMult => " ** ",
297 ast.Node.InfixOp.Op.Assign => " = ",
298 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
299 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
300 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
301 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
302 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
303 ast.Node.InfixOp.Op.AssignDiv => " /= ",
304 ast.Node.InfixOp.Op.AssignMinus => " -= ",
305 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
306 ast.Node.InfixOp.Op.AssignMod => " %= ",
307 ast.Node.InfixOp.Op.AssignPlus => " += ",
308 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
309 ast.Node.InfixOp.Op.AssignTimes => " *= ",
310 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
311 ast.Node.InfixOp.Op.BangEqual => " != ",
312 ast.Node.InfixOp.Op.BitAnd => " & ",
313 ast.Node.InfixOp.Op.BitOr => " | ",
314 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
315 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
316 ast.Node.InfixOp.Op.BitXor => " ^ ",
317 ast.Node.InfixOp.Op.BoolAnd => " and ",
318 ast.Node.InfixOp.Op.BoolOr => " or ",
319 ast.Node.InfixOp.Op.Div => " / ",
320 ast.Node.InfixOp.Op.EqualEqual => " == ",
321 ast.Node.InfixOp.Op.ErrorUnion => "!",
322 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
323 ast.Node.InfixOp.Op.GreaterThan => " > ",
324 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
325 ast.Node.InfixOp.Op.LessThan => " < ",
326 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
327 ast.Node.InfixOp.Op.Mod => " % ",
328 ast.Node.InfixOp.Op.Mult => " * ",
329 ast.Node.InfixOp.Op.MultWrap => " *% ",
330 ast.Node.InfixOp.Op.Period => ".",
331 ast.Node.InfixOp.Op.Sub => " - ",
332 ast.Node.InfixOp.Op.SubWrap => " -% ",
333 ast.Node.InfixOp.Op.UnwrapMaybe => " ?? ",
334 ast.Node.InfixOp.Op.Range => " ... ",
335 ast.Node.InfixOp.Op.Catch => unreachable,
336 };
337
338 try stack.append(RenderState { .Text = text });
289 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
290 try stream.write("[]");
291 if (addr_of_info.align_expr) |align_expr| {
292 try stream.print("align(");
293 try renderExpression(allocator, stream, tree, indent, align_expr);
294 try stream.print(") ");
339295 }
340 try stack.append(RenderState { .Expression = prefix_op_node.lhs });
341 },
342 ast.Node.Id.PrefixOp => {
343 const prefix_op_node = @fieldParentPtr(ast.Node.PrefixOp, "base", base);
344 try stack.append(RenderState { .Expression = prefix_op_node.rhs });
345 switch (prefix_op_node.op) {
346 ast.Node.PrefixOp.Op.AddrOf => |addr_of_info| {
347 try stream.write("&");
348 if (addr_of_info.volatile_token != null) {
349 try stack.append(RenderState { .Text = "volatile "});
350 }
351 if (addr_of_info.const_token != null) {
352 try stack.append(RenderState { .Text = "const "});
353 }
354 if (addr_of_info.align_expr) |align_expr| {
355 try stream.print("align(");
356 try stack.append(RenderState { .Text = ") "});
357 try stack.append(RenderState { .Expression = align_expr});
358 }
359 },
360 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
361 try stream.write("[]");
362 if (addr_of_info.volatile_token != null) {
363 try stack.append(RenderState { .Text = "volatile "});
364 }
365 if (addr_of_info.const_token != null) {
366 try stack.append(RenderState { .Text = "const "});
367 }
368 if (addr_of_info.align_expr) |align_expr| {
369 try stream.print("align(");
370 try stack.append(RenderState { .Text = ") "});
371 try stack.append(RenderState { .Expression = align_expr});
372 }
373 },
374 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
375 try stack.append(RenderState { .Text = "]"});
376 try stack.append(RenderState { .Expression = array_index});
377 try stack.append(RenderState { .Text = "["});
378 },
379 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
380 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
381 ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
382 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
383 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
384 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
385 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
386 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
387 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
388 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
389 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
296 if (addr_of_info.const_token != null) {
297 try stream.print("const ");
390298 }
391 },
392 ast.Node.Id.SuffixOp => {
393 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
394
395 switch (suffix_op.op) {
396 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
397 try stack.append(RenderState { .Text = ")"});
398 var i = call_info.params.len;
399 while (i != 0) {
400 i -= 1;
401 const param_node = *call_info.params.at(i);
402 try stack.append(RenderState { .Expression = param_node});
403 if (i != 0) {
404 try stack.append(RenderState { .Text = ", " });
405 }
406 }
407 try stack.append(RenderState { .Text = "("});
408 try stack.append(RenderState { .Expression = suffix_op.lhs });
409
410 if (call_info.async_attr) |async_attr| {
411 try stack.append(RenderState { .Text = " "});
412 try stack.append(RenderState { .Expression = &async_attr.base });
413 }
414 },
415 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
416 try stack.append(RenderState { .Text = "]"});
417 try stack.append(RenderState { .Expression = index_expr});
418 try stack.append(RenderState { .Text = "["});
419 try stack.append(RenderState { .Expression = suffix_op.lhs });
420 },
421 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
422 try stack.append(RenderState { .Text = "]"});
423 if (range.end) |end| {
424 try stack.append(RenderState { .Expression = end});
425 }
426 try stack.append(RenderState { .Text = ".."});
427 try stack.append(RenderState { .Expression = range.start});
428 try stack.append(RenderState { .Text = "["});
429 try stack.append(RenderState { .Expression = suffix_op.lhs });
430 },
431 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
432 if (field_inits.len == 0) {
433 try stack.append(RenderState { .Text = "{}" });
434 try stack.append(RenderState { .Expression = suffix_op.lhs });
435 continue;
436 }
437 if (field_inits.len == 1) {
438 const field_init = *field_inits.at(0);
439
440 try stack.append(RenderState { .Text = " }" });
441 try stack.append(RenderState { .Expression = field_init });
442 try stack.append(RenderState { .Text = "{ " });
443 try stack.append(RenderState { .Expression = suffix_op.lhs });
444 continue;
445 }
446 try stack.append(RenderState { .Text = "}"});
447 try stack.append(RenderState.PrintIndent);
448 try stack.append(RenderState { .Indent = indent });
449 try stack.append(RenderState { .Text = "\n" });
450 var i = field_inits.len;
451 while (i != 0) {
452 i -= 1;
453 const field_init = *field_inits.at(i);
454 if (field_init.id != ast.Node.Id.LineComment) {
455 try stack.append(RenderState { .Text = "," });
456 }
457 try stack.append(RenderState { .Expression = field_init });
458 try stack.append(RenderState.PrintIndent);
459 if (i != 0) {
460 try stack.append(RenderState { .Text = blk: {
461 const prev_node = *field_inits.at(i - 1);
462 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
463 const loc = tree.tokenLocation(prev_node_last_token_end, field_init.firstToken());
464 if (loc.line >= 2) {
465 break :blk "\n\n";
466 }
467 break :blk "\n";
468 }});
469 }
470 }
471 try stack.append(RenderState { .Indent = indent + indent_delta });
472 try stack.append(RenderState { .Text = "{\n"});
473 try stack.append(RenderState { .Expression = suffix_op.lhs });
474 },
475 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
476 if (exprs.len == 0) {
477 try stack.append(RenderState { .Text = "{}" });
478 try stack.append(RenderState { .Expression = suffix_op.lhs });
479 continue;
480 }
481 if (exprs.len == 1) {
482 const expr = *exprs.at(0);
483
484 try stack.append(RenderState { .Text = "}" });
485 try stack.append(RenderState { .Expression = expr });
486 try stack.append(RenderState { .Text = "{" });
487 try stack.append(RenderState { .Expression = suffix_op.lhs });
488 continue;
489 }
490
491 try stack.append(RenderState { .Text = "}"});
492 try stack.append(RenderState.PrintIndent);
493 try stack.append(RenderState { .Indent = indent });
494 var i = exprs.len;
495 while (i != 0) {
496 i -= 1;
497 const expr = *exprs.at(i);
498 try stack.append(RenderState { .Text = ",\n" });
499 try stack.append(RenderState { .Expression = expr });
500 try stack.append(RenderState.PrintIndent);
501 }
502 try stack.append(RenderState { .Indent = indent + indent_delta });
503 try stack.append(RenderState { .Text = "{\n"});
504 try stack.append(RenderState { .Expression = suffix_op.lhs });
505 },
299 if (addr_of_info.volatile_token != null) {
300 try stream.print("volatile ");
506301 }
507302 },
508 ast.Node.Id.ControlFlowExpression => {
509 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
303 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
304 try stream.print("[");
305 try renderExpression(allocator, stream, tree, indent, array_index);
306 try stream.print("]");
307 },
308 ast.Node.PrefixOp.Op.BitNot => try stream.write("~"),
309 ast.Node.PrefixOp.Op.BoolNot => try stream.write("!"),
310 ast.Node.PrefixOp.Op.Deref => try stream.write("*"),
311 ast.Node.PrefixOp.Op.Negation => try stream.write("-"),
312 ast.Node.PrefixOp.Op.NegationWrap => try stream.write("-%"),
313 ast.Node.PrefixOp.Op.Try => try stream.write("try "),
314 ast.Node.PrefixOp.Op.UnwrapMaybe => try stream.write("??"),
315 ast.Node.PrefixOp.Op.MaybeType => try stream.write("?"),
316 ast.Node.PrefixOp.Op.Await => try stream.write("await "),
317 ast.Node.PrefixOp.Op.Cancel => try stream.write("cancel "),
318 ast.Node.PrefixOp.Op.Resume => try stream.write("resume "),
319 }
320
321 try renderExpression(allocator, stream, tree, indent, prefix_op_node.rhs);
322 },
510323
511 if (flow_expr.rhs) |rhs| {
512 try stack.append(RenderState { .Expression = rhs });
513 try stack.append(RenderState { .Text = " " });
324 ast.Node.Id.SuffixOp => {
325 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
326
327 switch (suffix_op.op) {
328 @TagType(ast.Node.SuffixOp.Op).Call => |*call_info| {
329 if (call_info.async_attr) |async_attr| {
330 try renderExpression(allocator, stream, tree, indent, &async_attr.base);
331 try stream.write(" ");
514332 }
515333
516 switch (flow_expr.kind) {
517 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
518 try stream.print("break");
519 if (maybe_label) |label| {
520 try stream.print(" :");
521 try stack.append(RenderState { .Expression = label });
522 }
523 },
524 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
525 try stream.print("continue");
526 if (maybe_label) |label| {
527 try stream.print(" :");
528 try stack.append(RenderState { .Expression = label });
529 }
530 },
531 ast.Node.ControlFlowExpression.Kind.Return => {
532 try stream.print("return");
533 },
334 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
335 try stream.write("(");
534336
337 var it = call_info.params.iterator(0);
338 while (it.next()) |param_node| {
339 try renderExpression(allocator, stream, tree, indent, *param_node);
340 if (it.peek() != null) {
341 try stream.write(", ");
342 }
535343 }
344
345 try stream.write(")");
536346 },
537 ast.Node.Id.Payload => {
538 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
539 try stack.append(RenderState { .Text = "|"});
540 try stack.append(RenderState { .Expression = payload.error_symbol });
541 try stack.append(RenderState { .Text = "|"});
347
348 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
349 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
350 try stream.write("[");
351 try renderExpression(allocator, stream, tree, indent, index_expr);
352 try stream.write("]");
542353 },
543 ast.Node.Id.PointerPayload => {
544 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
545 try stack.append(RenderState { .Text = "|"});
546 try stack.append(RenderState { .Expression = payload.value_symbol });
547354
548 if (payload.ptr_token) |ptr_token| {
549 try stack.append(RenderState { .Text = tree.tokenSlice(ptr_token) });
355 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
356 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
357 try stream.write("[");
358 try renderExpression(allocator, stream, tree, indent, range.start);
359 try stream.write("..");
360 if (range.end) |end| {
361 try renderExpression(allocator, stream, tree, indent, end);
550362 }
551
552 try stack.append(RenderState { .Text = "|"});
363 try stream.write("]");
553364 },
554 ast.Node.Id.PointerIndexPayload => {
555 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
556 try stack.append(RenderState { .Text = "|"});
557365
558 if (payload.index_symbol) |index_symbol| {
559 try stack.append(RenderState { .Expression = index_symbol });
560 try stack.append(RenderState { .Text = ", "});
366 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
367 if (field_inits.len == 0) {
368 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
369 try stream.write("{}");
370 return;
561371 }
562372
563 try stack.append(RenderState { .Expression = payload.value_symbol });
373 if (field_inits.len == 1) {
374 const field_init = *field_inits.at(0);
564375
565 if (payload.ptr_token) |ptr_token| {
566 try stack.append(RenderState { .Text = tree.tokenSlice(ptr_token) });
376 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
377 try stream.write("{ ");
378 try renderExpression(allocator, stream, tree, indent, field_init);
379 try stream.write(" }");
380 return;
567381 }
568382
569 try stack.append(RenderState { .Text = "|"});
570 },
571 ast.Node.Id.GroupedExpression => {
572 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
573 try stack.append(RenderState { .Text = ")"});
574 try stack.append(RenderState { .Expression = grouped_expr.expr });
575 try stack.append(RenderState { .Text = "("});
576 },
577 ast.Node.Id.FieldInitializer => {
578 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
579 try stream.print(".{} = ", tree.tokenSlice(field_init.name_token));
580 try stack.append(RenderState { .Expression = field_init.expr });
581 },
582 ast.Node.Id.IntegerLiteral => {
583 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
584 try stream.print("{}", tree.tokenSlice(integer_literal.token));
585 },
586 ast.Node.Id.FloatLiteral => {
587 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
588 try stream.print("{}", tree.tokenSlice(float_literal.token));
589 },
590 ast.Node.Id.StringLiteral => {
591 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
592 try stream.print("{}", tree.tokenSlice(string_literal.token));
593 },
594 ast.Node.Id.CharLiteral => {
595 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
596 try stream.print("{}", tree.tokenSlice(char_literal.token));
597 },
598 ast.Node.Id.BoolLiteral => {
599 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
600 try stream.print("{}", tree.tokenSlice(bool_literal.token));
601 },
602 ast.Node.Id.NullLiteral => {
603 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
604 try stream.print("{}", tree.tokenSlice(null_literal.token));
605 },
606 ast.Node.Id.ThisLiteral => {
607 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
608 try stream.print("{}", tree.tokenSlice(this_literal.token));
609 },
610 ast.Node.Id.Unreachable => {
611 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
612 try stream.print("{}", tree.tokenSlice(unreachable_node.token));
613 },
614 ast.Node.Id.ErrorType => {
615 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
616 try stream.print("{}", tree.tokenSlice(error_type.token));
617 },
618 ast.Node.Id.VarType => {
619 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
620 try stream.print("{}", tree.tokenSlice(var_type.token));
621 },
622 ast.Node.Id.ContainerDecl => {
623 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
383 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
384 try stream.write("{\n");
624385
625 switch (container_decl.layout) {
626 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
627 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
628 ast.Node.ContainerDecl.Layout.Auto => { },
629 }
386 const new_indent = indent + indent_delta;
630387
631 switch (container_decl.kind) {
632 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
633 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
634 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
635 }
636
637 if (container_decl.fields_and_decls.len == 0) {
638 try stack.append(RenderState { .Text = "{}"});
639 } else {
640 try stack.append(RenderState { .Text = "}"});
641 try stack.append(RenderState.PrintIndent);
642 try stack.append(RenderState { .Indent = indent });
643 try stack.append(RenderState { .Text = "\n"});
644
645 var i = container_decl.fields_and_decls.len;
646 while (i != 0) {
647 i -= 1;
648 const node = *container_decl.fields_and_decls.at(i);
649 try stack.append(RenderState { .TopLevelDecl = node});
650 try stack.append(RenderState.PrintIndent);
651 try stack.append(RenderState {
652 .Text = blk: {
653 if (i != 0) {
654 const prev_node = *container_decl.fields_and_decls.at(i - 1);
655 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
656 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
657 if (loc.line >= 2) {
658 break :blk "\n\n";
659 }
660 }
661 break :blk "\n";
662 },
663 });
388 var it = field_inits.iterator(0);
389 while (it.next()) |field_init| {
390 try stream.writeByteNTimes(' ', new_indent);
391 try renderExpression(allocator, stream, tree, new_indent, *field_init);
392 if ((*field_init).id != ast.Node.Id.LineComment) {
393 try stream.write(",");
394 }
395 if (it.peek()) |next_field_init| {
396 const n = if (nodeLineOffset(tree, *field_init, *next_field_init) >= 2) u8(2) else u8(1);
397 try stream.writeByteNTimes('\n', n);
664398 }
665 try stack.append(RenderState { .Indent = indent + indent_delta});
666 try stack.append(RenderState { .Text = "{"});
667399 }
668400
669 switch (container_decl.init_arg_expr) {
670 ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),
671 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
672 if (enum_tag_type) |expr| {
673 try stack.append(RenderState { .Text = ")) "});
674 try stack.append(RenderState { .Expression = expr});
675 try stack.append(RenderState { .Text = "(enum("});
676 } else {
677 try stack.append(RenderState { .Text = "(enum) "});
678 }
679 },
680 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
681 try stack.append(RenderState { .Text = ") "});
682 try stack.append(RenderState { .Expression = type_expr});
683 try stack.append(RenderState { .Text = "("});
684 },
685 }
401 try stream.write("\n");
402 try stream.writeByteNTimes(' ', indent);
403 try stream.write("}");
686404 },
687 ast.Node.Id.ErrorSetDecl => {
688 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
689405
690 if (err_set_decl.decls.len == 0) {
691 try stream.write("error{}");
692 continue;
406 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
407
408 if (exprs.len == 0) {
409 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
410 try stream.write("{}");
411 return;
412 }
413 if (exprs.len == 1) {
414 const expr = *exprs.at(0);
415
416 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
417 try stream.write("{");
418 try renderExpression(allocator, stream, tree, indent, expr);
419 try stream.write("}");
420 return;
693421 }
694422
695 if (err_set_decl.decls.len == 1) blk: {
696 const node = *err_set_decl.decls.at(0);
423 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
697424
698 // if there are any doc comments or same line comments
699 // don't try to put it all on one line
700 if (node.cast(ast.Node.ErrorTag)) |tag| {
701 if (tag.doc_comments != null) break :blk;
702 } else {
703 break :blk;
704 }
425 const new_indent = indent + indent_delta;
426 try stream.write("{\n");
705427
428 var it = exprs.iterator(0);
429 while (it.next()) |expr| {
430 try stream.writeByteNTimes(' ', new_indent);
431 try renderExpression(allocator, stream, tree, new_indent, *expr);
432 try stream.write(",");
706433
707 try stream.write("error{");
708 try stack.append(RenderState { .Text = "}" });
709 try stack.append(RenderState { .TopLevelDecl = node });
710 continue;
434 if (it.peek()) |next_expr| {
435 const n = if (nodeLineOffset(tree, *expr, *next_expr) >= 2) u8(2) else u8(1);
436 try stream.writeByteNTimes('\n', n);
437 }
711438 }
712439
713 try stream.write("error{");
440 try stream.write("\n");
441 try stream.writeByteNTimes(' ', indent);
442 try stream.write("}");
443 },
444 }
445 },
714446
715 try stack.append(RenderState { .Text = "}"});
716 try stack.append(RenderState.PrintIndent);
717 try stack.append(RenderState { .Indent = indent });
718 try stack.append(RenderState { .Text = "\n"});
447 ast.Node.Id.ControlFlowExpression => {
448 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
719449
720 var i = err_set_decl.decls.len;
721 while (i != 0) {
722 i -= 1;
723 const node = *err_set_decl.decls.at(i);
724 if (node.id != ast.Node.Id.LineComment) {
725 try stack.append(RenderState { .Text = "," });
726 }
727 try stack.append(RenderState { .TopLevelDecl = node });
728 try stack.append(RenderState.PrintIndent);
729 try stack.append(RenderState {
730 .Text = blk: {
731 if (i != 0) {
732 const prev_node = *err_set_decl.decls.at(i - 1);
733 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
734 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
735 if (loc.line >= 2) {
736 break :blk "\n\n";
737 }
738 }
739 break :blk "\n";
740 },
741 });
450 switch (flow_expr.kind) {
451 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
452 try stream.print("break");
453 if (maybe_label) |label| {
454 try stream.print(" :");
455 try renderExpression(allocator, stream, tree, indent, label);
742456 }
743 try stack.append(RenderState { .Indent = indent + indent_delta});
744457 },
745 ast.Node.Id.MultilineStringLiteral => {
746 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
747 try stream.print("\n");
748
749 var i : usize = 0;
750 while (i < multiline_str_literal.lines.len) : (i += 1) {
751 const t = *multiline_str_literal.lines.at(i);
752 try stream.writeByteNTimes(' ', indent + indent_delta);
753 try stream.print("{}", tree.tokenSlice(t));
458 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
459 try stream.print("continue");
460 if (maybe_label) |label| {
461 try stream.print(" :");
462 try renderExpression(allocator, stream, tree, indent, label);
754463 }
755 try stream.writeByteNTimes(' ', indent);
756 },
757 ast.Node.Id.UndefinedLiteral => {
758 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
759 try stream.print("{}", tree.tokenSlice(undefined_literal.token));
760464 },
761 ast.Node.Id.BuiltinCall => {
762 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
763 try stream.print("{}(", tree.tokenSlice(builtin_call.builtin_token));
764 try stack.append(RenderState { .Text = ")"});
765 var i = builtin_call.params.len;
766 while (i != 0) {
767 i -= 1;
768 const param_node = *builtin_call.params.at(i);
769 try stack.append(RenderState { .Expression = param_node});
770 if (i != 0) {
771 try stack.append(RenderState { .Text = ", " });
772 }
773 }
465 ast.Node.ControlFlowExpression.Kind.Return => {
466 try stream.print("return");
774467 },
775 ast.Node.Id.FnProto => {
776 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
777
778 switch (fn_proto.return_type) {
779 ast.Node.FnProto.ReturnType.Explicit => |node| {
780 try stack.append(RenderState { .Expression = node});
781 },
782 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
783 try stack.append(RenderState { .Expression = node});
784 try stack.append(RenderState { .Text = "!"});
785 },
786 }
787468
788 if (fn_proto.align_expr) |align_expr| {
789 try stack.append(RenderState { .Text = ") " });
790 try stack.append(RenderState { .Expression = align_expr});
791 try stack.append(RenderState { .Text = "align(" });
792 }
469 }
793470
794 try stack.append(RenderState { .Text = ") " });
795 var i = fn_proto.params.len;
796 while (i != 0) {
797 i -= 1;
798 const param_decl_node = *fn_proto.params.at(i);
799 try stack.append(RenderState { .ParamDecl = param_decl_node});
800 if (i != 0) {
801 try stack.append(RenderState { .Text = ", " });
802 }
803 }
471 if (flow_expr.rhs) |rhs| {
472 try stream.write(" ");
473 try renderExpression(allocator, stream, tree, indent, rhs);
474 }
475 },
804476
805 try stack.append(RenderState { .Text = "(" });
806 if (fn_proto.name_token) |name_token| {
807 try stack.append(RenderState { .Text = tree.tokenSlice(name_token) });
808 try stack.append(RenderState { .Text = " " });
809 }
477 ast.Node.Id.Payload => {
478 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
810479
811 try stack.append(RenderState { .Text = "fn" });
480 try stream.write("|");
481 try renderExpression(allocator, stream, tree, indent, payload.error_symbol);
482 try stream.write("|");
483 },
812484
813 if (fn_proto.async_attr) |async_attr| {
814 try stack.append(RenderState { .Text = " " });
815 try stack.append(RenderState { .Expression = &async_attr.base });
816 }
485 ast.Node.Id.PointerPayload => {
486 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
817487
818 if (fn_proto.cc_token) |cc_token| {
819 try stack.append(RenderState { .Text = " " });
820 try stack.append(RenderState { .Text = tree.tokenSlice(cc_token) });
821 }
488 try stream.write("|");
489 if (payload.ptr_token) |ptr_token| {
490 try stream.write(tree.tokenSlice(ptr_token));
491 }
492 try renderExpression(allocator, stream, tree, indent, payload.value_symbol);
493 try stream.write("|");
494 },
822495
823 if (fn_proto.lib_name) |lib_name| {
824 try stack.append(RenderState { .Text = " " });
825 try stack.append(RenderState { .Expression = lib_name });
826 }
827 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
828 try stack.append(RenderState { .Text = " " });
829 try stack.append(RenderState { .Text = tree.tokenSlice(extern_export_inline_token) });
830 }
496 ast.Node.Id.PointerIndexPayload => {
497 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
831498
832 if (fn_proto.visib_token) |visib_token_index| {
833 const visib_token = tree.tokens.at(visib_token_index);
834 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
835 try stack.append(RenderState { .Text = " " });
836 try stack.append(RenderState { .Text = tree.tokenSlice(visib_token_index) });
837 }
838 },
839 ast.Node.Id.PromiseType => {
840 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
841 try stream.write(tree.tokenSlice(promise_type.promise_token));
842 if (promise_type.result) |result| {
843 try stream.write(tree.tokenSlice(result.arrow_token));
844 try stack.append(RenderState { .Expression = result.return_type});
499 try stream.write("|");
500 if (payload.ptr_token) |ptr_token| {
501 try stream.write(tree.tokenSlice(ptr_token));
502 }
503 try renderExpression(allocator, stream, tree, indent, payload.value_symbol);
504
505 if (payload.index_symbol) |index_symbol| {
506 try stream.write(", ");
507 try renderExpression(allocator, stream, tree, indent, index_symbol);
508 }
509
510 try stream.write("|");
511 },
512
513 ast.Node.Id.GroupedExpression => {
514 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", base);
515
516 try stream.write("(");
517 try renderExpression(allocator, stream, tree, indent, grouped_expr.expr);
518 try stream.write(")");
519 },
520
521 ast.Node.Id.FieldInitializer => {
522 const field_init = @fieldParentPtr(ast.Node.FieldInitializer, "base", base);
523
524 try stream.print(".{} = ", tree.tokenSlice(field_init.name_token));
525 try renderExpression(allocator, stream, tree, indent, field_init.expr);
526 },
527
528 ast.Node.Id.IntegerLiteral => {
529 const integer_literal = @fieldParentPtr(ast.Node.IntegerLiteral, "base", base);
530 try stream.print("{}", tree.tokenSlice(integer_literal.token));
531 },
532 ast.Node.Id.FloatLiteral => {
533 const float_literal = @fieldParentPtr(ast.Node.FloatLiteral, "base", base);
534 try stream.print("{}", tree.tokenSlice(float_literal.token));
535 },
536 ast.Node.Id.StringLiteral => {
537 const string_literal = @fieldParentPtr(ast.Node.StringLiteral, "base", base);
538 try stream.print("{}", tree.tokenSlice(string_literal.token));
539 },
540 ast.Node.Id.CharLiteral => {
541 const char_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
542 try stream.print("{}", tree.tokenSlice(char_literal.token));
543 },
544 ast.Node.Id.BoolLiteral => {
545 const bool_literal = @fieldParentPtr(ast.Node.CharLiteral, "base", base);
546 try stream.print("{}", tree.tokenSlice(bool_literal.token));
547 },
548 ast.Node.Id.NullLiteral => {
549 const null_literal = @fieldParentPtr(ast.Node.NullLiteral, "base", base);
550 try stream.print("{}", tree.tokenSlice(null_literal.token));
551 },
552 ast.Node.Id.ThisLiteral => {
553 const this_literal = @fieldParentPtr(ast.Node.ThisLiteral, "base", base);
554 try stream.print("{}", tree.tokenSlice(this_literal.token));
555 },
556 ast.Node.Id.Unreachable => {
557 const unreachable_node = @fieldParentPtr(ast.Node.Unreachable, "base", base);
558 try stream.print("{}", tree.tokenSlice(unreachable_node.token));
559 },
560 ast.Node.Id.ErrorType => {
561 const error_type = @fieldParentPtr(ast.Node.ErrorType, "base", base);
562 try stream.print("{}", tree.tokenSlice(error_type.token));
563 },
564 ast.Node.Id.VarType => {
565 const var_type = @fieldParentPtr(ast.Node.VarType, "base", base);
566 try stream.print("{}", tree.tokenSlice(var_type.token));
567 },
568 ast.Node.Id.ContainerDecl => {
569 const container_decl = @fieldParentPtr(ast.Node.ContainerDecl, "base", base);
570
571 switch (container_decl.layout) {
572 ast.Node.ContainerDecl.Layout.Packed => try stream.print("packed "),
573 ast.Node.ContainerDecl.Layout.Extern => try stream.print("extern "),
574 ast.Node.ContainerDecl.Layout.Auto => { },
575 }
576
577 switch (container_decl.kind) {
578 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),
579 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),
580 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),
581 }
582
583 switch (container_decl.init_arg_expr) {
584 ast.Node.ContainerDecl.InitArg.None => try stream.write(" "),
585 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {
586 if (enum_tag_type) |expr| {
587 try stream.write("(enum(");
588 try renderExpression(allocator, stream, tree, indent, expr);
589 try stream.write(")) ");
590 } else {
591 try stream.write("(enum) ");
845592 }
846593 },
847 ast.Node.Id.LineComment => {
848 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);
849 try stream.write(tree.tokenSlice(line_comment_node.token));
594 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
595 try stream.write("(");
596 try renderExpression(allocator, stream, tree, indent, type_expr);
597 try stream.write(") ");
850598 },
851 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
852 ast.Node.Id.Switch => {
853 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
599 }
854600
855 try stream.print("{} (", tree.tokenSlice(switch_node.switch_token));
601 if (container_decl.fields_and_decls.len == 0) {
602 try stream.write("{}");
603 } else {
604 try stream.write("{\n");
605 const new_indent = indent + indent_delta;
856606
857 if (switch_node.cases.len == 0) {
858 try stack.append(RenderState { .Text = ") {}"});
859 try stack.append(RenderState { .Expression = switch_node.expr });
860 continue;
861 }
607 var it = container_decl.fields_and_decls.iterator(0);
608 while (it.next()) |decl| {
609 try stream.writeByteNTimes(' ', new_indent);
610 try renderTopLevelDecl(allocator, stream, tree, new_indent, *decl);
862611
863 try stack.append(RenderState { .Text = "}"});
864 try stack.append(RenderState.PrintIndent);
865 try stack.append(RenderState { .Indent = indent });
866 try stack.append(RenderState { .Text = "\n"});
867
868 var i = switch_node.cases.len;
869 while (i != 0) {
870 i -= 1;
871 const node = *switch_node.cases.at(i);
872 try stack.append(RenderState { .Expression = node});
873 try stack.append(RenderState.PrintIndent);
874 try stack.append(RenderState {
875 .Text = blk: {
876 if (i != 0) {
877 const prev_node = *switch_node.cases.at(i - 1);
878 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
879 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
880 if (loc.line >= 2) {
881 break :blk "\n\n";
882 }
883 }
884 break :blk "\n";
885 },
886 });
612 if (it.peek()) |next_decl| {
613 const n = if (nodeLineOffset(tree, *decl, *next_decl) >= 2) u8(2) else u8(1);
614 try stream.writeByteNTimes('\n', n);
887615 }
888 try stack.append(RenderState { .Indent = indent + indent_delta});
889 try stack.append(RenderState { .Text = ") {"});
890 try stack.append(RenderState { .Expression = switch_node.expr });
891 },
892 ast.Node.Id.SwitchCase => {
893 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
894
895 try stack.append(RenderState { .Token = switch_case.lastToken() + 1 });
896 try stack.append(RenderState { .Expression = switch_case.expr });
897 if (switch_case.payload) |payload| {
898 try stack.append(RenderState { .Text = " " });
899 try stack.append(RenderState { .Expression = payload });
900 }
901 try stack.append(RenderState { .Text = " => "});
616 }
902617
903 var i = switch_case.items.len;
904 while (i != 0) {
905 i -= 1;
906 try stack.append(RenderState { .Expression = *switch_case.items.at(i) });
618 try stream.write("\n");
619 try stream.writeByteNTimes(' ', indent);
620 try stream.write("}");
621 }
622 },
907623
908 if (i != 0) {
909 try stack.append(RenderState.PrintIndent);
910 try stack.append(RenderState { .Text = ",\n" });
911 }
912 }
624 ast.Node.Id.ErrorSetDecl => {
625 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
626
627 if (err_set_decl.decls.len == 0) {
628 try stream.write("error{}");
629 return;
630 }
631
632 if (err_set_decl.decls.len == 1) blk: {
633 const node = *err_set_decl.decls.at(0);
634
635 // if there are any doc comments or same line comments
636 // don't try to put it all on one line
637 if (node.cast(ast.Node.ErrorTag)) |tag| {
638 if (tag.doc_comments != null) break :blk;
639 } else {
640 break :blk;
641 }
642
643
644 try stream.write("error{");
645 try renderTopLevelDecl(allocator, stream, tree, indent, node);
646 try stream.write("}");
647 return;
648 }
649
650 try stream.write("error{\n");
651 const new_indent = indent + indent_delta;
652
653 var it = err_set_decl.decls.iterator(0);
654 while (it.next()) |node| {
655 try stream.writeByteNTimes(' ', new_indent);
656 try renderTopLevelDecl(allocator, stream, tree, new_indent, *node);
657 if ((*node).id != ast.Node.Id.LineComment) {
658 try stream.write(",");
659 }
660 if (it.peek()) |next_node| {
661 const n = if (nodeLineOffset(tree, *node, *next_node) >= 2) u8(2) else u8(1);
662 try stream.writeByteNTimes('\n', n);
663 }
664 }
665
666 try stream.write("\n");
667 try stream.writeByteNTimes(' ', indent);
668 try stream.write("}");
669 },
670
671 ast.Node.Id.MultilineStringLiteral => {
672 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);
673 try stream.print("\n");
674
675 var i : usize = 0;
676 while (i < multiline_str_literal.lines.len) : (i += 1) {
677 const t = *multiline_str_literal.lines.at(i);
678 try stream.writeByteNTimes(' ', indent + indent_delta);
679 try stream.print("{}", tree.tokenSlice(t));
680 }
681 try stream.writeByteNTimes(' ', indent);
682 },
683 ast.Node.Id.UndefinedLiteral => {
684 const undefined_literal = @fieldParentPtr(ast.Node.UndefinedLiteral, "base", base);
685 try stream.print("{}", tree.tokenSlice(undefined_literal.token));
686 },
687
688 ast.Node.Id.BuiltinCall => {
689 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);
690 try stream.print("{}(", tree.tokenSlice(builtin_call.builtin_token));
691
692 var it = builtin_call.params.iterator(0);
693 while (it.next()) |param_node| {
694 try renderExpression(allocator, stream, tree, indent, *param_node);
695 if (it.peek() != null) {
696 try stream.write(", ");
697 }
698 }
699 try stream.write(")");
700 },
701
702 ast.Node.Id.FnProto => {
703 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", base);
704
705 if (fn_proto.visib_token) |visib_token_index| {
706 const visib_token = tree.tokens.at(visib_token_index);
707 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);
708 try stream.print("{} ", tree.tokenSlice(visib_token_index));
709 }
710
711 if (fn_proto.extern_export_inline_token) |extern_export_inline_token| {
712 try stream.print("{} ", tree.tokenSlice(extern_export_inline_token));
713 }
714
715 if (fn_proto.lib_name) |lib_name| {
716 try renderExpression(allocator, stream, tree, indent, lib_name);
717 try stream.write(" ");
718 }
719
720 if (fn_proto.cc_token) |cc_token| {
721 try stream.print("{} ", tree.tokenSlice(cc_token));
722 }
723
724 if (fn_proto.async_attr) |async_attr| {
725 try renderExpression(allocator, stream, tree, indent, &async_attr.base);
726 try stream.write(" ");
727 }
728
729 try stream.write("fn");
730
731 if (fn_proto.name_token) |name_token| {
732 try stream.print(" {}", tree.tokenSlice(name_token));
733 }
734
735 try stream.write("(");
736
737 var it = fn_proto.params.iterator(0);
738 while (it.next()) |param_decl_node| {
739 try renderParamDecl(allocator, stream, tree, indent, *param_decl_node);
740
741 if (it.peek() != null) {
742 try stream.write(", ");
743 }
744 }
745
746 try stream.write(") ");
747
748 if (fn_proto.align_expr) |align_expr| {
749 try stream.write("align(");
750 try renderExpression(allocator, stream, tree, indent, align_expr);
751 try stream.write(") ");
752 }
753
754 switch (fn_proto.return_type) {
755 ast.Node.FnProto.ReturnType.Explicit => |node| {
756 try renderExpression(allocator, stream, tree, indent, node);
913757 },
914 ast.Node.Id.SwitchElse => {
915 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
916 try stream.print("{}", tree.tokenSlice(switch_else.token));
758 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
759 try stream.write("!");
760 try renderExpression(allocator, stream, tree, indent, node);
917761 },
918 ast.Node.Id.Else => {
919 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
920 try stream.print("{}", tree.tokenSlice(else_node.else_token));
921
922 switch (else_node.body.id) {
923 ast.Node.Id.Block, ast.Node.Id.If,
924 ast.Node.Id.For, ast.Node.Id.While,
925 ast.Node.Id.Switch => {
926 try stream.print(" ");
927 try stack.append(RenderState { .Expression = else_node.body });
928 },
929 else => {
930 try stack.append(RenderState { .Indent = indent });
931 try stack.append(RenderState { .Expression = else_node.body });
932 try stack.append(RenderState.PrintIndent);
933 try stack.append(RenderState { .Indent = indent + indent_delta });
934 try stack.append(RenderState { .Text = "\n" });
935 }
936 }
762 }
937763
938 if (else_node.payload) |payload| {
939 try stack.append(RenderState { .Text = " " });
940 try stack.append(RenderState { .Expression = payload });
941 }
942 },
943 ast.Node.Id.While => {
944 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
945 if (while_node.label) |label| {
946 try stream.print("{}: ", tree.tokenSlice(label));
947 }
764 },
948765
949 if (while_node.inline_token) |inline_token| {
950 try stream.print("{} ", tree.tokenSlice(inline_token));
951 }
766 ast.Node.Id.PromiseType => {
767 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
768 try stream.write(tree.tokenSlice(promise_type.promise_token));
769 if (promise_type.result) |result| {
770 try stream.write(tree.tokenSlice(result.arrow_token));
771 try renderExpression(allocator, stream, tree, indent, result.return_type);
772 }
773 },
952774
953 try stream.print("{} ", tree.tokenSlice(while_node.while_token));
775 ast.Node.Id.LineComment => {
776 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);
777 try stream.write(tree.tokenSlice(line_comment_node.token));
778 },
954779
955 if (while_node.@"else") |@"else"| {
956 try stack.append(RenderState { .Expression = &@"else".base });
780 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
957781
958 if (while_node.body.id == ast.Node.Id.Block) {
959 try stack.append(RenderState { .Text = " " });
960 } else {
961 try stack.append(RenderState.PrintIndent);
962 try stack.append(RenderState { .Text = "\n" });
963 }
964 }
782 ast.Node.Id.Switch => {
783 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
965784
966 if (while_node.body.id == ast.Node.Id.Block) {
967 try stack.append(RenderState { .Expression = while_node.body });
968 try stack.append(RenderState { .Text = " " });
969 } else {
970 try stack.append(RenderState { .Indent = indent });
971 try stack.append(RenderState { .Expression = while_node.body });
972 try stack.append(RenderState.PrintIndent);
973 try stack.append(RenderState { .Indent = indent + indent_delta });
974 try stack.append(RenderState { .Text = "\n" });
975 }
785 try stream.print("{} (", tree.tokenSlice(switch_node.switch_token));
786 if (switch_node.cases.len == 0) {
787 try renderExpression(allocator, stream, tree, indent, switch_node.expr);
788 try stream.write(") {}");
789 return;
790 }
976791
977 if (while_node.continue_expr) |continue_expr| {
978 try stack.append(RenderState { .Text = ")" });
979 try stack.append(RenderState { .Expression = continue_expr });
980 try stack.append(RenderState { .Text = ": (" });
981 try stack.append(RenderState { .Text = " " });
982 }
792 try renderExpression(allocator, stream, tree, indent, switch_node.expr);
793 try stream.write(") {\n");
983794
984 if (while_node.payload) |payload| {
985 try stack.append(RenderState { .Expression = payload });
986 try stack.append(RenderState { .Text = " " });
987 }
795 const new_indent = indent + indent_delta;
988796
989 try stack.append(RenderState { .Text = ")" });
990 try stack.append(RenderState { .Expression = while_node.condition });
991 try stack.append(RenderState { .Text = "(" });
992 },
993 ast.Node.Id.For => {
994 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
995 if (for_node.label) |label| {
996 try stream.print("{}: ", tree.tokenSlice(label));
997 }
797 var it = switch_node.cases.iterator(0);
798 while (it.next()) |node| {
799 try stream.writeByteNTimes(' ', new_indent);
800 try renderExpression(allocator, stream, tree, new_indent, *node);
998801
999 if (for_node.inline_token) |inline_token| {
1000 try stream.print("{} ", tree.tokenSlice(inline_token));
1001 }
802 if (it.peek()) |next_node| {
803 const n = if (nodeLineOffset(tree, *node, *next_node) >= 2) u8(2) else u8(1);
804 try stream.writeByteNTimes('\n', n);
805 }
806 }
1002807
1003 try stream.print("{} ", tree.tokenSlice(for_node.for_token));
808 try stream.write("\n");
809 try stream.writeByteNTimes(' ', indent);
810 try stream.write("}");
811 },
1004812
1005 if (for_node.@"else") |@"else"| {
1006 try stack.append(RenderState { .Expression = &@"else".base });
813 ast.Node.Id.SwitchCase => {
814 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
1007815
1008 if (for_node.body.id == ast.Node.Id.Block) {
1009 try stack.append(RenderState { .Text = " " });
1010 } else {
1011 try stack.append(RenderState.PrintIndent);
1012 try stack.append(RenderState { .Text = "\n" });
1013 }
1014 }
816 var it = switch_case.items.iterator(0);
817 while (it.next()) |node| {
818 try renderExpression(allocator, stream, tree, indent, *node);
1015819
1016 if (for_node.body.id == ast.Node.Id.Block) {
1017 try stack.append(RenderState { .Expression = for_node.body });
1018 try stack.append(RenderState { .Text = " " });
1019 } else {
1020 try stack.append(RenderState { .Indent = indent });
1021 try stack.append(RenderState { .Expression = for_node.body });
1022 try stack.append(RenderState.PrintIndent);
1023 try stack.append(RenderState { .Indent = indent + indent_delta });
1024 try stack.append(RenderState { .Text = "\n" });
1025 }
820 if (it.peek() != null) {
821 try stream.write(",\n");
822 try stream.writeByteNTimes(' ', indent);
823 }
824 }
1026825
1027 if (for_node.payload) |payload| {
1028 try stack.append(RenderState { .Expression = payload });
1029 try stack.append(RenderState { .Text = " " });
1030 }
826 try stream.write(" => ");
1031827
1032 try stack.append(RenderState { .Text = ")" });
1033 try stack.append(RenderState { .Expression = for_node.array_expr });
1034 try stack.append(RenderState { .Text = "(" });
1035 },
1036 ast.Node.Id.If => {
1037 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
1038 try stream.print("{} ", tree.tokenSlice(if_node.if_token));
1039
1040 switch (if_node.body.id) {
1041 ast.Node.Id.Block, ast.Node.Id.If,
1042 ast.Node.Id.For, ast.Node.Id.While,
1043 ast.Node.Id.Switch => {
1044 if (if_node.@"else") |@"else"| {
1045 try stack.append(RenderState { .Expression = &@"else".base });
1046
1047 if (if_node.body.id == ast.Node.Id.Block) {
1048 try stack.append(RenderState { .Text = " " });
1049 } else {
1050 try stack.append(RenderState.PrintIndent);
1051 try stack.append(RenderState { .Text = "\n" });
1052 }
1053 }
1054 },
1055 else => {
1056 if (if_node.@"else") |@"else"| {
1057 try stack.append(RenderState { .Expression = @"else".body });
1058
1059 if (@"else".payload) |payload| {
1060 try stack.append(RenderState { .Text = " " });
1061 try stack.append(RenderState { .Expression = payload });
1062 }
1063
1064 try stack.append(RenderState { .Text = " " });
1065 try stack.append(RenderState { .Text = tree.tokenSlice(@"else".else_token) });
1066 try stack.append(RenderState { .Text = " " });
1067 }
828 if (switch_case.payload) |payload| {
829 try renderExpression(allocator, stream, tree, indent, payload);
830 try stream.write(" ");
831 }
832
833 try renderExpression(allocator, stream, tree, indent, switch_case.expr);
834 try renderToken(tree, stream, switch_case.lastToken() + 1, indent, true);
835 },
836 ast.Node.Id.SwitchElse => {
837 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
838 try stream.print("{}", tree.tokenSlice(switch_else.token));
839 },
840 ast.Node.Id.Else => {
841 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
842 try stream.print("{}", tree.tokenSlice(else_node.else_token));
843
844 const block_body = switch (else_node.body.id) {
845 ast.Node.Id.Block, ast.Node.Id.If,
846 ast.Node.Id.For, ast.Node.Id.While,
847 ast.Node.Id.Switch => true,
848 else => false,
849 };
850
851 if (block_body) {
852 try stream.write(" ");
853 }
854
855 if (else_node.payload) |payload| {
856 try renderExpression(allocator, stream, tree, indent, payload);
857 try stream.write(" ");
858 }
859
860 if (block_body) {
861 try renderExpression(allocator, stream, tree, indent, else_node.body);
862 } else {
863 try stream.write("\n");
864 try stream.writeByteNTimes(' ', indent + indent_delta);
865 try renderExpression(allocator, stream, tree, indent, else_node.body);
866 }
867 },
868
869 ast.Node.Id.While => {
870 const while_node = @fieldParentPtr(ast.Node.While, "base", base);
871
872 if (while_node.label) |label| {
873 try stream.print("{}: ", tree.tokenSlice(label));
874 }
875
876 if (while_node.inline_token) |inline_token| {
877 try stream.print("{} ", tree.tokenSlice(inline_token));
878 }
879
880 try stream.print("{} (", tree.tokenSlice(while_node.while_token));
881 try renderExpression(allocator, stream, tree, indent, while_node.condition);
882 try stream.write(")");
883
884 if (while_node.payload) |payload| {
885 try stream.write(" ");
886 try renderExpression(allocator, stream, tree, indent, payload);
887 }
888
889 if (while_node.continue_expr) |continue_expr| {
890 try stream.write(" : (");
891 try renderExpression(allocator, stream, tree, indent, continue_expr);
892 try stream.write(")");
893 }
894
895 if (while_node.body.id == ast.Node.Id.Block) {
896 try stream.write(" ");
897 try renderExpression(allocator, stream, tree, indent, while_node.body);
898 } else {
899 try stream.write("\n");
900 try stream.writeByteNTimes(' ', indent + indent_delta);
901 try renderExpression(allocator, stream, tree, indent, while_node.body);
902 }
903
904 if (while_node.@"else") |@"else"| {
905 if (while_node.body.id == ast.Node.Id.Block) {
906 try stream.write(" ");
907 } else {
908 try stream.write("\n");
909 try stream.writeByteNTimes(' ', indent);
910 }
911
912 try renderExpression(allocator, stream, tree, indent, &@"else".base);
913 }
914 },
915
916 ast.Node.Id.For => {
917 const for_node = @fieldParentPtr(ast.Node.For, "base", base);
918 if (for_node.label) |label| {
919 try stream.print("{}: ", tree.tokenSlice(label));
920 }
921
922 if (for_node.inline_token) |inline_token| {
923 try stream.print("{} ", tree.tokenSlice(inline_token));
924 }
925
926 try stream.print("{} (", tree.tokenSlice(for_node.for_token));
927 try renderExpression(allocator, stream, tree, indent, for_node.array_expr);
928 try stream.write(")");
929
930 if (for_node.payload) |payload| {
931 try stream.write(" ");
932 try renderExpression(allocator, stream, tree, indent, payload);
933 }
934
935 if (for_node.body.id == ast.Node.Id.Block) {
936 try stream.write(" ");
937 try renderExpression(allocator, stream, tree, indent, for_node.body);
938 } else {
939 try stream.write("\n");
940 try stream.writeByteNTimes(' ', indent + indent_delta);
941 try renderExpression(allocator, stream, tree, indent, for_node.body);
942 }
943
944 if (for_node.@"else") |@"else"| {
945 if (for_node.body.id == ast.Node.Id.Block) {
946 try stream.write(" ");
947 } else {
948 try stream.write("\n");
949 try stream.writeByteNTimes(' ', indent);
950 }
951
952 try renderExpression(allocator, stream, tree, indent, &@"else".base);
953 }
954 },
955
956 ast.Node.Id.If => {
957 const if_node = @fieldParentPtr(ast.Node.If, "base", base);
958 try stream.print("{} (", tree.tokenSlice(if_node.if_token));
959
960 try renderExpression(allocator, stream, tree, indent, if_node.condition);
961 try renderToken(tree, stream, if_node.condition.lastToken() + 1, indent, false);
962
963 if (if_node.payload) |payload| {
964 try renderExpression(allocator, stream, tree, indent, payload);
965 try stream.write(" ");
966 }
967
968 try renderExpression(allocator, stream, tree, indent, if_node.body);
969
970 switch (if_node.body.id) {
971 ast.Node.Id.Block, ast.Node.Id.If, ast.Node.Id.For, ast.Node.Id.While, ast.Node.Id.Switch => {
972 if (if_node.@"else") |@"else"| {
973 if (if_node.body.id == ast.Node.Id.Block) {
974 try stream.write(" ");
975 } else {
976 try stream.write("\n");
977 try stream.writeByteNTimes(' ', indent);
1068978 }
979
980 try renderExpression(allocator, stream, tree, indent, &@"else".base);
1069981 }
982 },
983 else => {
984 if (if_node.@"else") |@"else"| {
985 try stream.print(" {} ", tree.tokenSlice(@"else".else_token));
1070986
1071 try stack.append(RenderState { .Expression = if_node.body });
987 if (@"else".payload) |payload| {
988 try renderExpression(allocator, stream, tree, indent, payload);
989 try stream.write(" ");
990 }
1072991
1073 if (if_node.payload) |payload| {
1074 try stack.append(RenderState { .Text = " " });
1075 try stack.append(RenderState { .Expression = payload });
992 try renderExpression(allocator, stream, tree, indent, @"else".body);
1076993 }
994 }
995 }
996 },
1077997
1078 try stack.append(RenderState { .NonBreakToken = if_node.condition.lastToken() + 1 });
1079 try stack.append(RenderState { .Expression = if_node.condition });
1080 try stack.append(RenderState { .Text = "(" });
1081 },
1082 ast.Node.Id.Asm => {
1083 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
1084 try stream.print("{} ", tree.tokenSlice(asm_node.asm_token));
998 ast.Node.Id.Asm => {
999 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
1000 try stream.print("{} ", tree.tokenSlice(asm_node.asm_token));
10851001
1086 if (asm_node.volatile_token) |volatile_token| {
1087 try stream.print("{} ", tree.tokenSlice(volatile_token));
1088 }
1002 if (asm_node.volatile_token) |volatile_token| {
1003 try stream.print("{} ", tree.tokenSlice(volatile_token));
1004 }
10891005
1090 try stack.append(RenderState { .Indent = indent });
1091 try stack.append(RenderState { .Text = ")" });
1092 {
1093 var i = asm_node.clobbers.len;
1094 while (i != 0) {
1095 i -= 1;
1096 try stack.append(RenderState { .Expression = *asm_node.clobbers.at(i) });
1097
1098 if (i != 0) {
1099 try stack.append(RenderState { .Text = ", " });
1100 }
1101 }
1006 try stream.print("(");
1007 try renderExpression(allocator, stream, tree, indent, asm_node.template);
1008 try stream.print("\n");
1009 const indent_once = indent + indent_delta;
1010 try stream.writeByteNTimes(' ', indent_once);
1011 try stream.print(": ");
1012 const indent_extra = indent_once + 2;
1013
1014 {
1015 var it = asm_node.outputs.iterator(0);
1016 while (it.next()) |asm_output| {
1017 const node = &(*asm_output).base;
1018 try renderExpression(allocator, stream, tree, indent_extra, node);
1019
1020 if (it.peek()) |next_asm_output| {
1021 const next_node = &(*next_asm_output).base;
1022 const n = if (nodeLineOffset(tree, node, next_node) >= 2) u8(2) else u8(1);
1023 try stream.writeByte(',');
1024 try stream.writeByteNTimes('\n', n);
1025 try stream.writeByteNTimes(' ', indent_extra);
11021026 }
1103 try stack.append(RenderState { .Text = ": " });
1104 try stack.append(RenderState.PrintIndent);
1105 try stack.append(RenderState { .Indent = indent + indent_delta });
1106 try stack.append(RenderState { .Text = "\n" });
1107 {
1108 var i = asm_node.inputs.len;
1109 while (i != 0) {
1110 i -= 1;
1111 const node = *asm_node.inputs.at(i);
1112 try stack.append(RenderState { .Expression = &node.base});
1113
1114 if (i != 0) {
1115 try stack.append(RenderState.PrintIndent);
1116 try stack.append(RenderState {
1117 .Text = blk: {
1118 const prev_node = *asm_node.inputs.at(i - 1);
1119 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
1120 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
1121 if (loc.line >= 2) {
1122 break :blk "\n\n";
1123 }
1124 break :blk "\n";
1125 },
1126 });
1127 try stack.append(RenderState { .Text = "," });
1128 }
1129 }
1027 }
1028 }
1029
1030 try stream.write("\n");
1031 try stream.writeByteNTimes(' ', indent_once);
1032 try stream.write(": ");
1033
1034 {
1035 var it = asm_node.inputs.iterator(0);
1036 while (it.next()) |asm_input| {
1037 const node = &(*asm_input).base;
1038 try renderExpression(allocator, stream, tree, indent_extra, node);
1039
1040 if (it.peek()) |next_asm_input| {
1041 const next_node = &(*next_asm_input).base;
1042 const n = if (nodeLineOffset(tree, node, next_node) >= 2) u8(2) else u8(1);
1043 try stream.writeByte(',');
1044 try stream.writeByteNTimes('\n', n);
1045 try stream.writeByteNTimes(' ', indent_extra);
11301046 }
1131 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
1132 try stack.append(RenderState { .Text = ": "});
1133 try stack.append(RenderState.PrintIndent);
1134 try stack.append(RenderState { .Indent = indent + indent_delta});
1135 try stack.append(RenderState { .Text = "\n" });
1136 {
1137 var i = asm_node.outputs.len;
1138 while (i != 0) {
1139 i -= 1;
1140 const node = *asm_node.outputs.at(i);
1141 try stack.append(RenderState { .Expression = &node.base});
1142
1143 if (i != 0) {
1144 try stack.append(RenderState.PrintIndent);
1145 try stack.append(RenderState {
1146 .Text = blk: {
1147 const prev_node = *asm_node.outputs.at(i - 1);
1148 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;
1149 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());
1150 if (loc.line >= 2) {
1151 break :blk "\n\n";
1152 }
1153 break :blk "\n";
1154 },
1155 });
1156 try stack.append(RenderState { .Text = "," });
1157 }
1158 }
1047 }
1048 }
1049
1050 try stream.write("\n");
1051 try stream.writeByteNTimes(' ', indent_once);
1052 try stream.write(": ");
1053
1054 {
1055 var it = asm_node.clobbers.iterator(0);
1056 while (it.next()) |node| {
1057 try renderExpression(allocator, stream, tree, indent_once, *node);
1058
1059 if (it.peek() != null) {
1060 try stream.write(", ");
11591061 }
1160 try stack.append(RenderState { .Indent = indent + indent_delta + 2});
1161 try stack.append(RenderState { .Text = ": "});
1162 try stack.append(RenderState.PrintIndent);
1163 try stack.append(RenderState { .Indent = indent + indent_delta});
1164 try stack.append(RenderState { .Text = "\n" });
1165 try stack.append(RenderState { .Expression = asm_node.template });
1166 try stack.append(RenderState { .Text = "(" });
1167 },
1168 ast.Node.Id.AsmInput => {
1169 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
1170
1171 try stack.append(RenderState { .Text = ")"});
1172 try stack.append(RenderState { .Expression = asm_input.expr});
1173 try stack.append(RenderState { .Text = " ("});
1174 try stack.append(RenderState { .Expression = asm_input.constraint });
1175 try stack.append(RenderState { .Text = "] "});
1176 try stack.append(RenderState { .Expression = asm_input.symbolic_name });
1177 try stack.append(RenderState { .Text = "["});
1062 }
1063 }
1064
1065 try stream.write(")");
1066 },
1067
1068 ast.Node.Id.AsmInput => {
1069 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
1070
1071 try stream.write("[");
1072 try renderExpression(allocator, stream, tree, indent, asm_input.symbolic_name);
1073 try stream.write("] ");
1074 try renderExpression(allocator, stream, tree, indent, asm_input.constraint);
1075 try stream.write(" (");
1076 try renderExpression(allocator, stream, tree, indent, asm_input.expr);
1077 try stream.write(")");
1078 },
1079
1080 ast.Node.Id.AsmOutput => {
1081 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
1082
1083 try stream.write("[");
1084 try renderExpression(allocator, stream, tree, indent, asm_output.symbolic_name);
1085 try stream.write("] ");
1086 try renderExpression(allocator, stream, tree, indent, asm_output.constraint);
1087 try stream.write(" (");
1088
1089 switch (asm_output.kind) {
1090 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
1091 try renderExpression(allocator, stream, tree, indent, &variable_name.base);
11781092 },
1179 ast.Node.Id.AsmOutput => {
1180 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);
1181
1182 try stack.append(RenderState { .Text = ")"});
1183 switch (asm_output.kind) {
1184 ast.Node.AsmOutput.Kind.Variable => |variable_name| {
1185 try stack.append(RenderState { .Expression = &variable_name.base});
1186 },
1187 ast.Node.AsmOutput.Kind.Return => |return_type| {
1188 try stack.append(RenderState { .Expression = return_type});
1189 try stack.append(RenderState { .Text = "-> "});
1190 },
1191 }
1192 try stack.append(RenderState { .Text = " ("});
1193 try stack.append(RenderState { .Expression = asm_output.constraint });
1194 try stack.append(RenderState { .Text = "] "});
1195 try stack.append(RenderState { .Expression = asm_output.symbolic_name });
1196 try stack.append(RenderState { .Text = "["});
1093 ast.Node.AsmOutput.Kind.Return => |return_type| {
1094 try stream.write("-> ");
1095 try renderExpression(allocator, stream, tree, indent, return_type);
11971096 },
1097 }
11981098
1199 ast.Node.Id.StructField,
1200 ast.Node.Id.UnionTag,
1201 ast.Node.Id.EnumTag,
1202 ast.Node.Id.ErrorTag,
1203 ast.Node.Id.Root,
1204 ast.Node.Id.VarDecl,
1205 ast.Node.Id.Use,
1206 ast.Node.Id.TestDecl,
1207 ast.Node.Id.ParamDecl => unreachable,
1208 },
1209 RenderState.Statement => |base| {
1210 switch (base.id) {
1211 ast.Node.Id.VarDecl => {
1212 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
1213 try stack.append(RenderState { .VarDecl = var_decl});
1214 },
1215 else => {
1216 try stack.append(RenderState { .MaybeSemiColon = base });
1217 try stack.append(RenderState { .Expression = base });
1218 },
1219 }
1220 },
1221 RenderState.Indent => |new_indent| indent = new_indent,
1222 RenderState.PrintIndent => try stream.writeByteNTimes(' ', indent),
1223 RenderState.Token => |token_index| try renderToken(tree, stream, token_index, indent, true),
1224 RenderState.NonBreakToken => |token_index| try renderToken(tree, stream, token_index, indent, false),
1225 RenderState.MaybeSemiColon => |base| {
1226 if (base.requireSemiColon()) {
1227 const semicolon_index = base.lastToken() + 1;
1228 assert(tree.tokens.at(semicolon_index).id == Token.Id.Semicolon);
1229 try renderToken(tree, stream, semicolon_index, indent, true);
1230 }
1231 },
1099 try stream.write(")");
1100 },
1101
1102 ast.Node.Id.StructField,
1103 ast.Node.Id.UnionTag,
1104 ast.Node.Id.EnumTag,
1105 ast.Node.Id.ErrorTag,
1106 ast.Node.Id.Root,
1107 ast.Node.Id.VarDecl,
1108 ast.Node.Id.Use,
1109 ast.Node.Id.TestDecl,
1110 ast.Node.Id.ParamDecl => unreachable,
1111 }
1112}
1113
1114fn renderVarDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, var_decl: &ast.Node.VarDecl) (@typeOf(stream).Child.Error || Error)!void {
1115 if (var_decl.visib_token) |visib_token| {
1116 try stream.print("{} ", tree.tokenSlice(visib_token));
1117 }
1118
1119 if (var_decl.extern_export_token) |extern_export_token| {
1120 try stream.print("{} ", tree.tokenSlice(extern_export_token));
1121
1122 if (var_decl.lib_name) |lib_name| {
1123 try renderExpression(allocator, stream, tree, indent, lib_name);
1124 try stream.write(" ");
12321125 }
12331126 }
1127
1128 if (var_decl.comptime_token) |comptime_token| {
1129 try stream.print("{} ", tree.tokenSlice(comptime_token));
1130 }
1131
1132 try stream.print("{} {}", tree.tokenSlice(var_decl.mut_token), tree.tokenSlice(var_decl.name_token));
1133
1134 if (var_decl.type_node) |type_node| {
1135 try stream.write(": ");
1136 try renderExpression(allocator, stream, tree, indent, type_node);
1137 }
1138
1139 if (var_decl.align_node) |align_node| {
1140 try stream.write(" align(");
1141 try renderExpression(allocator, stream, tree, indent, align_node);
1142 try stream.write(")");
1143 }
1144
1145 if (var_decl.init_node) |init_node| {
1146 const text = if (init_node.id == ast.Node.Id.MultilineStringLiteral) " =" else " = ";
1147 try stream.write(text);
1148 try renderExpression(allocator, stream, tree, indent, init_node);
1149 }
1150
1151 try renderToken(tree, stream, var_decl.semicolon_token, indent, true);
1152}
1153
1154fn maybeRenderSemicolon(stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
1155 if (base.requireSemiColon()) {
1156 const semicolon_index = base.lastToken() + 1;
1157 assert(tree.tokens.at(semicolon_index).id == Token.Id.Semicolon);
1158 try renderToken(tree, stream, semicolon_index, indent, true);
1159 }
1160}
1161
1162fn renderParamDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
1163 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);
1164 if (param_decl.comptime_token) |comptime_token| {
1165 try stream.print("{} ", tree.tokenSlice(comptime_token));
1166 }
1167 if (param_decl.noalias_token) |noalias_token| {
1168 try stream.print("{} ", tree.tokenSlice(noalias_token));
1169 }
1170 if (param_decl.name_token) |name_token| {
1171 try stream.print("{}: ", tree.tokenSlice(name_token));
1172 }
1173 if (param_decl.var_args_token) |var_args_token| {
1174 try stream.print("{}", tree.tokenSlice(var_args_token));
1175 } else {
1176 try renderExpression(allocator, stream, tree, indent, param_decl.type_node);
1177 }
1178}
1179
1180fn renderStatement(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, base: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
1181 switch (base.id) {
1182 ast.Node.Id.VarDecl => {
1183 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);
1184 try renderVarDecl(allocator, stream, tree, indent, var_decl);
1185 },
1186 else => {
1187 try renderExpression(allocator, stream, tree, indent, base);
1188 try maybeRenderSemicolon(stream, tree, indent, base);
1189 },
1190 }
12341191}
12351192
1236fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent: usize, line_break: bool) !void {
1193fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent: usize, line_break: bool) (@typeOf(stream).Child.Error || Error)!void {
12371194 const token = tree.tokens.at(token_index);
12381195 try stream.write(tree.tokenSlicePtr(token));
12391196
......@@ -1255,7 +1212,7 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent
12551212 }
12561213}
12571214
1258fn renderComments(tree: &ast.Tree, stream: var, node: var, indent: usize) !void {
1215fn renderComments(tree: &ast.Tree, stream: var, node: var, indent: usize) (@typeOf(stream).Child.Error || Error)!void {
12591216 const comment = node.doc_comments ?? return;
12601217 var it = comment.lines.iterator(0);
12611218 while (it.next()) |line_token_index| {