function void expr_print(Expr *expr); function void typespec_print(Typespec *spec); global S64 indent; #define println(...) do{ printf("\n"); print_indent(); printf(__VA_ARGS__); }while(0) function void print_indent(){ for(S64 i = 0; i < indent*2; i++) printf(" "); } function void token_print(Token *token){ printf("%.*s", (S32)token->len, token->str); } function void expr_compound_print(Expr_Compound_Field *field){ switch(field->kind){ case COMPOUND_Default: { expr_print(field->init); }break; case COMPOUND_Named: { printf(".%s = ", field->name.s.str); expr_print(field->init); }break; case COMPOUND_Index: { printf("["); expr_print(field->index); printf("] = "); expr_print(field->init); }break; default: invalid_codepath; } } function void expr_print(Expr *expr){ switch(expr->kind) { case EK_Int:case EK_String:case EK_Identifier: { token_print(expr->token); } break; case EK_SizeExpr:{ printf("sizeof("); expr_print(expr->size_expr.expr); printf(")"); }break; case EK_Compound:{ if(expr->compound.typespec){ printf("("); typespec_print(expr->compound.typespec); printf(")"); } printf("{"); for(Expr_Compound_Field *n = expr->compound.first; n; n=n->next){ expr_compound_print(n); if(n!=expr->compound.last) printf(","); } printf("}"); } break; case EK_SizeType:{ printf("sizeof("); typespec_print(expr->size_type.typespec); printf(")"); }break; case EK_Paren:{ printf("("); expr_print(expr->paren.expr); printf(")"); } break; case EK_Field:{ expr_print(expr->field.expr); printf(".%s", expr->field.name.s.str); } break; case EK_Binary:{ printf("("); expr_print(expr->binary.left); printf("%s", token_kind_string[expr->binary.op]); expr_print(expr->binary.right); printf(")"); } break; case EK_PostfixUnary:{ printf("("); expr_print(expr->unary.expr); token_print(expr->token); printf(")"); } break; case EK_Unary:{ printf("("); token_print(expr->token); expr_print(expr->unary.expr); printf(")"); } break; case EK_Ternary:{ printf("("); expr_print(expr->ternary.cond); printf("?"); expr_print(expr->ternary.on_true); printf(":"); expr_print(expr->ternary.on_false); printf(")"); } break; case EK_Cast:{ printf("("); printf("("); typespec_print(expr->cast.typespec); printf(")"); expr_print(expr->cast.expr); printf(")"); } break; case EK_Index:{ expr_print(expr->index.atom); printf("["); expr_print(expr->index.index); printf("]"); }break; case EK_Call:{ expr_print(expr->call.atom); printf("("); for(Expr_Compound_Field *n = expr->call.first; n; n=n->next){ expr_compound_print(n); if(n!=expr->call.last) printf(","); } printf(")"); }break; default: {invalid_codepath;} break; } } function void typespec_print(Typespec *spec){ switch(spec->kind) { case TS_Name: { printf("%s", spec->name.s.str); } break; case TS_NamedArgument: { printf("%s: ", spec->named.name.s.str); typespec_print(spec->named.base); }break; case TS_Pointer: { typespec_print(spec->base); printf("*"); } break; case TS_Array: { typespec_print(spec->arr.base); printf("["); expr_print(spec->arr.size); printf("]"); } break; case TS_Function: { printf("("); for(Typespec *n = spec->func.first; n; n=n->next){ typespec_print(n); if(n!=spec->func.last) printf(", "); } printf(")"); typespec_print(spec->func.ret); } break; default: {invalid_codepath;} break; } } function void print_assign_expr(Expr *expr){ if(expr){ printf(" = "); expr_print(expr); } } function void ast_print(AST *in){ switch(in->kind) { case AST_Program: { Program *node = (Program *)in; for(AST *n = node->first; n; n=n->next){ ast_print(n); printf("\n"); } } break; case AST_Decl_Const: case AST_Decl_Var:{ Decl_Var *node = (Decl_Var *)in; println(""); if(node->typespec) typespec_print(node->typespec); printf(" %s", node->name.s.str); print_assign_expr(node->expr); } break; case AST_Decl_Typedef:{ Decl_Typedef *node = (Decl_Typedef *)in; println("typedef %s ", node->name.s.str); typespec_print(node->typespec); printf(";"); } break; case AST_Decl_Func:{ Decl_Func *node = (Decl_Func *)in; println("function "); typespec_print(node->ret); printf("\n%s", node->name.s.str); printf("("); AST_IterT(node, arg, Decl_Func_Arg){ typespec_print(arg->typespec); printf(" %s", arg->name.s.str); if((AST *)arg != node->last) printf(", "); } printf(")"); if(!node->is_incomplete){ ast_print((AST *)node->body); } } break; case AST_Decl_Struct: case AST_Decl_Union :{ Decl_Struct *node = (Decl_Struct *)in; const char *struct_name = node->kind==AST_Decl_Struct ? "struct" : "union"; println("%s %s{", struct_name, node->name.s.str?(char*)node->name.s.str:""); indent++; for(AST *n = node->first; n; n=n->next){ ast_print(n); printf(";"); } indent--; println("};"); } break; case AST_Decl_SubStruct: case AST_Decl_SubUnion :{ Decl_Struct *node = (Decl_Struct *)in; const char *struct_name = node->kind==AST_Decl_Struct ? "struct" : "union"; println("%s %s{", struct_name, node->name.s.str?(char*)node->name.s.str:""); indent++; for(AST *n = node->first; n; n=n->next){ ast_print(n); } indent--; println("};"); } break; case AST_Decl_Enum:{ Decl_Enum *node = (Decl_Enum *)in; println("enum %s : ", node->name.s.str); typespec_print(node->typespec); printf("{"); indent++; AST_IterT(node, n, Decl_Enum_Child){ //print_notes(p, n->first_note); println("%s", n->name.s.str); print_assign_expr(n->expr); printf(","); } indent--; println("};"); } break; case AST_Stmt_Init:{ Stmt_Init *node = (Stmt_Init *)in; if(node->typespec) typespec_print(node->typespec); printf(" %s", node->name.s.str); print_assign_expr(node->expr); }break; case AST_Stmt_Assign:{ Stmt_Assign *node = (Stmt_Assign *)in; expr_print(node->left); token_print(node->pos); expr_print(node->right); }break; case AST_Stmt_Expr:{ Stmt_Expr *node = (Stmt_Expr *)in; expr_print(node->expr); }break; case AST_Stmt_Defer:{ Stmt_Defer *node = (Stmt_Defer *)in; printf("defer "); ast_print((AST *)node->body); }break; case AST_Stmt_Return:{ Stmt_Return *node = (Stmt_Return *)in; printf("return "); expr_print(node->expr); }break; case AST_Stmt_Block:{ Stmt_Block *node = (Stmt_Block *)in; printf(" {"); indent++; AST_IterT(node, n, AST){ println(""); ast_print(n); if(n->kind != AST_Stmt_If && n->kind != AST_Stmt_For && n->kind != AST_Stmt_Else && n->kind != AST_Stmt_ElseIf) printf(";"); } indent--; println("}"); }break; case AST_Stmt_Else:{ Stmt_Else *node = (Stmt_Else *)in; printf("else "); ast_print((AST *)node->body); }break; case AST_Stmt_ElseIf:{ Stmt_ElseIf *node = (Stmt_ElseIf *)in; printf("else if "); expr_print(node->condition); ast_print((AST *)node->body); }break; case AST_Stmt_If:{ Stmt_If *node = (Stmt_If *)in; printf("if "); expr_print(node->condition); ast_print((AST *)node->body); AST_IterT(node, n, AST){ ast_print(n); } }break; case AST_Stmt_For:{ Stmt_For *node = (Stmt_For *)in; printf("for("); if(node->on_begin) ast_print(node->on_begin); printf(";"); if(node->condition) expr_print(node->condition); printf(";"); if(node->on_iter) ast_print(node->on_iter); printf(")"); ast_print((AST *)node->body); }break; default: {invalid_codepath;} break; } }