// @todo @cleanup ?? // :PrinterCleanup // Instead of relying on global state, this probably should // use a String_Builder or some kind of Builder context + macros CORE_Static String core_type_to_string(Ast_Type *type) { // @todo: use get_name_of_type instead of duplicating the typename dispatch table switch (type->kind) { case TYPE_NONE: return ""_s; break; case TYPE_S64: return "S64"_s; break; case TYPE_S32: return "S32"_s; break; case TYPE_S16: return "S16"_s; break; case TYPE_S8: return "S8"_s; break; case TYPE_CHAR: return "char"_s; case TYPE_UCHAR: return "uchar"_s; case TYPE_INT: return "int"_s; case TYPE_UINT: return "uint"_s; case TYPE_LONG: return "long"_s; case TYPE_ULONG: return "ulong"_s; case TYPE_LLONG: return "llong"_s; case TYPE_ULLONG: return "ullong"_s; case TYPE_SHORT: return "short"_s; case TYPE_USHORT: return "ushort"_s; case TYPE_U64: return "U64"_s; break; case TYPE_U32: return "U32"_s; break; case TYPE_U16: return "U16"_s; break; case TYPE_U8: return "U8"_s; break; case TYPE_F32: return "F32"_s; break; case TYPE_F64: return "F64"_s; break; case TYPE_BOOL: return "bool"_s; break; case TYPE_STRING: return "String"_s; break; case TYPE_VOID: return "void"_s; break; case TYPE_POINTER: { String base = core_type_to_string(type->base); return pctx->fmt("*%Q", base); } break; case TYPE_LAMBDA: { String_Builder *b = &pctx->helper_builder; b->addf("("); Array &args = type->func.args; For(args) { String t = core_type_to_string(it); b->addf("%Q", t); if (!args.is_last(it)) b->addf(", "); } b->addf(")"); if (type->func.ret) { String t = core_type_to_string(type->func.ret); b->addf("%Q", t); } String result = string_flatten(pctx->perm, b); return result; } break; case TYPE_STRUCT: case TYPE_UNION: case TYPE_ENUM: { // @fixme: we probably want a string on Ast_Type // so that we don't have to reach into Ast_Decl // for Structs Enums etc. Ast_Decl *decl = (Ast_Decl *)type->ast; return decl->name.s; } break; case TYPE_ARRAY: { String base = core_type_to_string(type->base); return pctx->fmt("[%u]%Q", type->arr.size, base); } break; case TYPE_SLICE: { String base = core_type_to_string(type->base); return pctx->fmt("[]%Q", base); } break; case TYPE_TUPLE: { invalid_codepath; } break; case TYPE_TYPE: return "Type"_s; break; case TYPE_UNTYPED_BOOL: return "UntypedBool"_s; break; case TYPE_UNTYPED_INT: return "UntypedInt"_s; break; case TYPE_UNTYPED_FLOAT: return "UntypedFloat"_s; break; case TYPE_UNTYPED_STRING: return "UntypedString"_s; break; case TYPE_COMPLETING: invalid_codepath; break; case TYPE_INCOMPLETE: invalid_codepath; break; case TYPE_POLYMORPH: invalid_codepath; break; invalid_default_case; } invalid_return; } void core__stringify(Ast *ast) { if (!ast) return; gen("@%u", ast->di); switch (ast->kind) { case AST_SCOPE: { Ast_Scope *n = (Ast_Scope *)ast; global_indent += 1; genln("@%u", n->di); For(n->decls) { genln(""); core__stringify(it); } For(n->stmts) { genln(""); core__stringify(it); } global_indent -= 1; } break; case AST_MODULE: invalid_codepath; break; case AST_FILE: invalid_codepath; break; case AST_IDENT: { Ast_Atom *n = (Ast_Atom *)ast; gen("%Q", n->intern_val); } break; case AST_VALUE: { Ast_Atom *n = (Ast_Atom *)ast; //@todo: proper value gen("%Q", n->pos->string); } break; case AST_INDEX: { Ast_Index *n = (Ast_Index *)ast; core__stringify(n->expr); gen("["); core__stringify(n->index); gen("]"); } break; case AST_UNARY: { Ast_Unary *n = (Ast_Unary *)ast; gen("%Q", n->pos->string); core__stringify(n->expr); } break; case AST_BINARY: { Ast_Binary *n = (Ast_Binary *)ast; core__stringify(n->left); gen("%Q", n->pos->string); core__stringify(n->right); } break; case AST_CALL_ITEM: { Ast_Call_Item *n = (Ast_Call_Item *)ast; if (n->call_flags & CALL_INDEX) { core__stringify(n->index); gen(" = "); } else if (n->call_flags & CALL_NAME) { core__stringify(n->name); gen(" = "); } core__stringify(n->item); } break; case AST_CALL: { Ast_Call *n = (Ast_Call *)ast; core__stringify(n->name); gen("("); For(n->exprs) { core__stringify(it); if (!n->exprs.is_last(it)) gen(","); } gen(")"); } break; case AST_COMPOUND: { Ast_Call *n = (Ast_Call *)ast; core__stringify(n->name); gen("{"); global_indent += 1; For(n->exprs) { genln(""); core__stringify(it); gen(","); } global_indent -= 1; genln("}"); } break; case AST_TYPE_OF: gen("TypeOf"); goto builtin; case AST_LENGTH_OF: gen("LengthOf"); goto builtin; case AST_ALIGN_OF: gen("AlignOf"); goto builtin; case AST_SIZE_OF: gen("SizeOf"); goto builtin; case AST_RUNTIME_ASSERT: gen("Assert"); goto builtin; case AST_CONSTANT_ASSERT: gen("#Assert"); goto builtin; builtin : { Ast_Builtin *n = (Ast_Builtin *)ast; gen("("); core__stringify(n->expr); gen(")"); } break; case AST_SWITCH: { Ast_Switch *n = (Ast_Switch *)ast; core__stringify(n->value); For(n->cases) { core__stringify(it); } core__stringify(n->default_scope); } break; case AST_SWITCH_CASE: { Ast_Switch_Case *n = (Ast_Switch_Case *)ast; For(n->labels) { core__stringify(it); } core__stringify(n->scope); } break; case AST_VAR_UNPACK: { Ast_Var_Unpack *n = (Ast_Var_Unpack *)ast; For(n->vars) { core__stringify(it); if (!n->vars.is_last(it)) gen(","); } gen(" = "); core__stringify(n->expr); } break; case AST_PASS: { genln("pass"); } break; case AST_BREAK: { genln("break"); } break; case AST_NAMESPACE: { Ast_Decl *n = (Ast_Decl *)ast; gen("%Q :: NAMESPACE", n->name); } break; case AST_UNION: case AST_STRUCT: { Ast_Decl *n = (Ast_Decl *)ast; genln("%Q :: %s", n->name, n->kind == AST_STRUCT ? "struct" : "union"); core__stringify(n->scope); } break; case AST_ENUM: { Ast_Decl *n = (Ast_Decl *)ast; genln("%Q :: enum", n->name); core__stringify(n->scope); } break; case AST_LAMBDA: { Ast_Decl *n = (Ast_Decl *)ast; genln("%Q :: ", n->name); core__stringify(n->lambda); // @cleanup } break; // @cleanup: what is this used for? case AST_TYPE: { invalid_codepath; } break; case AST_CONST: { Ast_Decl *n = (Ast_Decl *)ast; gen("%Q :: CONST value @todo", n->name); } break; case AST_VAR: { Ast_Decl *n = (Ast_Decl *)ast; gen("%Q: %Q", n->name, core_type_to_string(n->type)); if (n->expr) { gen(" = "); core__stringify(n->expr); } } break; case AST_ARRAY: { Ast_Array *n = (Ast_Array *)ast; gen("["); core__stringify(n->expr); gen("]"); core__stringify(n->base); } break; case AST_FOR: { Ast_For *n = (Ast_For *)ast; gen("for "); core__stringify(n->init); if (n->cond) gen(", "); core__stringify(n->cond); if (n->iter) gen(", "); core__stringify(n->iter); core__stringify(n->scope); } break; case AST_IF: { Ast_If *n = (Ast_If *)ast; int i = 0; For(n->ifs) { if (i == 0) gen("if "); else if (it->expr) gen("elif "); else gen("else "); core__stringify(it->expr); if (it->init) gen(", "); core__stringify(it->init); core__stringify(it->scope); i += 1; } } break; case AST_RETURN: { Ast_Return *n = (Ast_Return *)ast; gen("return "); For(n->expr) { core__stringify(it); if (!n->expr.is_last(it)) gen(", "); } } break; case AST_LAMBDA_EXPR: { Ast_Lambda *n = (Ast_Lambda *)ast; gen("("); For(n->args) { core__stringify(it); if (!n->args.is_last(it)) gen(", "); } gen(")"); if (n->ret.len) gen(": "); For(n->ret) { core__stringify(it); if (!n->ret.is_last(it)) gen(", "); } core__stringify(n->scope); } break; default: assert(!"Invalid default case"); } } String core_stringify(Ast *ast) { core__stringify(ast); String result = string_flatten(pctx->perm, &pctx->gen); pctx->gen.reset(); return result; }