Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016 Andrew Kelley
3 : : *
4 : : * This file is part of zig, which is MIT licensed.
5 : : * See http://opensource.org/licenses/MIT
6 : : */
7 : :
8 : : #include "analyze.hpp"
9 : : #include "ast_render.hpp"
10 : : #include "os.hpp"
11 : :
12 : : #include <stdio.h>
13 : :
14 : 0 : static const char *bin_op_str(BinOpType bin_op) {
15 [ # # # # : 0 : switch (bin_op) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # ]
16 : 0 : case BinOpTypeInvalid: return "(invalid)";
17 : 0 : case BinOpTypeBoolOr: return "or";
18 : 0 : case BinOpTypeBoolAnd: return "and";
19 : 0 : case BinOpTypeCmpEq: return "==";
20 : 0 : case BinOpTypeCmpNotEq: return "!=";
21 : 0 : case BinOpTypeCmpLessThan: return "<";
22 : 0 : case BinOpTypeCmpGreaterThan: return ">";
23 : 0 : case BinOpTypeCmpLessOrEq: return "<=";
24 : 0 : case BinOpTypeCmpGreaterOrEq: return ">=";
25 : 0 : case BinOpTypeBinOr: return "|";
26 : 0 : case BinOpTypeBinXor: return "^";
27 : 0 : case BinOpTypeBinAnd: return "&";
28 : 0 : case BinOpTypeBitShiftLeft: return "<<";
29 : 0 : case BinOpTypeBitShiftRight: return ">>";
30 : 0 : case BinOpTypeAdd: return "+";
31 : 0 : case BinOpTypeAddWrap: return "+%";
32 : 0 : case BinOpTypeSub: return "-";
33 : 0 : case BinOpTypeSubWrap: return "-%";
34 : 0 : case BinOpTypeMult: return "*";
35 : 0 : case BinOpTypeMultWrap: return "*%";
36 : 0 : case BinOpTypeDiv: return "/";
37 : 0 : case BinOpTypeMod: return "%";
38 : 0 : case BinOpTypeAssign: return "=";
39 : 0 : case BinOpTypeAssignTimes: return "*=";
40 : 0 : case BinOpTypeAssignTimesWrap: return "*%=";
41 : 0 : case BinOpTypeAssignDiv: return "/=";
42 : 0 : case BinOpTypeAssignMod: return "%=";
43 : 0 : case BinOpTypeAssignPlus: return "+=";
44 : 0 : case BinOpTypeAssignPlusWrap: return "+%=";
45 : 0 : case BinOpTypeAssignMinus: return "-=";
46 : 0 : case BinOpTypeAssignMinusWrap: return "-%=";
47 : 0 : case BinOpTypeAssignBitShiftLeft: return "<<=";
48 : 0 : case BinOpTypeAssignBitShiftRight: return ">>=";
49 : 0 : case BinOpTypeAssignBitAnd: return "&=";
50 : 0 : case BinOpTypeAssignBitXor: return "^=";
51 : 0 : case BinOpTypeAssignBitOr: return "|=";
52 : 0 : case BinOpTypeAssignMergeErrorSets: return "||=";
53 : 0 : case BinOpTypeUnwrapOptional: return "orelse";
54 : 0 : case BinOpTypeArrayCat: return "++";
55 : 0 : case BinOpTypeArrayMult: return "**";
56 : 0 : case BinOpTypeErrorUnion: return "!";
57 : 0 : case BinOpTypeMergeErrorSets: return "||";
58 : : }
59 : 0 : zig_unreachable();
60 : : }
61 : :
62 : 0 : static const char *prefix_op_str(PrefixOp prefix_op) {
63 [ # # # # : 0 : switch (prefix_op) {
# # # # ]
64 : 0 : case PrefixOpInvalid: return "(invalid)";
65 : 0 : case PrefixOpNegation: return "-";
66 : 0 : case PrefixOpNegationWrap: return "-%";
67 : 0 : case PrefixOpBoolNot: return "!";
68 : 0 : case PrefixOpBinNot: return "~";
69 : 0 : case PrefixOpOptional: return "?";
70 : 0 : case PrefixOpAddrOf: return "&";
71 : : }
72 : 0 : zig_unreachable();
73 : : }
74 : :
75 : 0 : static const char *visib_mod_string(VisibMod mod) {
76 [ # # # ]: 0 : switch (mod) {
77 : 0 : case VisibModPub: return "pub ";
78 : 0 : case VisibModPrivate: return "";
79 : : }
80 : 0 : zig_unreachable();
81 : : }
82 : :
83 : 0 : static const char *return_string(ReturnKind kind) {
84 [ # # # ]: 0 : switch (kind) {
85 : 0 : case ReturnKindUnconditional: return "return";
86 : 0 : case ReturnKindError: return "try";
87 : : }
88 : 0 : zig_unreachable();
89 : : }
90 : :
91 : 0 : static const char *defer_string(ReturnKind kind) {
92 [ # # # ]: 0 : switch (kind) {
93 : 0 : case ReturnKindUnconditional: return "defer";
94 : 0 : case ReturnKindError: return "errdefer";
95 : : }
96 : 0 : zig_unreachable();
97 : : }
98 : :
99 : 0 : static const char *layout_string(ContainerLayout layout) {
100 [ # # # # ]: 0 : switch (layout) {
101 : 0 : case ContainerLayoutAuto: return "";
102 : 0 : case ContainerLayoutExtern: return "extern ";
103 : 0 : case ContainerLayoutPacked: return "packed ";
104 : : }
105 : 0 : zig_unreachable();
106 : : }
107 : :
108 : 0 : static const char *extern_string(bool is_extern) {
109 [ # # ]: 0 : return is_extern ? "extern " : "";
110 : : }
111 : :
112 : 0 : static const char *export_string(bool is_export) {
113 [ # # ]: 0 : return is_export ? "export " : "";
114 : : }
115 : :
116 : : //static const char *calling_convention_string(CallingConvention cc) {
117 : : // switch (cc) {
118 : : // case CallingConventionUnspecified: return "";
119 : : // case CallingConventionC: return "extern ";
120 : : // case CallingConventionCold: return "coldcc ";
121 : : // case CallingConventionNaked: return "nakedcc ";
122 : : // case CallingConventionStdcall: return "stdcallcc ";
123 : : // }
124 : : // zig_unreachable();
125 : : //}
126 : :
127 : 0 : static const char *inline_string(FnInline fn_inline) {
128 [ # # # # ]: 0 : switch (fn_inline) {
129 : 0 : case FnInlineAlways: return "inline ";
130 : 0 : case FnInlineNever: return "noinline ";
131 : 0 : case FnInlineAuto: return "";
132 : : }
133 : 0 : zig_unreachable();
134 : : }
135 : :
136 : 0 : static const char *const_or_var_string(bool is_const) {
137 [ # # ]: 0 : return is_const ? "const" : "var";
138 : : }
139 : :
140 : 0 : static const char *thread_local_string(Token *tok) {
141 [ # # ]: 0 : return (tok == nullptr) ? "" : "threadlocal ";
142 : : }
143 : :
144 : 0 : static const char *token_to_ptr_len_str(Token *tok) {
145 : 0 : assert(tok != nullptr);
146 [ # # # # ]: 0 : switch (tok->id) {
147 : 0 : case TokenIdStar:
148 : : case TokenIdStarStar:
149 : 0 : return "*";
150 : 0 : case TokenIdBracketStarBracket:
151 : 0 : return "[*]";
152 : 0 : case TokenIdBracketStarCBracket:
153 : 0 : return "[*c]";
154 : 0 : default:
155 : 0 : zig_unreachable();
156 : : }
157 : : }
158 : :
159 : 0 : static const char *node_type_str(NodeType node_type) {
160 [ # # # # : 0 : switch (node_type) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
161 : 0 : case NodeTypeFnDef:
162 : 0 : return "FnDef";
163 : 0 : case NodeTypeFnProto:
164 : 0 : return "FnProto";
165 : 0 : case NodeTypeParamDecl:
166 : 0 : return "ParamDecl";
167 : 0 : case NodeTypeBlock:
168 : 0 : return "Block";
169 : 0 : case NodeTypeGroupedExpr:
170 : 0 : return "Parens";
171 : 0 : case NodeTypeBinOpExpr:
172 : 0 : return "BinOpExpr";
173 : 0 : case NodeTypeCatchExpr:
174 : 0 : return "CatchExpr";
175 : 0 : case NodeTypeFnCallExpr:
176 : 0 : return "FnCallExpr";
177 : 0 : case NodeTypeArrayAccessExpr:
178 : 0 : return "ArrayAccessExpr";
179 : 0 : case NodeTypeSliceExpr:
180 : 0 : return "SliceExpr";
181 : 0 : case NodeTypeReturnExpr:
182 : 0 : return "ReturnExpr";
183 : 0 : case NodeTypeDefer:
184 : 0 : return "Defer";
185 : 0 : case NodeTypeVariableDeclaration:
186 : 0 : return "VariableDeclaration";
187 : 0 : case NodeTypeTestDecl:
188 : 0 : return "TestDecl";
189 : 0 : case NodeTypeIntLiteral:
190 : 0 : return "IntLiteral";
191 : 0 : case NodeTypeFloatLiteral:
192 : 0 : return "FloatLiteral";
193 : 0 : case NodeTypeStringLiteral:
194 : 0 : return "StringLiteral";
195 : 0 : case NodeTypeCharLiteral:
196 : 0 : return "CharLiteral";
197 : 0 : case NodeTypeSymbol:
198 : 0 : return "Symbol";
199 : 0 : case NodeTypePrefixOpExpr:
200 : 0 : return "PrefixOpExpr";
201 : 0 : case NodeTypeUsingNamespace:
202 : 0 : return "UsingNamespace";
203 : 0 : case NodeTypeBoolLiteral:
204 : 0 : return "BoolLiteral";
205 : 0 : case NodeTypeNullLiteral:
206 : 0 : return "NullLiteral";
207 : 0 : case NodeTypeUndefinedLiteral:
208 : 0 : return "UndefinedLiteral";
209 : 0 : case NodeTypeIfBoolExpr:
210 : 0 : return "IfBoolExpr";
211 : 0 : case NodeTypeWhileExpr:
212 : 0 : return "WhileExpr";
213 : 0 : case NodeTypeForExpr:
214 : 0 : return "ForExpr";
215 : 0 : case NodeTypeSwitchExpr:
216 : 0 : return "SwitchExpr";
217 : 0 : case NodeTypeSwitchProng:
218 : 0 : return "SwitchProng";
219 : 0 : case NodeTypeSwitchRange:
220 : 0 : return "SwitchRange";
221 : 0 : case NodeTypeCompTime:
222 : 0 : return "CompTime";
223 : 0 : case NodeTypeBreak:
224 : 0 : return "Break";
225 : 0 : case NodeTypeContinue:
226 : 0 : return "Continue";
227 : 0 : case NodeTypeUnreachable:
228 : 0 : return "Unreachable";
229 : 0 : case NodeTypeAsmExpr:
230 : 0 : return "AsmExpr";
231 : 0 : case NodeTypeFieldAccessExpr:
232 : 0 : return "FieldAccessExpr";
233 : 0 : case NodeTypePtrDeref:
234 : 0 : return "PtrDerefExpr";
235 : 0 : case NodeTypeUnwrapOptional:
236 : 0 : return "UnwrapOptional";
237 : 0 : case NodeTypeContainerDecl:
238 : 0 : return "ContainerDecl";
239 : 0 : case NodeTypeStructField:
240 : 0 : return "StructField";
241 : 0 : case NodeTypeStructValueField:
242 : 0 : return "StructValueField";
243 : 0 : case NodeTypeContainerInitExpr:
244 : 0 : return "ContainerInitExpr";
245 : 0 : case NodeTypeArrayType:
246 : 0 : return "ArrayType";
247 : 0 : case NodeTypeInferredArrayType:
248 : 0 : return "InferredArrayType";
249 : 0 : case NodeTypeErrorType:
250 : 0 : return "ErrorType";
251 : 0 : case NodeTypeIfErrorExpr:
252 : 0 : return "IfErrorExpr";
253 : 0 : case NodeTypeIfOptional:
254 : 0 : return "IfOptional";
255 : 0 : case NodeTypeErrorSetDecl:
256 : 0 : return "ErrorSetDecl";
257 : 0 : case NodeTypeResume:
258 : 0 : return "Resume";
259 : 0 : case NodeTypeAwaitExpr:
260 : 0 : return "AwaitExpr";
261 : 0 : case NodeTypeSuspend:
262 : 0 : return "Suspend";
263 : 0 : case NodeTypePointerType:
264 : 0 : return "PointerType";
265 : 0 : case NodeTypeAnyFrameType:
266 : 0 : return "AnyFrameType";
267 : 0 : case NodeTypeEnumLiteral:
268 : 0 : return "EnumLiteral";
269 : : }
270 : 0 : zig_unreachable();
271 : : }
272 : :
273 : : struct AstPrint {
274 : : int indent;
275 : : FILE *f;
276 : : };
277 : :
278 : 0 : static void ast_print_visit(AstNode **node_ptr, void *context) {
279 : 0 : AstNode *node = *node_ptr;
280 : 0 : AstPrint *ap = (AstPrint *)context;
281 : :
282 [ # # ]: 0 : for (int i = 0; i < ap->indent; i += 1) {
283 : 0 : fprintf(ap->f, " ");
284 : : }
285 : :
286 : 0 : fprintf(ap->f, "%s\n", node_type_str(node->type));
287 : :
288 : : AstPrint new_ap;
289 : 0 : new_ap.indent = ap->indent + 2;
290 : 0 : new_ap.f = ap->f;
291 : :
292 : 0 : ast_visit_node_children(node, ast_print_visit, &new_ap);
293 : 0 : }
294 : :
295 : 0 : void ast_print(FILE *f, AstNode *node, int indent) {
296 : : AstPrint ap;
297 : 0 : ap.indent = indent;
298 : 0 : ap.f = f;
299 : 0 : ast_visit_node_children(node, ast_print_visit, &ap);
300 : 0 : }
301 : :
302 : :
303 : : struct AstRender {
304 : : int indent;
305 : : int indent_size;
306 : : FILE *f;
307 : : };
308 : :
309 : 0 : static void print_indent(AstRender *ar) {
310 [ # # ]: 0 : for (int i = 0; i < ar->indent; i += 1) {
311 : 0 : fprintf(ar->f, " ");
312 : : }
313 : 0 : }
314 : :
315 : 0 : static bool is_alpha_under(uint8_t c) {
316 [ # # ][ # # ]: 0 : return (c >= 'a' && c <= 'z') ||
317 [ # # ][ # # ]: 0 : (c >= 'A' && c <= 'Z') || c == '_';
[ # # ]
318 : : }
319 : :
320 : 0 : static bool is_digit(uint8_t c) {
321 [ # # ][ # # ]: 0 : return (c >= '0' && c <= '9');
322 : : }
323 : :
324 : 0 : static bool is_printable(uint8_t c) {
325 [ # # ]: 0 : if (c == 0) {
326 : 0 : return false;
327 : : }
328 : : static const uint8_t printables[] =
329 : : " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.~`!@#$%^&*()_-+=\\{}[];'\"?/<>,:";
330 [ # # ]: 0 : for (size_t i = 0; i < array_length(printables); i += 1) {
331 [ # # ]: 0 : if (c == printables[i]) return true;
332 : : }
333 : 0 : return false;
334 : : }
335 : :
336 : 0 : static void string_literal_escape(Buf *source, Buf *dest) {
337 : 0 : buf_resize(dest, 0);
338 [ # # ]: 0 : for (size_t i = 0; i < buf_len(source); i += 1) {
339 : 0 : uint8_t c = *((uint8_t*)buf_ptr(source) + i);
340 [ # # ]: 0 : if (c == '\'') {
341 : 0 : buf_append_str(dest, "\\'");
342 [ # # ]: 0 : } else if (c == '"') {
343 : 0 : buf_append_str(dest, "\\\"");
344 [ # # ]: 0 : } else if (c == '\\') {
345 : 0 : buf_append_str(dest, "\\\\");
346 [ # # ]: 0 : } else if (c == '\n') {
347 : 0 : buf_append_str(dest, "\\n");
348 [ # # ]: 0 : } else if (c == '\r') {
349 : 0 : buf_append_str(dest, "\\r");
350 [ # # ]: 0 : } else if (c == '\t') {
351 : 0 : buf_append_str(dest, "\\t");
352 [ # # ]: 0 : } else if (is_printable(c)) {
353 : 0 : buf_append_char(dest, c);
354 : : } else {
355 : 0 : buf_appendf(dest, "\\x%02x", (int)c);
356 : : }
357 : : }
358 : 0 : }
359 : :
360 : 0 : static bool is_valid_bare_symbol(Buf *symbol) {
361 [ # # ]: 0 : if (buf_len(symbol) == 0) {
362 : 0 : return false;
363 : : }
364 : 0 : uint8_t first_char = *buf_ptr(symbol);
365 [ # # ]: 0 : if (!is_alpha_under(first_char)) {
366 : 0 : return false;
367 : : }
368 [ # # ]: 0 : for (size_t i = 1; i < buf_len(symbol); i += 1) {
369 : 0 : uint8_t c = *((uint8_t*)buf_ptr(symbol) + i);
370 [ # # ][ # # ]: 0 : if (!is_alpha_under(c) && !is_digit(c)) {
[ # # ]
371 : 0 : return false;
372 : : }
373 : : }
374 : 0 : return true;
375 : : }
376 : :
377 : 0 : static void print_symbol(AstRender *ar, Buf *symbol) {
378 [ # # ]: 0 : if (is_zig_keyword(symbol)) {
379 : 0 : fprintf(ar->f, "@\"%s\"", buf_ptr(symbol));
380 : 0 : return;
381 : : }
382 [ # # ]: 0 : if (is_valid_bare_symbol(symbol)) {
383 : 0 : fprintf(ar->f, "%s", buf_ptr(symbol));
384 : 0 : return;
385 : : }
386 : 0 : Buf escaped = BUF_INIT;
387 : 0 : string_literal_escape(symbol, &escaped);
388 : 0 : fprintf(ar->f, "@\"%s\"", buf_ptr(&escaped));
389 : : }
390 : :
391 : 0 : static bool statement_terminates_without_semicolon(AstNode *node) {
392 [ # # # # : 0 : switch (node->type) {
# # # # #
# ]
393 : 0 : case NodeTypeIfBoolExpr:
394 [ # # ]: 0 : if (node->data.if_bool_expr.else_node)
395 : 0 : return statement_terminates_without_semicolon(node->data.if_bool_expr.else_node);
396 : 0 : return node->data.if_bool_expr.then_block->type == NodeTypeBlock;
397 : 0 : case NodeTypeIfErrorExpr:
398 [ # # ]: 0 : if (node->data.if_err_expr.else_node)
399 : 0 : return statement_terminates_without_semicolon(node->data.if_err_expr.else_node);
400 : 0 : return node->data.if_err_expr.then_node->type == NodeTypeBlock;
401 : 0 : case NodeTypeIfOptional:
402 [ # # ]: 0 : if (node->data.test_expr.else_node)
403 : 0 : return statement_terminates_without_semicolon(node->data.test_expr.else_node);
404 : 0 : return node->data.test_expr.then_node->type == NodeTypeBlock;
405 : 0 : case NodeTypeWhileExpr:
406 : 0 : return node->data.while_expr.body->type == NodeTypeBlock;
407 : 0 : case NodeTypeForExpr:
408 : 0 : return node->data.for_expr.body->type == NodeTypeBlock;
409 : 0 : case NodeTypeCompTime:
410 : 0 : return node->data.comptime_expr.expr->type == NodeTypeBlock;
411 : 0 : case NodeTypeDefer:
412 : 0 : return node->data.defer.expr->type == NodeTypeBlock;
413 : 0 : case NodeTypeSuspend:
414 [ # # ][ # # ]: 0 : return node->data.suspend.block != nullptr && node->data.suspend.block->type == NodeTypeBlock;
415 : 0 : case NodeTypeSwitchExpr:
416 : : case NodeTypeBlock:
417 : 0 : return true;
418 : 0 : default:
419 : 0 : return false;
420 : : }
421 : : }
422 : :
423 : : static void render_node_extra(AstRender *ar, AstNode *node, bool grouped);
424 : :
425 : 0 : static void render_node_grouped(AstRender *ar, AstNode *node) {
426 : 0 : return render_node_extra(ar, node, true);
427 : : }
428 : :
429 : 0 : static void render_node_ungrouped(AstRender *ar, AstNode *node) {
430 : 0 : return render_node_extra(ar, node, false);
431 : : }
432 : :
433 : 0 : static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
434 [ # # # # : 0 : switch (node->type) {
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# ]
435 : 0 : case NodeTypeSwitchProng:
436 : : case NodeTypeSwitchRange:
437 : : case NodeTypeStructValueField:
438 : 0 : zig_unreachable();
439 : 0 : case NodeTypeFnProto:
440 : : {
441 : 0 : const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod);
442 : 0 : const char *extern_str = extern_string(node->data.fn_proto.is_extern);
443 : 0 : const char *export_str = export_string(node->data.fn_proto.is_export);
444 : 0 : const char *inline_str = inline_string(node->data.fn_proto.fn_inline);
445 : 0 : fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str);
446 [ # # ]: 0 : if (node->data.fn_proto.name != nullptr) {
447 : 0 : print_symbol(ar, node->data.fn_proto.name);
448 : : }
449 : 0 : fprintf(ar->f, "(");
450 : 0 : size_t arg_count = node->data.fn_proto.params.length;
451 [ # # ]: 0 : for (size_t arg_i = 0; arg_i < arg_count; arg_i += 1) {
452 : 0 : AstNode *param_decl = node->data.fn_proto.params.at(arg_i);
453 : 0 : assert(param_decl->type == NodeTypeParamDecl);
454 [ # # ]: 0 : if (param_decl->data.param_decl.name != nullptr) {
455 [ # # ]: 0 : const char *noalias_str = param_decl->data.param_decl.is_noalias ? "noalias " : "";
456 [ # # ]: 0 : const char *inline_str = param_decl->data.param_decl.is_comptime ? "comptime " : "";
457 : 0 : fprintf(ar->f, "%s%s", noalias_str, inline_str);
458 : 0 : print_symbol(ar, param_decl->data.param_decl.name);
459 : 0 : fprintf(ar->f, ": ");
460 : : }
461 [ # # ]: 0 : if (param_decl->data.param_decl.is_var_args) {
462 : 0 : fprintf(ar->f, "...");
463 [ # # ]: 0 : } else if (param_decl->data.param_decl.var_token != nullptr) {
464 : 0 : fprintf(ar->f, "var");
465 : : } else {
466 : 0 : render_node_grouped(ar, param_decl->data.param_decl.type);
467 : : }
468 : :
469 [ # # ]: 0 : if (arg_i + 1 < arg_count) {
470 : 0 : fprintf(ar->f, ", ");
471 : : }
472 : : }
473 [ # # ]: 0 : if (node->data.fn_proto.is_var_args) {
474 : 0 : fprintf(ar->f, ", ...");
475 : : }
476 : 0 : fprintf(ar->f, ")");
477 [ # # ]: 0 : if (node->data.fn_proto.align_expr) {
478 : 0 : fprintf(ar->f, " align(");
479 : 0 : render_node_grouped(ar, node->data.fn_proto.align_expr);
480 : 0 : fprintf(ar->f, ")");
481 : : }
482 [ # # ]: 0 : if (node->data.fn_proto.section_expr) {
483 : 0 : fprintf(ar->f, " section(");
484 : 0 : render_node_grouped(ar, node->data.fn_proto.section_expr);
485 : 0 : fprintf(ar->f, ")");
486 : : }
487 : :
488 [ # # ]: 0 : if (node->data.fn_proto.return_var_token != nullptr) {
489 : 0 : fprintf(ar->f, "var");
490 : : } else {
491 : 0 : AstNode *return_type_node = node->data.fn_proto.return_type;
492 : 0 : assert(return_type_node != nullptr);
493 : 0 : fprintf(ar->f, " ");
494 [ # # ]: 0 : if (node->data.fn_proto.auto_err_set) {
495 : 0 : fprintf(ar->f, "!");
496 : : }
497 : 0 : render_node_grouped(ar, return_type_node);
498 : : }
499 : 0 : break;
500 : : }
501 : 0 : case NodeTypeFnDef:
502 : : {
503 : 0 : render_node_grouped(ar, node->data.fn_def.fn_proto);
504 : 0 : fprintf(ar->f, " ");
505 : 0 : render_node_grouped(ar, node->data.fn_def.body);
506 : 0 : break;
507 : : }
508 : 0 : case NodeTypeBlock:
509 [ # # ]: 0 : if (node->data.block.name != nullptr) {
510 : 0 : fprintf(ar->f, "%s: ", buf_ptr(node->data.block.name));
511 : : }
512 [ # # ]: 0 : if (node->data.block.statements.length == 0) {
513 : 0 : fprintf(ar->f, "{}");
514 : 0 : break;
515 : : }
516 : 0 : fprintf(ar->f, "{\n");
517 : 0 : ar->indent += ar->indent_size;
518 [ # # ]: 0 : for (size_t i = 0; i < node->data.block.statements.length; i += 1) {
519 : 0 : AstNode *statement = node->data.block.statements.at(i);
520 : 0 : print_indent(ar);
521 : 0 : render_node_grouped(ar, statement);
522 : :
523 [ # # ]: 0 : if (!statement_terminates_without_semicolon(statement))
524 : 0 : fprintf(ar->f, ";");
525 : :
526 : 0 : fprintf(ar->f, "\n");
527 : : }
528 : 0 : ar->indent -= ar->indent_size;
529 : 0 : print_indent(ar);
530 : 0 : fprintf(ar->f, "}");
531 : 0 : break;
532 : 0 : case NodeTypeGroupedExpr:
533 : 0 : fprintf(ar->f, "(");
534 : 0 : render_node_ungrouped(ar, node->data.grouped_expr);
535 : 0 : fprintf(ar->f, ")");
536 : 0 : break;
537 : 0 : case NodeTypeReturnExpr:
538 : : {
539 : 0 : const char *return_str = return_string(node->data.return_expr.kind);
540 : 0 : fprintf(ar->f, "%s", return_str);
541 [ # # ]: 0 : if (node->data.return_expr.expr) {
542 : 0 : fprintf(ar->f, " ");
543 : 0 : render_node_grouped(ar, node->data.return_expr.expr);
544 : : }
545 : 0 : break;
546 : : }
547 : 0 : case NodeTypeBreak:
548 : : {
549 : 0 : fprintf(ar->f, "break");
550 [ # # ]: 0 : if (node->data.break_expr.name != nullptr) {
551 : 0 : fprintf(ar->f, " :%s", buf_ptr(node->data.break_expr.name));
552 : : }
553 [ # # ]: 0 : if (node->data.break_expr.expr) {
554 : 0 : fprintf(ar->f, " ");
555 : 0 : render_node_grouped(ar, node->data.break_expr.expr);
556 : : }
557 : 0 : break;
558 : : }
559 : 0 : case NodeTypeDefer:
560 : : {
561 : 0 : const char *defer_str = defer_string(node->data.defer.kind);
562 : 0 : fprintf(ar->f, "%s ", defer_str);
563 : 0 : render_node_grouped(ar, node->data.return_expr.expr);
564 : 0 : break;
565 : : }
566 : 0 : case NodeTypeVariableDeclaration:
567 : : {
568 : 0 : const char *pub_str = visib_mod_string(node->data.variable_declaration.visib_mod);
569 : 0 : const char *extern_str = extern_string(node->data.variable_declaration.is_extern);
570 : 0 : const char *thread_local_str = thread_local_string(node->data.variable_declaration.threadlocal_tok);
571 : 0 : const char *const_or_var = const_or_var_string(node->data.variable_declaration.is_const);
572 : 0 : fprintf(ar->f, "%s%s%s%s ", pub_str, extern_str, thread_local_str, const_or_var);
573 : 0 : print_symbol(ar, node->data.variable_declaration.symbol);
574 : :
575 [ # # ]: 0 : if (node->data.variable_declaration.type) {
576 : 0 : fprintf(ar->f, ": ");
577 : 0 : render_node_grouped(ar, node->data.variable_declaration.type);
578 : : }
579 [ # # ]: 0 : if (node->data.variable_declaration.align_expr) {
580 : 0 : fprintf(ar->f, "align(");
581 : 0 : render_node_grouped(ar, node->data.variable_declaration.align_expr);
582 : 0 : fprintf(ar->f, ") ");
583 : : }
584 [ # # ]: 0 : if (node->data.variable_declaration.section_expr) {
585 : 0 : fprintf(ar->f, "section(");
586 : 0 : render_node_grouped(ar, node->data.variable_declaration.section_expr);
587 : 0 : fprintf(ar->f, ") ");
588 : : }
589 [ # # ]: 0 : if (node->data.variable_declaration.expr) {
590 : 0 : fprintf(ar->f, " = ");
591 : 0 : render_node_grouped(ar, node->data.variable_declaration.expr);
592 : : }
593 : 0 : break;
594 : : }
595 : 0 : case NodeTypeBinOpExpr:
596 [ # # ]: 0 : if (!grouped) fprintf(ar->f, "(");
597 : 0 : render_node_ungrouped(ar, node->data.bin_op_expr.op1);
598 : 0 : fprintf(ar->f, " %s ", bin_op_str(node->data.bin_op_expr.bin_op));
599 : 0 : render_node_ungrouped(ar, node->data.bin_op_expr.op2);
600 [ # # ]: 0 : if (!grouped) fprintf(ar->f, ")");
601 : 0 : break;
602 : 0 : case NodeTypeFloatLiteral:
603 : : {
604 : 0 : Buf rendered_buf = BUF_INIT;
605 : 0 : buf_resize(&rendered_buf, 0);
606 : 0 : bigfloat_append_buf(&rendered_buf, node->data.float_literal.bigfloat);
607 : 0 : fprintf(ar->f, "%s", buf_ptr(&rendered_buf));
608 : : }
609 : 0 : break;
610 : 0 : case NodeTypeIntLiteral:
611 : : {
612 : 0 : Buf rendered_buf = BUF_INIT;
613 : 0 : buf_resize(&rendered_buf, 0);
614 : 0 : bigint_append_buf(&rendered_buf, node->data.int_literal.bigint, 10);
615 : 0 : fprintf(ar->f, "%s", buf_ptr(&rendered_buf));
616 : : }
617 : 0 : break;
618 : 0 : case NodeTypeStringLiteral:
619 : : {
620 [ # # ]: 0 : if (node->data.string_literal.c) {
621 : 0 : fprintf(ar->f, "c");
622 : : }
623 : 0 : Buf tmp_buf = BUF_INIT;
624 : 0 : string_literal_escape(node->data.string_literal.buf, &tmp_buf);
625 : 0 : fprintf(ar->f, "\"%s\"", buf_ptr(&tmp_buf));
626 : : }
627 : 0 : break;
628 : 0 : case NodeTypeCharLiteral:
629 : : {
630 : 0 : uint8_t c = node->data.char_literal.value;
631 [ # # ]: 0 : if (c == '\'') {
632 : 0 : fprintf(ar->f, "'\\''");
633 [ # # ]: 0 : } else if (c == '\"') {
634 : 0 : fprintf(ar->f, "'\\\"'");
635 [ # # ]: 0 : } else if (c == '\\') {
636 : 0 : fprintf(ar->f, "'\\\\'");
637 [ # # ]: 0 : } else if (c == '\n') {
638 : 0 : fprintf(ar->f, "'\\n'");
639 [ # # ]: 0 : } else if (c == '\r') {
640 : 0 : fprintf(ar->f, "'\\r'");
641 [ # # ]: 0 : } else if (c == '\t') {
642 : 0 : fprintf(ar->f, "'\\t'");
643 [ # # ]: 0 : } else if (is_printable(c)) {
644 : 0 : fprintf(ar->f, "'%c'", c);
645 : : } else {
646 : 0 : fprintf(ar->f, "'\\x%02x'", (int)c);
647 : : }
648 : 0 : break;
649 : : }
650 : 0 : case NodeTypeSymbol:
651 : 0 : print_symbol(ar, node->data.symbol_expr.symbol);
652 : 0 : break;
653 : 0 : case NodeTypePrefixOpExpr:
654 : : {
655 [ # # ]: 0 : if (!grouped) fprintf(ar->f, "(");
656 : 0 : PrefixOp op = node->data.prefix_op_expr.prefix_op;
657 : 0 : fprintf(ar->f, "%s", prefix_op_str(op));
658 : :
659 : 0 : AstNode *child_node = node->data.prefix_op_expr.primary_expr;
660 [ # # ][ # # ]: 0 : bool new_grouped = child_node->type == NodeTypePrefixOpExpr || child_node->type == NodeTypePointerType;
661 : 0 : render_node_extra(ar, child_node, new_grouped);
662 [ # # ]: 0 : if (!grouped) fprintf(ar->f, ")");
663 : 0 : break;
664 : : }
665 : 0 : case NodeTypePointerType:
666 : : {
667 [ # # ]: 0 : if (!grouped) fprintf(ar->f, "(");
668 : 0 : const char *ptr_len_str = token_to_ptr_len_str(node->data.pointer_type.star_token);
669 : 0 : fprintf(ar->f, "%s", ptr_len_str);
670 [ # # ]: 0 : if (node->data.pointer_type.align_expr != nullptr) {
671 : 0 : fprintf(ar->f, "align(");
672 : 0 : render_node_grouped(ar, node->data.pointer_type.align_expr);
673 [ # # ]: 0 : if (node->data.pointer_type.bit_offset_start != nullptr) {
674 : 0 : assert(node->data.pointer_type.host_int_bytes != nullptr);
675 : :
676 : 0 : Buf offset_start_buf = BUF_INIT;
677 : 0 : buf_resize(&offset_start_buf, 0);
678 : 0 : bigint_append_buf(&offset_start_buf, node->data.pointer_type.bit_offset_start, 10);
679 : :
680 : 0 : Buf offset_end_buf = BUF_INIT;
681 : 0 : buf_resize(&offset_end_buf, 0);
682 : 0 : bigint_append_buf(&offset_end_buf, node->data.pointer_type.host_int_bytes, 10);
683 : :
684 : 0 : fprintf(ar->f, ":%s:%s ", buf_ptr(&offset_start_buf), buf_ptr(&offset_end_buf));
685 : : }
686 : 0 : fprintf(ar->f, ") ");
687 : : }
688 [ # # ]: 0 : if (node->data.pointer_type.is_const) {
689 : 0 : fprintf(ar->f, "const ");
690 : : }
691 [ # # ]: 0 : if (node->data.pointer_type.is_volatile) {
692 : 0 : fprintf(ar->f, "volatile ");
693 : : }
694 : :
695 : 0 : render_node_ungrouped(ar, node->data.pointer_type.op_expr);
696 [ # # ]: 0 : if (!grouped) fprintf(ar->f, ")");
697 : 0 : break;
698 : : }
699 : 0 : case NodeTypeFnCallExpr:
700 : : {
701 [ # # ]: 0 : if (node->data.fn_call_expr.is_builtin) {
702 : 0 : fprintf(ar->f, "@");
703 : : }
704 [ # # ]: 0 : if (node->data.fn_call_expr.is_async) {
705 : 0 : fprintf(ar->f, "async ");
706 : : }
707 : 0 : AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr;
708 [ # # ][ # # ]: 0 : bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypePointerType);
709 : 0 : render_node_extra(ar, fn_ref_node, grouped);
710 : 0 : fprintf(ar->f, "(");
711 [ # # ]: 0 : for (size_t i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
712 : 0 : AstNode *param = node->data.fn_call_expr.params.at(i);
713 [ # # ]: 0 : if (i != 0) {
714 : 0 : fprintf(ar->f, ", ");
715 : : }
716 : 0 : render_node_grouped(ar, param);
717 : : }
718 : 0 : fprintf(ar->f, ")");
719 : 0 : break;
720 : : }
721 : 0 : case NodeTypeArrayAccessExpr:
722 : 0 : render_node_ungrouped(ar, node->data.array_access_expr.array_ref_expr);
723 : 0 : fprintf(ar->f, "[");
724 : 0 : render_node_grouped(ar, node->data.array_access_expr.subscript);
725 : 0 : fprintf(ar->f, "]");
726 : 0 : break;
727 : 0 : case NodeTypeFieldAccessExpr:
728 : : {
729 : 0 : AstNode *lhs = node->data.field_access_expr.struct_expr;
730 : 0 : Buf *rhs = node->data.field_access_expr.field_name;
731 [ # # ]: 0 : if (lhs->type == NodeTypeErrorType) {
732 : 0 : fprintf(ar->f, "error");
733 : : } else {
734 : 0 : render_node_ungrouped(ar, lhs);
735 : : }
736 : 0 : fprintf(ar->f, ".");
737 : 0 : print_symbol(ar, rhs);
738 : 0 : break;
739 : : }
740 : 0 : case NodeTypePtrDeref:
741 : : {
742 : 0 : AstNode *lhs = node->data.ptr_deref_expr.target;
743 : 0 : render_node_ungrouped(ar, lhs);
744 : 0 : fprintf(ar->f, ".*");
745 : 0 : break;
746 : : }
747 : 0 : case NodeTypeUnwrapOptional:
748 : : {
749 : 0 : AstNode *lhs = node->data.unwrap_optional.expr;
750 : 0 : render_node_ungrouped(ar, lhs);
751 : 0 : fprintf(ar->f, ".?");
752 : 0 : break;
753 : : }
754 : 0 : case NodeTypeUndefinedLiteral:
755 : 0 : fprintf(ar->f, "undefined");
756 : 0 : break;
757 : 0 : case NodeTypeContainerDecl:
758 : : {
759 [ # # ]: 0 : if (!node->data.container_decl.is_root) {
760 : 0 : const char *layout_str = layout_string(node->data.container_decl.layout);
761 : 0 : const char *container_str = container_string(node->data.container_decl.kind);
762 : 0 : fprintf(ar->f, "%s%s", layout_str, container_str);
763 [ # # ]: 0 : if (node->data.container_decl.auto_enum) {
764 : 0 : fprintf(ar->f, "(enum");
765 : : }
766 [ # # ]: 0 : if (node->data.container_decl.init_arg_expr != nullptr) {
767 : 0 : fprintf(ar->f, "(");
768 : 0 : render_node_grouped(ar, node->data.container_decl.init_arg_expr);
769 : 0 : fprintf(ar->f, ")");
770 : : }
771 [ # # ]: 0 : if (node->data.container_decl.auto_enum) {
772 : 0 : fprintf(ar->f, ")");
773 : : }
774 : :
775 : 0 : fprintf(ar->f, " {\n");
776 : 0 : ar->indent += ar->indent_size;
777 : : }
778 [ # # ]: 0 : for (size_t field_i = 0; field_i < node->data.container_decl.fields.length; field_i += 1) {
779 : 0 : AstNode *field_node = node->data.container_decl.fields.at(field_i);
780 : 0 : assert(field_node->type == NodeTypeStructField);
781 : 0 : print_indent(ar);
782 : 0 : print_symbol(ar, field_node->data.struct_field.name);
783 [ # # ]: 0 : if (field_node->data.struct_field.type != nullptr) {
784 : 0 : fprintf(ar->f, ": ");
785 : 0 : render_node_grouped(ar, field_node->data.struct_field.type);
786 : : }
787 [ # # ]: 0 : if (field_node->data.struct_field.value != nullptr) {
788 : 0 : fprintf(ar->f, " = ");
789 : 0 : render_node_grouped(ar, field_node->data.struct_field.value);
790 : : }
791 : 0 : fprintf(ar->f, ",\n");
792 : : }
793 : :
794 [ # # ]: 0 : for (size_t decl_i = 0; decl_i < node->data.container_decl.decls.length; decl_i += 1) {
795 : 0 : AstNode *decls_node = node->data.container_decl.decls.at(decl_i);
796 : 0 : render_node_grouped(ar, decls_node);
797 : :
798 [ # # ][ # # ]: 0 : if (decls_node->type == NodeTypeUsingNamespace ||
799 [ # # ]: 0 : decls_node->type == NodeTypeVariableDeclaration ||
800 : 0 : decls_node->type == NodeTypeFnProto)
801 : : {
802 : 0 : fprintf(ar->f, ";");
803 : : }
804 : 0 : fprintf(ar->f, "\n");
805 : : }
806 : :
807 [ # # ]: 0 : if (!node->data.container_decl.is_root) {
808 : 0 : ar->indent -= ar->indent_size;
809 : 0 : print_indent(ar);
810 : 0 : fprintf(ar->f, "}");
811 : : }
812 : 0 : break;
813 : : }
814 : 0 : case NodeTypeContainerInitExpr:
815 : 0 : render_node_ungrouped(ar, node->data.container_init_expr.type);
816 [ # # ]: 0 : if (node->data.container_init_expr.kind == ContainerInitKindStruct) {
817 : 0 : fprintf(ar->f, "{\n");
818 : 0 : ar->indent += ar->indent_size;
819 : : } else {
820 : 0 : fprintf(ar->f, "{");
821 : : }
822 [ # # ]: 0 : for (size_t i = 0; i < node->data.container_init_expr.entries.length; i += 1) {
823 : 0 : AstNode *entry = node->data.container_init_expr.entries.at(i);
824 [ # # ]: 0 : if (entry->type == NodeTypeStructValueField) {
825 : 0 : Buf *name = entry->data.struct_val_field.name;
826 : 0 : AstNode *expr = entry->data.struct_val_field.expr;
827 : 0 : print_indent(ar);
828 : 0 : fprintf(ar->f, ".%s = ", buf_ptr(name));
829 : 0 : render_node_grouped(ar, expr);
830 : 0 : fprintf(ar->f, ",\n");
831 : : } else {
832 [ # # ]: 0 : if (i != 0)
833 : 0 : fprintf(ar->f, ", ");
834 : 0 : render_node_grouped(ar, entry);
835 : : }
836 : : }
837 [ # # ]: 0 : if (node->data.container_init_expr.kind == ContainerInitKindStruct) {
838 : 0 : ar->indent -= ar->indent_size;
839 : : }
840 : 0 : print_indent(ar);
841 : 0 : fprintf(ar->f, "}");
842 : 0 : break;
843 : 0 : case NodeTypeArrayType:
844 : : {
845 : 0 : fprintf(ar->f, "[");
846 [ # # ]: 0 : if (node->data.array_type.size) {
847 : 0 : render_node_grouped(ar, node->data.array_type.size);
848 : : }
849 : 0 : fprintf(ar->f, "]");
850 [ # # ]: 0 : if (node->data.array_type.is_const) {
851 : 0 : fprintf(ar->f, "const ");
852 : : }
853 : 0 : render_node_ungrouped(ar, node->data.array_type.child_type);
854 : 0 : break;
855 : : }
856 : 0 : case NodeTypeInferredArrayType:
857 : : {
858 : 0 : fprintf(ar->f, "[_]");
859 : 0 : render_node_ungrouped(ar, node->data.inferred_array_type.child_type);
860 : 0 : break;
861 : : }
862 : 0 : case NodeTypeAnyFrameType: {
863 : 0 : fprintf(ar->f, "anyframe");
864 [ # # ]: 0 : if (node->data.anyframe_type.payload_type != nullptr) {
865 : 0 : fprintf(ar->f, "->");
866 : 0 : render_node_grouped(ar, node->data.anyframe_type.payload_type);
867 : : }
868 : 0 : break;
869 : : }
870 : 0 : case NodeTypeErrorType:
871 : 0 : fprintf(ar->f, "anyerror");
872 : 0 : break;
873 : 0 : case NodeTypeAsmExpr:
874 : : {
875 : 0 : AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
876 [ # # ]: 0 : const char *volatile_str = (asm_expr->volatile_token != nullptr) ? " volatile" : "";
877 : 0 : fprintf(ar->f, "asm%s (\"%s\"\n", volatile_str, buf_ptr(&asm_expr->asm_template->data.str_lit.str));
878 : 0 : print_indent(ar);
879 : 0 : fprintf(ar->f, ": ");
880 [ # # ]: 0 : for (size_t i = 0; i < asm_expr->output_list.length; i += 1) {
881 : 0 : AsmOutput *asm_output = asm_expr->output_list.at(i);
882 : :
883 [ # # ]: 0 : if (i != 0) {
884 : 0 : fprintf(ar->f, ",\n");
885 : 0 : print_indent(ar);
886 : : }
887 : :
888 : 0 : fprintf(ar->f, "[%s] \"%s\" (",
889 : : buf_ptr(asm_output->asm_symbolic_name),
890 : : buf_ptr(asm_output->constraint));
891 [ # # ]: 0 : if (asm_output->return_type) {
892 : 0 : fprintf(ar->f, "-> ");
893 : 0 : render_node_grouped(ar, asm_output->return_type);
894 : : } else {
895 : 0 : fprintf(ar->f, "%s", buf_ptr(asm_output->variable_name));
896 : : }
897 : 0 : fprintf(ar->f, ")");
898 : : }
899 : 0 : fprintf(ar->f, "\n");
900 : 0 : print_indent(ar);
901 : 0 : fprintf(ar->f, ": ");
902 [ # # ]: 0 : for (size_t i = 0; i < asm_expr->input_list.length; i += 1) {
903 : 0 : AsmInput *asm_input = asm_expr->input_list.at(i);
904 : :
905 [ # # ]: 0 : if (i != 0) {
906 : 0 : fprintf(ar->f, ",\n");
907 : 0 : print_indent(ar);
908 : : }
909 : :
910 : 0 : fprintf(ar->f, "[%s] \"%s\" (",
911 : : buf_ptr(asm_input->asm_symbolic_name),
912 : : buf_ptr(asm_input->constraint));
913 : 0 : render_node_grouped(ar, asm_input->expr);
914 : 0 : fprintf(ar->f, ")");
915 : : }
916 : 0 : fprintf(ar->f, "\n");
917 : 0 : print_indent(ar);
918 : 0 : fprintf(ar->f, ": ");
919 [ # # ]: 0 : for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1) {
920 : 0 : Buf *reg_name = asm_expr->clobber_list.at(i);
921 [ # # ]: 0 : if (i != 0) fprintf(ar->f, ", ");
922 : 0 : fprintf(ar->f, "\"%s\"", buf_ptr(reg_name));
923 : : }
924 : 0 : fprintf(ar->f, ")");
925 : 0 : break;
926 : : }
927 : 0 : case NodeTypeWhileExpr:
928 : : {
929 [ # # ]: 0 : if (node->data.while_expr.name != nullptr) {
930 : 0 : fprintf(ar->f, "%s: ", buf_ptr(node->data.while_expr.name));
931 : : }
932 [ # # ]: 0 : const char *inline_str = node->data.while_expr.is_inline ? "inline " : "";
933 : 0 : fprintf(ar->f, "%swhile (", inline_str);
934 : 0 : render_node_grouped(ar, node->data.while_expr.condition);
935 : 0 : fprintf(ar->f, ") ");
936 [ # # ]: 0 : if (node->data.while_expr.var_symbol) {
937 : 0 : fprintf(ar->f, "|%s| ", buf_ptr(node->data.while_expr.var_symbol));
938 : : }
939 [ # # ]: 0 : if (node->data.while_expr.continue_expr) {
940 : 0 : fprintf(ar->f, ": (");
941 : 0 : render_node_grouped(ar, node->data.while_expr.continue_expr);
942 : 0 : fprintf(ar->f, ") ");
943 : : }
944 : 0 : render_node_grouped(ar, node->data.while_expr.body);
945 [ # # ]: 0 : if (node->data.while_expr.else_node) {
946 : 0 : fprintf(ar->f, " else ");
947 [ # # ]: 0 : if (node->data.while_expr.err_symbol) {
948 : 0 : fprintf(ar->f, "|%s| ", buf_ptr(node->data.while_expr.err_symbol));
949 : : }
950 : 0 : render_node_grouped(ar, node->data.while_expr.else_node);
951 : : }
952 : 0 : break;
953 : : }
954 : 0 : case NodeTypeBoolLiteral:
955 : : {
956 [ # # ]: 0 : const char *bool_str = node->data.bool_literal.value ? "true" : "false";
957 : 0 : fprintf(ar->f, "%s", bool_str);
958 : 0 : break;
959 : : }
960 : 0 : case NodeTypeIfBoolExpr:
961 : : {
962 : 0 : fprintf(ar->f, "if (");
963 : 0 : render_node_grouped(ar, node->data.if_bool_expr.condition);
964 : 0 : fprintf(ar->f, ") ");
965 : 0 : render_node_grouped(ar, node->data.if_bool_expr.then_block);
966 [ # # ]: 0 : if (node->data.if_bool_expr.else_node) {
967 : 0 : fprintf(ar->f, " else ");
968 : 0 : render_node_grouped(ar, node->data.if_bool_expr.else_node);
969 : : }
970 : 0 : break;
971 : : }
972 : 0 : case NodeTypeNullLiteral:
973 : : {
974 : 0 : fprintf(ar->f, "null");
975 : 0 : break;
976 : : }
977 : 0 : case NodeTypeIfErrorExpr:
978 : : {
979 : 0 : fprintf(ar->f, "if (");
980 : 0 : render_node_grouped(ar, node->data.if_err_expr.target_node);
981 : 0 : fprintf(ar->f, ") ");
982 [ # # ]: 0 : if (node->data.if_err_expr.var_symbol) {
983 [ # # ]: 0 : const char *ptr_str = node->data.if_err_expr.var_is_ptr ? "*" : "";
984 : 0 : const char *var_name = buf_ptr(node->data.if_err_expr.var_symbol);
985 : 0 : fprintf(ar->f, "|%s%s| ", ptr_str, var_name);
986 : : }
987 : 0 : render_node_grouped(ar, node->data.if_err_expr.then_node);
988 [ # # ]: 0 : if (node->data.if_err_expr.else_node) {
989 : 0 : fprintf(ar->f, " else ");
990 [ # # ]: 0 : if (node->data.if_err_expr.err_symbol) {
991 : 0 : fprintf(ar->f, "|%s| ", buf_ptr(node->data.if_err_expr.err_symbol));
992 : : }
993 : 0 : render_node_grouped(ar, node->data.if_err_expr.else_node);
994 : : }
995 : 0 : break;
996 : : }
997 : 0 : case NodeTypeIfOptional:
998 : : {
999 : 0 : fprintf(ar->f, "if (");
1000 : 0 : render_node_grouped(ar, node->data.test_expr.target_node);
1001 : 0 : fprintf(ar->f, ") ");
1002 [ # # ]: 0 : if (node->data.test_expr.var_symbol) {
1003 [ # # ]: 0 : const char *ptr_str = node->data.test_expr.var_is_ptr ? "*" : "";
1004 : 0 : const char *var_name = buf_ptr(node->data.test_expr.var_symbol);
1005 : 0 : fprintf(ar->f, "|%s%s| ", ptr_str, var_name);
1006 : : }
1007 : 0 : render_node_grouped(ar, node->data.test_expr.then_node);
1008 [ # # ]: 0 : if (node->data.test_expr.else_node) {
1009 : 0 : fprintf(ar->f, " else ");
1010 : 0 : render_node_grouped(ar, node->data.test_expr.else_node);
1011 : : }
1012 : 0 : break;
1013 : : }
1014 : 0 : case NodeTypeSwitchExpr:
1015 : : {
1016 : 0 : AstNodeSwitchExpr *switch_expr = &node->data.switch_expr;
1017 : 0 : fprintf(ar->f, "switch (");
1018 : 0 : render_node_grouped(ar, switch_expr->expr);
1019 : 0 : fprintf(ar->f, ") {\n");
1020 : 0 : ar->indent += ar->indent_size;
1021 : :
1022 [ # # ]: 0 : for (size_t prong_i = 0; prong_i < switch_expr->prongs.length; prong_i += 1) {
1023 : 0 : AstNode *prong_node = switch_expr->prongs.at(prong_i);
1024 : 0 : AstNodeSwitchProng *switch_prong = &prong_node->data.switch_prong;
1025 : 0 : print_indent(ar);
1026 [ # # ]: 0 : for (size_t item_i = 0; item_i < switch_prong->items.length; item_i += 1) {
1027 : 0 : AstNode *item_node = switch_prong->items.at(item_i);
1028 [ # # ]: 0 : if (item_i != 0)
1029 : 0 : fprintf(ar->f, ", ");
1030 [ # # ]: 0 : if (item_node->type == NodeTypeSwitchRange) {
1031 : 0 : AstNode *start_node = item_node->data.switch_range.start;
1032 : 0 : AstNode *end_node = item_node->data.switch_range.end;
1033 : 0 : render_node_grouped(ar, start_node);
1034 : 0 : fprintf(ar->f, "...");
1035 : 0 : render_node_grouped(ar, end_node);
1036 : : } else {
1037 : 0 : render_node_grouped(ar, item_node);
1038 : : }
1039 : : }
1040 [ # # ]: 0 : const char *else_str = (switch_prong->items.length == 0) ? "else" : "";
1041 : 0 : fprintf(ar->f, "%s => ", else_str);
1042 [ # # ]: 0 : if (switch_prong->var_symbol) {
1043 [ # # ]: 0 : const char *star_str = switch_prong->var_is_ptr ? "*" : "";
1044 : 0 : Buf *var_name = switch_prong->var_symbol->data.symbol_expr.symbol;
1045 : 0 : fprintf(ar->f, "|%s%s| ", star_str, buf_ptr(var_name));
1046 : : }
1047 : 0 : render_node_grouped(ar, switch_prong->expr);
1048 : 0 : fprintf(ar->f, ",\n");
1049 : : }
1050 : :
1051 : 0 : ar->indent -= ar->indent_size;
1052 : 0 : print_indent(ar);
1053 : 0 : fprintf(ar->f, "}");
1054 : 0 : break;
1055 : : }
1056 : 0 : case NodeTypeCompTime:
1057 : : {
1058 : 0 : fprintf(ar->f, "comptime ");
1059 : 0 : render_node_grouped(ar, node->data.comptime_expr.expr);
1060 : 0 : break;
1061 : : }
1062 : 0 : case NodeTypeForExpr:
1063 : : {
1064 [ # # ]: 0 : if (node->data.for_expr.name != nullptr) {
1065 : 0 : fprintf(ar->f, "%s: ", buf_ptr(node->data.for_expr.name));
1066 : : }
1067 [ # # ]: 0 : const char *inline_str = node->data.for_expr.is_inline ? "inline " : "";
1068 : 0 : fprintf(ar->f, "%sfor (", inline_str);
1069 : 0 : render_node_grouped(ar, node->data.for_expr.array_expr);
1070 : 0 : fprintf(ar->f, ") ");
1071 [ # # ]: 0 : if (node->data.for_expr.elem_node) {
1072 : 0 : fprintf(ar->f, "|");
1073 [ # # ]: 0 : if (node->data.for_expr.elem_is_ptr)
1074 : 0 : fprintf(ar->f, "*");
1075 : 0 : render_node_grouped(ar, node->data.for_expr.elem_node);
1076 [ # # ]: 0 : if (node->data.for_expr.index_node) {
1077 : 0 : fprintf(ar->f, ", ");
1078 : 0 : render_node_grouped(ar, node->data.for_expr.index_node);
1079 : : }
1080 : 0 : fprintf(ar->f, "| ");
1081 : : }
1082 : 0 : render_node_grouped(ar, node->data.for_expr.body);
1083 [ # # ]: 0 : if (node->data.for_expr.else_node) {
1084 : 0 : fprintf(ar->f, " else");
1085 : 0 : render_node_grouped(ar, node->data.for_expr.else_node);
1086 : : }
1087 : 0 : break;
1088 : : }
1089 : 0 : case NodeTypeContinue:
1090 : : {
1091 : 0 : fprintf(ar->f, "continue");
1092 [ # # ]: 0 : if (node->data.continue_expr.name != nullptr) {
1093 : 0 : fprintf(ar->f, " :%s", buf_ptr(node->data.continue_expr.name));
1094 : : }
1095 : 0 : break;
1096 : : }
1097 : 0 : case NodeTypeUnreachable:
1098 : : {
1099 : 0 : fprintf(ar->f, "unreachable");
1100 : 0 : break;
1101 : : }
1102 : 0 : case NodeTypeSliceExpr:
1103 : : {
1104 : 0 : render_node_ungrouped(ar, node->data.slice_expr.array_ref_expr);
1105 : 0 : fprintf(ar->f, "[");
1106 : 0 : render_node_grouped(ar, node->data.slice_expr.start);
1107 : 0 : fprintf(ar->f, "..");
1108 [ # # ]: 0 : if (node->data.slice_expr.end)
1109 : 0 : render_node_grouped(ar, node->data.slice_expr.end);
1110 : 0 : fprintf(ar->f, "]");
1111 : 0 : break;
1112 : : }
1113 : 0 : case NodeTypeCatchExpr:
1114 : : {
1115 : 0 : render_node_ungrouped(ar, node->data.unwrap_err_expr.op1);
1116 : 0 : fprintf(ar->f, " catch ");
1117 [ # # ]: 0 : if (node->data.unwrap_err_expr.symbol) {
1118 : 0 : Buf *var_name = node->data.unwrap_err_expr.symbol->data.symbol_expr.symbol;
1119 : 0 : fprintf(ar->f, "|%s| ", buf_ptr(var_name));
1120 : : }
1121 : 0 : render_node_ungrouped(ar, node->data.unwrap_err_expr.op2);
1122 : 0 : break;
1123 : : }
1124 : 0 : case NodeTypeErrorSetDecl:
1125 : : {
1126 : 0 : fprintf(ar->f, "error {\n");
1127 : 0 : ar->indent += ar->indent_size;
1128 : :
1129 [ # # ]: 0 : for (size_t i = 0; i < node->data.err_set_decl.decls.length; i += 1) {
1130 : 0 : AstNode *field_node = node->data.err_set_decl.decls.at(i);
1131 : 0 : assert(field_node->type == NodeTypeSymbol);
1132 : 0 : print_indent(ar);
1133 : 0 : print_symbol(ar, field_node->data.symbol_expr.symbol);
1134 : 0 : fprintf(ar->f, ",\n");
1135 : : }
1136 : :
1137 : 0 : ar->indent -= ar->indent_size;
1138 : 0 : print_indent(ar);
1139 : 0 : fprintf(ar->f, "}");
1140 : 0 : break;
1141 : : }
1142 : 0 : case NodeTypeResume:
1143 : : {
1144 : 0 : fprintf(ar->f, "resume ");
1145 : 0 : render_node_grouped(ar, node->data.resume_expr.expr);
1146 : 0 : break;
1147 : : }
1148 : 0 : case NodeTypeAwaitExpr:
1149 : : {
1150 : 0 : fprintf(ar->f, "await ");
1151 : 0 : render_node_grouped(ar, node->data.await_expr.expr);
1152 : 0 : break;
1153 : : }
1154 : 0 : case NodeTypeSuspend:
1155 : : {
1156 [ # # ]: 0 : if (node->data.suspend.block != nullptr) {
1157 : 0 : fprintf(ar->f, "suspend ");
1158 : 0 : render_node_grouped(ar, node->data.suspend.block);
1159 : : } else {
1160 : 0 : fprintf(ar->f, "suspend\n");
1161 : : }
1162 : 0 : break;
1163 : : }
1164 : 0 : case NodeTypeEnumLiteral:
1165 : : {
1166 : 0 : fprintf(ar->f, ".%s", buf_ptr(&node->data.enum_literal.identifier->data.str_lit.str));
1167 : 0 : break;
1168 : : }
1169 : 0 : case NodeTypeParamDecl:
1170 : : case NodeTypeTestDecl:
1171 : : case NodeTypeStructField:
1172 : : case NodeTypeUsingNamespace:
1173 : 0 : zig_panic("TODO more ast rendering");
1174 : : }
1175 : 0 : }
1176 : :
1177 : :
1178 : 0 : void ast_render(FILE *f, AstNode *node, int indent_size) {
1179 : 0 : AstRender ar = {0};
1180 : 0 : ar.f = f;
1181 : 0 : ar.indent_size = indent_size;
1182 : 0 : ar.indent = 0;
1183 : :
1184 : 0 : render_node_grouped(&ar, node);
1185 : 0 : }
1186 : :
1187 : 0 : void AstNode::src() {
1188 : 0 : fprintf(stderr, "%s:%" ZIG_PRI_usize ":%" ZIG_PRI_usize "\n",
1189 : 0 : buf_ptr(this->owner->data.structure.root_struct->path),
1190 : 0 : this->line + 1, this->column + 1);
1191 : 0 : }
|