function void expr_print(Expr *expr); function B32 typespec_print(Typespec *spec); global S64 indent; #define println(...) do{ printf("\n"); print_indent(); printf(__VA_ARGS__); }while(0) #define AST_CAST(item, T) T *item = (T *)item; assert(item->kind == AST_##Kind #define AST_Iter(parent, name, T) for(T *name = (T *)(parent)->first; name; name=(T *)name->next) // , assert(name->kind == AST_##type 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("size_expr("); 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("size_type("); 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); token_print(expr->token); 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 B32 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; } return true; } function void print_assign_expr(Expr *expr){ if(expr){ printf(" = "); expr_print(expr); } } function void ast_print(AST *in){ //print_notes(p, node->first_note); switch(in->kind) { case AST_Program: { AST_Parent *node = (AST_Parent *)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("%s: ", node->name.s.str); if(node->typespec) typespec_print(node->typespec); 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(""); typespec_print(node->ret); printf(" %s", node->name.s.str); printf("("); AST_Iter(node, arg, Decl_Func_Arg){ printf("%s: ", arg->name.s.str); typespec_print(arg->typespec); if((AST *)arg != node->last) printf(", "); } printf(");"); } 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); } 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_Iter(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; default: {invalid_codepath;} break; } }