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 @@...@@ -1,29 +1,23 @@
1const std = @import("../index.zig");1const std = @import("../index.zig");
2const builtin = @import("builtin");
2const assert = std.debug.assert;3const assert = std.debug.assert;
3const mem = std.mem;4const mem = std.mem;
4const ast = std.zig.ast;5const ast = std.zig.ast;
5const Token = std.zig.Token;6const Token = std.zig.Token;
67
7const RenderState = union(enum) {8const indent_delta = 4;
8 TopLevelDecl: &ast.Node,9
9 ParamDecl: &ast.Node,10pub const Error = error {
10 Text: []const u8,11 /// Ran out of memory allocating call stack frames to complete rendering.
11 Expression: &ast.Node,12 OutOfMemory,
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,
19};13};
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 {
24 var it = tree.root_node.decls.iterator(0);18 var it = tree.root_node.decls.iterator(0);
25 while (it.next()) |decl| {19 while (it.next()) |decl| {
26 try renderTopLevelDecl(allocator, stream, tree, *decl);20 try renderTopLevelDecl(allocator, stream, tree, 0, *decl);
27 if (it.peek()) |next_decl| {21 if (it.peek()) |next_decl| {
28 const n = if (nodeLineOffset(tree, *decl, *next_decl) >= 2) u8(2) else u8(1);22 const n = if (nodeLineOffset(tree, *decl, *next_decl) >= 2) u8(2) else u8(1);
29 try stream.writeByteNTimes('\n', n);23 try stream.writeByteNTimes('\n', n);
...@@ -38,1202 +32,1165 @@ fn nodeLineOffset(tree: &ast.Tree, a: &ast.Node, b: &ast.Node) usize {...@@ -38,1202 +32,1165 @@ fn nodeLineOffset(tree: &ast.Tree, a: &ast.Node, b: &ast.Node) usize {
38 return loc.line;32 return loc.line;
39}33}
4034
41fn renderTopLevelDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, decl_ptr: &ast.Node) !void {35fn renderTopLevelDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, decl: &ast.Node) (@typeOf(stream).Child.Error || Error)!void {
42 var stack = std.ArrayList(RenderState).init(allocator);36 switch (decl.id) {
43 defer stack.deinit();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;43 if (fn_proto.body_node) |body_node| {
48 while (stack.popOrNull()) |state| {44 try stream.write(" ");
49 switch (state) {45 try renderExpression(allocator, stream, tree, indent, body_node);
50 RenderState.TopLevelDecl => |decl| {46 } else {
51 switch (decl.id) {47 try stream.write(";");
52 ast.Node.Id.FnProto => {48 }
53 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);49 },
54 try renderComments(tree, stream, fn_proto, indent);50 ast.Node.Id.Use => {
51 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);
5552
56 if (fn_proto.body_node) |body_node| {53 if (use_decl.visib_token) |visib_token| {
57 stack.append(RenderState { .Expression = body_node}) catch unreachable;54 try stream.print("{} ", tree.tokenSlice(visib_token));
58 try stack.append(RenderState { .Text = " "});55 }
59 } else {56 try stream.write("use ");
60 stack.append(RenderState { .Text = ";" }) catch unreachable;57 try renderExpression(allocator, stream, tree, indent, use_decl.expr);
61 }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 });97 if (tag.value_expr) |value_expr| {
64 },98 try stream.print(" = ");
65 ast.Node.Id.Use => {99 try renderExpression(allocator, stream, tree, indent, value_expr);
66 const use_decl = @fieldParentPtr(ast.Node.Use, "base", decl);100 }
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 }
108101
109 if (tag.type_expr) |type_expr| {102 try stream.write(",");
110 try stream.print(": ");103 },
111 try stack.append(RenderState { .Expression = type_expr});104 ast.Node.Id.EnumTag => {
112 }105 const tag = @fieldParentPtr(ast.Node.EnumTag, "base", decl);
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) });
161106
162 if (var_decl.comptime_token) |comptime_token| {107 try renderComments(tree, stream, tag, indent);
163 try stack.append(RenderState { .Text = " " });108 try stream.print("{}", tree.tokenSlice(tag.name_token));
164 try stack.append(RenderState { .Text = tree.tokenSlice(comptime_token) });
165 }
166109
167 if (var_decl.extern_export_token) |extern_export_token| {110 if (tag.value) |value| {
168 if (var_decl.lib_name != null) {111 try stream.print(" = ");
169 try stack.append(RenderState { .Text = " " });112 try renderExpression(allocator, stream, tree, indent, value);
170 try stack.append(RenderState { .Expression = ??var_decl.lib_name });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);
171 }162 }
172 try stack.append(RenderState { .Text = " " });
173 try stack.append(RenderState { .Text = tree.tokenSlice(extern_export_token) });
174 }163 }
175164
176 if (var_decl.visib_token) |visib_token| {165 try stream.write("\n");
177 try stack.append(RenderState { .Text = " " });166 try stream.writeByteNTimes(' ', indent);
178 try stack.append(RenderState { .Text = tree.tokenSlice(visib_token) });167 try stream.write("}");
179 }168 }
180 },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| {197 if (suspend_node.payload) |payload| {
183 const param_decl = @fieldParentPtr(ast.Node.ParamDecl, "base", base);198 try stream.write(" ");
184 if (param_decl.comptime_token) |comptime_token| {199 try renderExpression(allocator, stream, tree, indent, payload);
185 try stream.print("{} ", tree.tokenSlice(comptime_token));200 }
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 }
212201
213 if (block.statements.len == 0) {202 if (suspend_node.body) |body| {
214 try stream.write("{}");203 try stream.write(" ");
215 } else {204 try renderExpression(allocator, stream, tree, indent, body);
216 try stream.write("{");205 }
217 try stack.append(RenderState { .Text = "}"});206
218 try stack.append(RenderState.PrintIndent);207 },
219 try stack.append(RenderState { .Indent = indent});208
220 try stack.append(RenderState { .Text = "\n"});209 ast.Node.Id.InfixOp => {
221 var i = block.statements.len;210 const infix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);
222 while (i != 0) {211
223 i -= 1;212 try renderExpression(allocator, stream, tree, indent, infix_op_node.lhs);
224 const statement_node = *block.statements.at(i);213
225 try stack.append(RenderState { .Statement = statement_node});214 const text = switch (infix_op_node.op) {
226 try stack.append(RenderState.PrintIndent);215 ast.Node.InfixOp.Op.Add => " + ",
227 try stack.append(RenderState { .Indent = indent + indent_delta});216 ast.Node.InfixOp.Op.AddWrap => " +% ",
228 try stack.append(RenderState {217 ast.Node.InfixOp.Op.ArrayCat => " ++ ",
229 .Text = blk: {218 ast.Node.InfixOp.Op.ArrayMult => " ** ",
230 if (i != 0) {219 ast.Node.InfixOp.Op.Assign => " = ",
231 const prev_node = *block.statements.at(i - 1);220 ast.Node.InfixOp.Op.AssignBitAnd => " &= ",
232 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;221 ast.Node.InfixOp.Op.AssignBitOr => " |= ",
233 const loc = tree.tokenLocation(prev_node_last_token_end, statement_node.firstToken());222 ast.Node.InfixOp.Op.AssignBitShiftLeft => " <<= ",
234 if (loc.line >= 2) {223 ast.Node.InfixOp.Op.AssignBitShiftRight => " >>= ",
235 break :blk "\n\n";224 ast.Node.InfixOp.Op.AssignBitXor => " ^= ",
236 }225 ast.Node.InfixOp.Op.AssignDiv => " /= ",
237 }226 ast.Node.InfixOp.Op.AssignMinus => " -= ",
238 break :blk "\n";227 ast.Node.InfixOp.Op.AssignMinusWrap => " -%= ",
239 },228 ast.Node.InfixOp.Op.AssignMod => " %= ",
240 });229 ast.Node.InfixOp.Op.AssignPlus => " += ",
241 }230 ast.Node.InfixOp.Op.AssignPlusWrap => " +%= ",
242 }231 ast.Node.InfixOp.Op.AssignTimes => " *= ",
243 },232 ast.Node.InfixOp.Op.AssignTimesWarp => " *%= ",
244 ast.Node.Id.Defer => {233 ast.Node.InfixOp.Op.BangEqual => " != ",
245 const defer_node = @fieldParentPtr(ast.Node.Defer, "base", base);234 ast.Node.InfixOp.Op.BitAnd => " & ",
246 try stream.print("{} ", tree.tokenSlice(defer_node.defer_token));235 ast.Node.InfixOp.Op.BitOr => " | ",
247 try stack.append(RenderState { .Expression = defer_node.expr });236 ast.Node.InfixOp.Op.BitShiftLeft => " << ",
248 },237 ast.Node.InfixOp.Op.BitShiftRight => " >> ",
249 ast.Node.Id.Comptime => {238 ast.Node.InfixOp.Op.BitXor => " ^ ",
250 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", base);239 ast.Node.InfixOp.Op.BoolAnd => " and ",
251 try stream.print("{} ", tree.tokenSlice(comptime_node.comptime_token));240 ast.Node.InfixOp.Op.BoolOr => " or ",
252 try stack.append(RenderState { .Expression = comptime_node.expr });241 ast.Node.InfixOp.Op.Div => " / ",
253 },242 ast.Node.InfixOp.Op.EqualEqual => " == ",
254 ast.Node.Id.AsyncAttribute => {243 ast.Node.InfixOp.Op.ErrorUnion => "!",
255 const async_attr = @fieldParentPtr(ast.Node.AsyncAttribute, "base", base);244 ast.Node.InfixOp.Op.GreaterOrEqual => " >= ",
256 try stream.print("{}", tree.tokenSlice(async_attr.async_token));245 ast.Node.InfixOp.Op.GreaterThan => " > ",
257246 ast.Node.InfixOp.Op.LessOrEqual => " <= ",
258 if (async_attr.allocator_type) |allocator_type| {247 ast.Node.InfixOp.Op.LessThan => " < ",
259 try stack.append(RenderState { .Text = ">" });248 ast.Node.InfixOp.Op.MergeErrorSets => " || ",
260 try stack.append(RenderState { .Expression = allocator_type });249 ast.Node.InfixOp.Op.Mod => " % ",
261 try stack.append(RenderState { .Text = "<" });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(" ");
262 }262 }
263 break :blk "";
263 },264 },
264 ast.Node.Id.Suspend => {265 };
265 const suspend_node = @fieldParentPtr(ast.Node.Suspend, "base", base);266
266 if (suspend_node.label) |label| {267 try stream.write(text);
267 try stream.print("{}: ", tree.tokenSlice(label));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(") ");
268 }281 }
269 try stream.print("{}", tree.tokenSlice(suspend_node.suspend_token));282 if (addr_of_info.const_token != null) {
270283 try stream.write("const ");
271 if (suspend_node.body) |body| {
272 try stack.append(RenderState { .Expression = body });
273 try stack.append(RenderState { .Text = " " });
274 }284 }
275285 if (addr_of_info.volatile_token != null) {
276 if (suspend_node.payload) |payload| {286 try stream.write("volatile ");
277 try stack.append(RenderState { .Expression = payload });
278 try stack.append(RenderState { .Text = " " });
279 }287 }
280 },288 },
281 ast.Node.Id.InfixOp => {289 ast.Node.PrefixOp.Op.SliceType => |addr_of_info| {
282 const prefix_op_node = @fieldParentPtr(ast.Node.InfixOp, "base", base);290 try stream.write("[]");
283 try stack.append(RenderState { .Expression = prefix_op_node.rhs });291 if (addr_of_info.align_expr) |align_expr| {
284292 try stream.print("align(");
285 if (prefix_op_node.op == ast.Node.InfixOp.Op.Catch) {293 try renderExpression(allocator, stream, tree, indent, align_expr);
286 if (prefix_op_node.op.Catch) |payload| {294 try stream.print(") ");
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 });
339 }295 }
340 try stack.append(RenderState { .Expression = prefix_op_node.lhs });296 if (addr_of_info.const_token != null) {
341 },297 try stream.print("const ");
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 "),
390 }298 }
391 },299 if (addr_of_info.volatile_token != null) {
392 ast.Node.Id.SuffixOp => {300 try stream.print("volatile ");
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 },
506 }301 }
507 },302 },
508 ast.Node.Id.ControlFlowExpression => {303 ast.Node.PrefixOp.Op.ArrayType => |array_index| {
509 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);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| {324 ast.Node.Id.SuffixOp => {
512 try stack.append(RenderState { .Expression = rhs });325 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", base);
513 try stack.append(RenderState { .Text = " " });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(" ");
514 }332 }
515333
516 switch (flow_expr.kind) {334 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
517 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {335 try stream.write("(");
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 },
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 }
535 }343 }
344
345 try stream.write(")");
536 },346 },
537 ast.Node.Id.Payload => {347
538 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);348 ast.Node.SuffixOp.Op.ArrayAccess => |index_expr| {
539 try stack.append(RenderState { .Text = "|"});349 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
540 try stack.append(RenderState { .Expression = payload.error_symbol });350 try stream.write("[");
541 try stack.append(RenderState { .Text = "|"});351 try renderExpression(allocator, stream, tree, indent, index_expr);
352 try stream.write("]");
542 },353 },
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| {355 @TagType(ast.Node.SuffixOp.Op).Slice => |range| {
549 try stack.append(RenderState { .Text = tree.tokenSlice(ptr_token) });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);
550 }362 }
551363 try stream.write("]");
552 try stack.append(RenderState { .Text = "|"});
553 },364 },
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| {366 ast.Node.SuffixOp.Op.StructInitializer => |*field_inits| {
559 try stack.append(RenderState { .Expression = index_symbol });367 if (field_inits.len == 0) {
560 try stack.append(RenderState { .Text = ", "});368 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
369 try stream.write("{}");
370 return;
561 }371 }
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| {376 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
566 try stack.append(RenderState { .Text = tree.tokenSlice(ptr_token) });377 try stream.write("{ ");
378 try renderExpression(allocator, stream, tree, indent, field_init);
379 try stream.write(" }");
380 return;
567 }381 }
568382
569 try stack.append(RenderState { .Text = "|"});383 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
570 },384 try stream.write("{\n");
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);
624385
625 switch (container_decl.layout) {386 const new_indent = indent + indent_delta;
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 }
630387
631 switch (container_decl.kind) {388 var it = field_inits.iterator(0);
632 ast.Node.ContainerDecl.Kind.Struct => try stream.print("struct"),389 while (it.next()) |field_init| {
633 ast.Node.ContainerDecl.Kind.Enum => try stream.print("enum"),390 try stream.writeByteNTimes(' ', new_indent);
634 ast.Node.ContainerDecl.Kind.Union => try stream.print("union"),391 try renderExpression(allocator, stream, tree, new_indent, *field_init);
635 }392 if ((*field_init).id != ast.Node.Id.LineComment) {
636393 try stream.write(",");
637 if (container_decl.fields_and_decls.len == 0) {394 }
638 try stack.append(RenderState { .Text = "{}"});395 if (it.peek()) |next_field_init| {
639 } else {396 const n = if (nodeLineOffset(tree, *field_init, *next_field_init) >= 2) u8(2) else u8(1);
640 try stack.append(RenderState { .Text = "}"});397 try stream.writeByteNTimes('\n', n);
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 });
664 }398 }
665 try stack.append(RenderState { .Indent = indent + indent_delta});
666 try stack.append(RenderState { .Text = "{"});
667 }399 }
668400
669 switch (container_decl.init_arg_expr) {401 try stream.write("\n");
670 ast.Node.ContainerDecl.InitArg.None => try stack.append(RenderState { .Text = " "}),402 try stream.writeByteNTimes(' ', indent);
671 ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| {403 try stream.write("}");
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 }
686 },404 },
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) {406 ast.Node.SuffixOp.Op.ArrayInitializer => |*exprs| {
691 try stream.write("error{}");407
692 continue;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;
693 }421 }
694422
695 if (err_set_decl.decls.len == 1) blk: {423 try renderExpression(allocator, stream, tree, indent, suffix_op.lhs);
696 const node = *err_set_decl.decls.at(0);
697424
698 // if there are any doc comments or same line comments425 const new_indent = indent + indent_delta;
699 // don't try to put it all on one line426 try stream.write("{\n");
700 if (node.cast(ast.Node.ErrorTag)) |tag| {
701 if (tag.doc_comments != null) break :blk;
702 } else {
703 break :blk;
704 }
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{");434 if (it.peek()) |next_expr| {
708 try stack.append(RenderState { .Text = "}" });435 const n = if (nodeLineOffset(tree, *expr, *next_expr) >= 2) u8(2) else u8(1);
709 try stack.append(RenderState { .TopLevelDecl = node });436 try stream.writeByteNTimes('\n', n);
710 continue;437 }
711 }438 }
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 = "}"});447 ast.Node.Id.ControlFlowExpression => {
716 try stack.append(RenderState.PrintIndent);448 const flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", base);
717 try stack.append(RenderState { .Indent = indent });
718 try stack.append(RenderState { .Text = "\n"});
719449
720 var i = err_set_decl.decls.len;450 switch (flow_expr.kind) {
721 while (i != 0) {451 ast.Node.ControlFlowExpression.Kind.Break => |maybe_label| {
722 i -= 1;452 try stream.print("break");
723 const node = *err_set_decl.decls.at(i);453 if (maybe_label) |label| {
724 if (node.id != ast.Node.Id.LineComment) {454 try stream.print(" :");
725 try stack.append(RenderState { .Text = "," });455 try renderExpression(allocator, stream, tree, indent, label);
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 });
742 }456 }
743 try stack.append(RenderState { .Indent = indent + indent_delta});
744 },457 },
745 ast.Node.Id.MultilineStringLiteral => {458 ast.Node.ControlFlowExpression.Kind.Continue => |maybe_label| {
746 const multiline_str_literal = @fieldParentPtr(ast.Node.MultilineStringLiteral, "base", base);459 try stream.print("continue");
747 try stream.print("\n");460 if (maybe_label) |label| {
748461 try stream.print(" :");
749 var i : usize = 0;462 try renderExpression(allocator, stream, tree, indent, label);
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));
754 }463 }
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));
760 },464 },
761 ast.Node.Id.BuiltinCall => {465 ast.Node.ControlFlowExpression.Kind.Return => {
762 const builtin_call = @fieldParentPtr(ast.Node.BuiltinCall, "base", base);466 try stream.print("return");
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 }
774 },467 },
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| {469 }
789 try stack.append(RenderState { .Text = ") " });
790 try stack.append(RenderState { .Expression = align_expr});
791 try stack.append(RenderState { .Text = "align(" });
792 }
793470
794 try stack.append(RenderState { .Text = ") " });471 if (flow_expr.rhs) |rhs| {
795 var i = fn_proto.params.len;472 try stream.write(" ");
796 while (i != 0) {473 try renderExpression(allocator, stream, tree, indent, rhs);
797 i -= 1;474 }
798 const param_decl_node = *fn_proto.params.at(i);475 },
799 try stack.append(RenderState { .ParamDecl = param_decl_node});
800 if (i != 0) {
801 try stack.append(RenderState { .Text = ", " });
802 }
803 }
804476
805 try stack.append(RenderState { .Text = "(" });477 ast.Node.Id.Payload => {
806 if (fn_proto.name_token) |name_token| {478 const payload = @fieldParentPtr(ast.Node.Payload, "base", base);
807 try stack.append(RenderState { .Text = tree.tokenSlice(name_token) });
808 try stack.append(RenderState { .Text = " " });
809 }
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| {485 ast.Node.Id.PointerPayload => {
814 try stack.append(RenderState { .Text = " " });486 const payload = @fieldParentPtr(ast.Node.PointerPayload, "base", base);
815 try stack.append(RenderState { .Expression = &async_attr.base });
816 }
817487
818 if (fn_proto.cc_token) |cc_token| {488 try stream.write("|");
819 try stack.append(RenderState { .Text = " " });489 if (payload.ptr_token) |ptr_token| {
820 try stack.append(RenderState { .Text = tree.tokenSlice(cc_token) });490 try stream.write(tree.tokenSlice(ptr_token));
821 }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| {496 ast.Node.Id.PointerIndexPayload => {
824 try stack.append(RenderState { .Text = " " });497 const payload = @fieldParentPtr(ast.Node.PointerIndexPayload, "base", base);
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 }
831498
832 if (fn_proto.visib_token) |visib_token_index| {499 try stream.write("|");
833 const visib_token = tree.tokens.at(visib_token_index);500 if (payload.ptr_token) |ptr_token| {
834 assert(visib_token.id == Token.Id.Keyword_pub or visib_token.id == Token.Id.Keyword_export);501 try stream.write(tree.tokenSlice(ptr_token));
835 try stack.append(RenderState { .Text = " " });502 }
836 try stack.append(RenderState { .Text = tree.tokenSlice(visib_token_index) });503 try renderExpression(allocator, stream, tree, indent, payload.value_symbol);
837 }504
838 },505 if (payload.index_symbol) |index_symbol| {
839 ast.Node.Id.PromiseType => {506 try stream.write(", ");
840 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);507 try renderExpression(allocator, stream, tree, indent, index_symbol);
841 try stream.write(tree.tokenSlice(promise_type.promise_token));508 }
842 if (promise_type.result) |result| {509
843 try stream.write(tree.tokenSlice(result.arrow_token));510 try stream.write("|");
844 try stack.append(RenderState { .Expression = result.return_type});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) ");
845 }592 }
846 },593 },
847 ast.Node.Id.LineComment => {594 ast.Node.ContainerDecl.InitArg.Type => |type_expr| {
848 const line_comment_node = @fieldParentPtr(ast.Node.LineComment, "base", base);595 try stream.write("(");
849 try stream.write(tree.tokenSlice(line_comment_node.token));596 try renderExpression(allocator, stream, tree, indent, type_expr);
597 try stream.write(") ");
850 },598 },
851 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes599 }
852 ast.Node.Id.Switch => {
853 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
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) {607 var it = container_decl.fields_and_decls.iterator(0);
858 try stack.append(RenderState { .Text = ") {}"});608 while (it.next()) |decl| {
859 try stack.append(RenderState { .Expression = switch_node.expr });609 try stream.writeByteNTimes(' ', new_indent);
860 continue;610 try renderTopLevelDecl(allocator, stream, tree, new_indent, *decl);
861 }
862611
863 try stack.append(RenderState { .Text = "}"});612 if (it.peek()) |next_decl| {
864 try stack.append(RenderState.PrintIndent);613 const n = if (nodeLineOffset(tree, *decl, *next_decl) >= 2) u8(2) else u8(1);
865 try stack.append(RenderState { .Indent = indent });614 try stream.writeByteNTimes('\n', n);
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 });
887 }615 }
888 try stack.append(RenderState { .Indent = indent + indent_delta});616 }
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 = " => "});
902617
903 var i = switch_case.items.len;618 try stream.write("\n");
904 while (i != 0) {619 try stream.writeByteNTimes(' ', indent);
905 i -= 1;620 try stream.write("}");
906 try stack.append(RenderState { .Expression = *switch_case.items.at(i) });621 }
622 },
907623
908 if (i != 0) {624 ast.Node.Id.ErrorSetDecl => {
909 try stack.append(RenderState.PrintIndent);625 const err_set_decl = @fieldParentPtr(ast.Node.ErrorSetDecl, "base", base);
910 try stack.append(RenderState { .Text = ",\n" });626
911 }627 if (err_set_decl.decls.len == 0) {
912 }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);
913 },757 },
914 ast.Node.Id.SwitchElse => {758 ast.Node.FnProto.ReturnType.InferErrorSet => |node| {
915 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);759 try stream.write("!");
916 try stream.print("{}", tree.tokenSlice(switch_else.token));760 try renderExpression(allocator, stream, tree, indent, node);
917 },761 },
918 ast.Node.Id.Else => {762 }
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 }
937763
938 if (else_node.payload) |payload| {764 },
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 }
948765
949 if (while_node.inline_token) |inline_token| {766 ast.Node.Id.PromiseType => {
950 try stream.print("{} ", tree.tokenSlice(inline_token));767 const promise_type = @fieldParentPtr(ast.Node.PromiseType, "base", base);
951 }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"| {780 ast.Node.Id.DocComment => unreachable, // doc comments are attached to nodes
956 try stack.append(RenderState { .Expression = &@"else".base });
957781
958 if (while_node.body.id == ast.Node.Id.Block) {782 ast.Node.Id.Switch => {
959 try stack.append(RenderState { .Text = " " });783 const switch_node = @fieldParentPtr(ast.Node.Switch, "base", base);
960 } else {
961 try stack.append(RenderState.PrintIndent);
962 try stack.append(RenderState { .Text = "\n" });
963 }
964 }
965784
966 if (while_node.body.id == ast.Node.Id.Block) {785 try stream.print("{} (", tree.tokenSlice(switch_node.switch_token));
967 try stack.append(RenderState { .Expression = while_node.body });786 if (switch_node.cases.len == 0) {
968 try stack.append(RenderState { .Text = " " });787 try renderExpression(allocator, stream, tree, indent, switch_node.expr);
969 } else {788 try stream.write(") {}");
970 try stack.append(RenderState { .Indent = indent });789 return;
971 try stack.append(RenderState { .Expression = while_node.body });790 }
972 try stack.append(RenderState.PrintIndent);
973 try stack.append(RenderState { .Indent = indent + indent_delta });
974 try stack.append(RenderState { .Text = "\n" });
975 }
976791
977 if (while_node.continue_expr) |continue_expr| {792 try renderExpression(allocator, stream, tree, indent, switch_node.expr);
978 try stack.append(RenderState { .Text = ")" });793 try stream.write(") {\n");
979 try stack.append(RenderState { .Expression = continue_expr });
980 try stack.append(RenderState { .Text = ": (" });
981 try stack.append(RenderState { .Text = " " });
982 }
983794
984 if (while_node.payload) |payload| {795 const new_indent = indent + indent_delta;
985 try stack.append(RenderState { .Expression = payload });
986 try stack.append(RenderState { .Text = " " });
987 }
988796
989 try stack.append(RenderState { .Text = ")" });797 var it = switch_node.cases.iterator(0);
990 try stack.append(RenderState { .Expression = while_node.condition });798 while (it.next()) |node| {
991 try stack.append(RenderState { .Text = "(" });799 try stream.writeByteNTimes(' ', new_indent);
992 },800 try renderExpression(allocator, stream, tree, new_indent, *node);
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 }
998801
999 if (for_node.inline_token) |inline_token| {802 if (it.peek()) |next_node| {
1000 try stream.print("{} ", tree.tokenSlice(inline_token));803 const n = if (nodeLineOffset(tree, *node, *next_node) >= 2) u8(2) else u8(1);
1001 }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"| {813 ast.Node.Id.SwitchCase => {
1006 try stack.append(RenderState { .Expression = &@"else".base });814 const switch_case = @fieldParentPtr(ast.Node.SwitchCase, "base", base);
1007815
1008 if (for_node.body.id == ast.Node.Id.Block) {816 var it = switch_case.items.iterator(0);
1009 try stack.append(RenderState { .Text = " " });817 while (it.next()) |node| {
1010 } else {818 try renderExpression(allocator, stream, tree, indent, *node);
1011 try stack.append(RenderState.PrintIndent);
1012 try stack.append(RenderState { .Text = "\n" });
1013 }
1014 }
1015819
1016 if (for_node.body.id == ast.Node.Id.Block) {820 if (it.peek() != null) {
1017 try stack.append(RenderState { .Expression = for_node.body });821 try stream.write(",\n");
1018 try stack.append(RenderState { .Text = " " });822 try stream.writeByteNTimes(' ', indent);
1019 } else {823 }
1020 try stack.append(RenderState { .Indent = indent });824 }
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 }
1026825
1027 if (for_node.payload) |payload| {826 try stream.write(" => ");
1028 try stack.append(RenderState { .Expression = payload });
1029 try stack.append(RenderState { .Text = " " });
1030 }
1031827
1032 try stack.append(RenderState { .Text = ")" });828 if (switch_case.payload) |payload| {
1033 try stack.append(RenderState { .Expression = for_node.array_expr });829 try renderExpression(allocator, stream, tree, indent, payload);
1034 try stack.append(RenderState { .Text = "(" });830 try stream.write(" ");
1035 },831 }
1036 ast.Node.Id.If => {832
1037 const if_node = @fieldParentPtr(ast.Node.If, "base", base);833 try renderExpression(allocator, stream, tree, indent, switch_case.expr);
1038 try stream.print("{} ", tree.tokenSlice(if_node.if_token));834 try renderToken(tree, stream, switch_case.lastToken() + 1, indent, true);
1039835 },
1040 switch (if_node.body.id) {836 ast.Node.Id.SwitchElse => {
1041 ast.Node.Id.Block, ast.Node.Id.If,837 const switch_else = @fieldParentPtr(ast.Node.SwitchElse, "base", base);
1042 ast.Node.Id.For, ast.Node.Id.While,838 try stream.print("{}", tree.tokenSlice(switch_else.token));
1043 ast.Node.Id.Switch => {839 },
1044 if (if_node.@"else") |@"else"| {840 ast.Node.Id.Else => {
1045 try stack.append(RenderState { .Expression = &@"else".base });841 const else_node = @fieldParentPtr(ast.Node.Else, "base", base);
1046842 try stream.print("{}", tree.tokenSlice(else_node.else_token));
1047 if (if_node.body.id == ast.Node.Id.Block) {843
1048 try stack.append(RenderState { .Text = " " });844 const block_body = switch (else_node.body.id) {
1049 } else {845 ast.Node.Id.Block, ast.Node.Id.If,
1050 try stack.append(RenderState.PrintIndent);846 ast.Node.Id.For, ast.Node.Id.While,
1051 try stack.append(RenderState { .Text = "\n" });847 ast.Node.Id.Switch => true,
1052 }848 else => false,
1053 }849 };
1054 },850
1055 else => {851 if (block_body) {
1056 if (if_node.@"else") |@"else"| {852 try stream.write(" ");
1057 try stack.append(RenderState { .Expression = @"else".body });853 }
1058854
1059 if (@"else".payload) |payload| {855 if (else_node.payload) |payload| {
1060 try stack.append(RenderState { .Text = " " });856 try renderExpression(allocator, stream, tree, indent, payload);
1061 try stack.append(RenderState { .Expression = payload });857 try stream.write(" ");
1062 }858 }
1063859
1064 try stack.append(RenderState { .Text = " " });860 if (block_body) {
1065 try stack.append(RenderState { .Text = tree.tokenSlice(@"else".else_token) });861 try renderExpression(allocator, stream, tree, indent, else_node.body);
1066 try stack.append(RenderState { .Text = " " });862 } else {
1067 }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);
1068 }978 }
979
980 try renderExpression(allocator, stream, tree, indent, &@"else".base);
1069 }981 }
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| {992 try renderExpression(allocator, stream, tree, indent, @"else".body);
1074 try stack.append(RenderState { .Text = " " });
1075 try stack.append(RenderState { .Expression = payload });
1076 }993 }
994 }
995 }
996 },
1077997
1078 try stack.append(RenderState { .NonBreakToken = if_node.condition.lastToken() + 1 });998 ast.Node.Id.Asm => {
1079 try stack.append(RenderState { .Expression = if_node.condition });999 const asm_node = @fieldParentPtr(ast.Node.Asm, "base", base);
1080 try stack.append(RenderState { .Text = "(" });1000 try stream.print("{} ", tree.tokenSlice(asm_node.asm_token));
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));
10851001
1086 if (asm_node.volatile_token) |volatile_token| {1002 if (asm_node.volatile_token) |volatile_token| {
1087 try stream.print("{} ", tree.tokenSlice(volatile_token));1003 try stream.print("{} ", tree.tokenSlice(volatile_token));
1088 }1004 }
10891005
1090 try stack.append(RenderState { .Indent = indent });1006 try stream.print("(");
1091 try stack.append(RenderState { .Text = ")" });1007 try renderExpression(allocator, stream, tree, indent, asm_node.template);
1092 {1008 try stream.print("\n");
1093 var i = asm_node.clobbers.len;1009 const indent_once = indent + indent_delta;
1094 while (i != 0) {1010 try stream.writeByteNTimes(' ', indent_once);
1095 i -= 1;1011 try stream.print(": ");
1096 try stack.append(RenderState { .Expression = *asm_node.clobbers.at(i) });1012 const indent_extra = indent_once + 2;
10971013
1098 if (i != 0) {1014 {
1099 try stack.append(RenderState { .Text = ", " });1015 var it = asm_node.outputs.iterator(0);
1100 }1016 while (it.next()) |asm_output| {
1101 }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);
1102 }1026 }
1103 try stack.append(RenderState { .Text = ": " });1027 }
1104 try stack.append(RenderState.PrintIndent);1028 }
1105 try stack.append(RenderState { .Indent = indent + indent_delta });1029
1106 try stack.append(RenderState { .Text = "\n" });1030 try stream.write("\n");
1107 {1031 try stream.writeByteNTimes(' ', indent_once);
1108 var i = asm_node.inputs.len;1032 try stream.write(": ");
1109 while (i != 0) {1033
1110 i -= 1;1034 {
1111 const node = *asm_node.inputs.at(i);1035 var it = asm_node.inputs.iterator(0);
1112 try stack.append(RenderState { .Expression = &node.base});1036 while (it.next()) |asm_input| {
11131037 const node = &(*asm_input).base;
1114 if (i != 0) {1038 try renderExpression(allocator, stream, tree, indent_extra, node);
1115 try stack.append(RenderState.PrintIndent);1039
1116 try stack.append(RenderState {1040 if (it.peek()) |next_asm_input| {
1117 .Text = blk: {1041 const next_node = &(*next_asm_input).base;
1118 const prev_node = *asm_node.inputs.at(i - 1);1042 const n = if (nodeLineOffset(tree, node, next_node) >= 2) u8(2) else u8(1);
1119 const prev_node_last_token_end = tree.tokens.at(prev_node.lastToken()).end;1043 try stream.writeByte(',');
1120 const loc = tree.tokenLocation(prev_node_last_token_end, node.firstToken());1044 try stream.writeByteNTimes('\n', n);
1121 if (loc.line >= 2) {1045 try stream.writeByteNTimes(' ', indent_extra);
1122 break :blk "\n\n";
1123 }
1124 break :blk "\n";
1125 },
1126 });
1127 try stack.append(RenderState { .Text = "," });
1128 }
1129 }
1130 }1046 }
1131 try stack.append(RenderState { .Indent = indent + indent_delta + 2});1047 }
1132 try stack.append(RenderState { .Text = ": "});1048 }
1133 try stack.append(RenderState.PrintIndent);1049
1134 try stack.append(RenderState { .Indent = indent + indent_delta});1050 try stream.write("\n");
1135 try stack.append(RenderState { .Text = "\n" });1051 try stream.writeByteNTimes(' ', indent_once);
1136 {1052 try stream.write(": ");
1137 var i = asm_node.outputs.len;1053
1138 while (i != 0) {1054 {
1139 i -= 1;1055 var it = asm_node.clobbers.iterator(0);
1140 const node = *asm_node.outputs.at(i);1056 while (it.next()) |node| {
1141 try stack.append(RenderState { .Expression = &node.base});1057 try renderExpression(allocator, stream, tree, indent_once, *node);
11421058
1143 if (i != 0) {1059 if (it.peek() != null) {
1144 try stack.append(RenderState.PrintIndent);1060 try stream.write(", ");
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 }
1159 }1061 }
1160 try stack.append(RenderState { .Indent = indent + indent_delta + 2});1062 }
1161 try stack.append(RenderState { .Text = ": "});1063 }
1162 try stack.append(RenderState.PrintIndent);1064
1163 try stack.append(RenderState { .Indent = indent + indent_delta});1065 try stream.write(")");
1164 try stack.append(RenderState { .Text = "\n" });1066 },
1165 try stack.append(RenderState { .Expression = asm_node.template });1067
1166 try stack.append(RenderState { .Text = "(" });1068 ast.Node.Id.AsmInput => {
1167 },1069 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);
1168 ast.Node.Id.AsmInput => {1070
1169 const asm_input = @fieldParentPtr(ast.Node.AsmInput, "base", base);1071 try stream.write("[");
11701072 try renderExpression(allocator, stream, tree, indent, asm_input.symbolic_name);
1171 try stack.append(RenderState { .Text = ")"});1073 try stream.write("] ");
1172 try stack.append(RenderState { .Expression = asm_input.expr});1074 try renderExpression(allocator, stream, tree, indent, asm_input.constraint);
1173 try stack.append(RenderState { .Text = " ("});1075 try stream.write(" (");
1174 try stack.append(RenderState { .Expression = asm_input.constraint });1076 try renderExpression(allocator, stream, tree, indent, asm_input.expr);
1175 try stack.append(RenderState { .Text = "] "});1077 try stream.write(")");
1176 try stack.append(RenderState { .Expression = asm_input.symbolic_name });1078 },
1177 try stack.append(RenderState { .Text = "["});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);
1178 },1092 },
1179 ast.Node.Id.AsmOutput => {1093 ast.Node.AsmOutput.Kind.Return => |return_type| {
1180 const asm_output = @fieldParentPtr(ast.Node.AsmOutput, "base", base);1094 try stream.write("-> ");
11811095 try renderExpression(allocator, stream, tree, indent, return_type);
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 = "["});
1197 },1096 },
1097 }
11981098
1199 ast.Node.Id.StructField,1099 try stream.write(")");
1200 ast.Node.Id.UnionTag,1100 },
1201 ast.Node.Id.EnumTag,1101
1202 ast.Node.Id.ErrorTag,1102 ast.Node.Id.StructField,
1203 ast.Node.Id.Root,1103 ast.Node.Id.UnionTag,
1204 ast.Node.Id.VarDecl,1104 ast.Node.Id.EnumTag,
1205 ast.Node.Id.Use,1105 ast.Node.Id.ErrorTag,
1206 ast.Node.Id.TestDecl,1106 ast.Node.Id.Root,
1207 ast.Node.Id.ParamDecl => unreachable,1107 ast.Node.Id.VarDecl,
1208 },1108 ast.Node.Id.Use,
1209 RenderState.Statement => |base| {1109 ast.Node.Id.TestDecl,
1210 switch (base.id) {1110 ast.Node.Id.ParamDecl => unreachable,
1211 ast.Node.Id.VarDecl => {1111 }
1212 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", base);1112}
1213 try stack.append(RenderState { .VarDecl = var_decl});1113
1214 },1114fn renderVarDecl(allocator: &mem.Allocator, stream: var, tree: &ast.Tree, indent: usize, var_decl: &ast.Node.VarDecl) (@typeOf(stream).Child.Error || Error)!void {
1215 else => {1115 if (var_decl.visib_token) |visib_token| {
1216 try stack.append(RenderState { .MaybeSemiColon = base });1116 try stream.print("{} ", tree.tokenSlice(visib_token));
1217 try stack.append(RenderState { .Expression = base });1117 }
1218 },1118
1219 }1119 if (var_decl.extern_export_token) |extern_export_token| {
1220 },1120 try stream.print("{} ", tree.tokenSlice(extern_export_token));
1221 RenderState.Indent => |new_indent| indent = new_indent,1121
1222 RenderState.PrintIndent => try stream.writeByteNTimes(' ', indent),1122 if (var_decl.lib_name) |lib_name| {
1223 RenderState.Token => |token_index| try renderToken(tree, stream, token_index, indent, true),1123 try renderExpression(allocator, stream, tree, indent, lib_name);
1224 RenderState.NonBreakToken => |token_index| try renderToken(tree, stream, token_index, indent, false),1124 try stream.write(" ");
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 },
1232 }1125 }
1233 }1126 }
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 }
1234}1191}
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 {
1237 const token = tree.tokens.at(token_index);1194 const token = tree.tokens.at(token_index);
1238 try stream.write(tree.tokenSlicePtr(token));1195 try stream.write(tree.tokenSlicePtr(token));
12391196
...@@ -1255,7 +1212,7 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent...@@ -1255,7 +1212,7 @@ fn renderToken(tree: &ast.Tree, stream: var, token_index: ast.TokenIndex, indent
1255 }1212 }
1256}1213}
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 {
1259 const comment = node.doc_comments ?? return;1216 const comment = node.doc_comments ?? return;
1260 var it = comment.lines.iterator(0);1217 var it = comment.lines.iterator(0);
1261 while (it.next()) |line_token_index| {1218 while (it.next()) |line_token_index| {