#define gen(...) pctx->gen.addf(__VA_ARGS__) #define genln(...) do{gen("\n"); gen_indent(); gen(__VA_ARGS__); }while(0) global S32 global_indent; function void gen_indent(){ for(S32 i = 0; i < global_indent; i++) gen(" "); } // @todo: Gen complicated decl //array 10 ( pointer (pointer array 5 int a)) // int (*(*(a[5])))[10] // // 1 Get to the bottom // 2 Add variable name // 3 Going backwards add arrays and pointers in parens // 4 Add type name on the left side function void gen_simple_decl_prefix(Ast_Resolved_Type *ast){ switch(ast->kind){ case TYPE_INT: gen("int "); break; case TYPE_BOOL: gen("bool "); break; case TYPE_UNSIGNED: gen("unsigned "); break; case TYPE_STRING: gen("String "); break; case TYPE_VOID: gen("void "); break; case TYPE_POINTER:{gen_simple_decl_prefix(ast->base); gen("*");} break; case TYPE_ARRAY: gen_simple_decl_prefix(ast->base); break; case TYPE_LAMBDA:break; case TYPE_STRUCT: { auto constant = (Ast_Const *)ast->ast->parent; auto name = constant->name; gen("%s ", name.str); }break; invalid_default_case; } } function void gen_simple_decl_postfix(Ast_Resolved_Type *ast){ switch(ast->kind){ case TYPE_INT: break; case TYPE_BOOL: break; case TYPE_UNSIGNED: break; case TYPE_STRING: break; case TYPE_VOID: break; case TYPE_POINTER: gen_simple_decl_postfix(ast->base); break; case TYPE_ARRAY: gen("[%d]", (int)ast->arr.size); gen_simple_decl_postfix(ast->arr.base); break; case TYPE_LAMBDA:break; case TYPE_STRUCT:break; invalid_default_case; } } function void gen_simple_decl(Ast_Resolved_Type *ast, Intern_String name){ if(ast->kind == TYPE_LAMBDA) { gen_simple_decl_prefix(ast->func.ret); gen("(*%s)(", name.str); For(ast->func.args){ gen_simple_decl_prefix(it); if(&it != ast->func.args.end() - 1) gen(", "); } gen(")"); } else{ gen_simple_decl_prefix(ast); if(name.len) { gen("%s", name.str); gen_simple_decl_postfix(ast); } } } function void gen_expr(Ast_Expr *ast){ switch(ast->kind){ CASE(IDENT, Atom){ gen("%s", node->intern_val.str); BREAK(); } CASE(INT, Atom){ gen("%lld", node->int_val); BREAK(); } CASE(STR, Atom){ gen("LIT(\"%s\")", node->intern_val.str); BREAK(); } CASE(INDEX, Index){ gen_expr(node->expr); gen("["); gen_expr(node->index); gen("]"); BREAK(); } CASE(BINARY, Binary){ gen("("); gen_expr(node->left); gen("%s", token_kind_string(node->op).str); gen_expr(node->right); gen(")"); BREAK(); } CASE(UNARY, Unary){ switch(node->op){ case TK_Pointer: { gen("(*"); gen_expr(node->expr); gen(")"); } break; case TK_Dereference: { gen("(&"); gen_expr(node->expr); gen(")"); } break; invalid_default_case; } BREAK(); } CASE(CAST, Cast){ gen("("); gen("("); gen_simple_decl(resolved_type_get(node->typespec), {}); gen(")"); gen_expr(node->expr); gen(")"); BREAK(); } CASE(CALL, Call){ // @todo: Reach into map instead of direct lookup if(node->type->kind == TYPE_STRUCT){ // @todo: Should this be type_type maybe??? gen("("); gen_simple_decl(node->type, {}); gen(")"); gen("{"); For(node->exprs){ auto comp = it; if(comp->name){ gen("."); gen_expr(comp->name); gen(" = "); } if(comp->index){ gen("["); gen_expr(comp->index); gen("] = "); } assert(comp->item); gen_expr(comp->item); if(!node->exprs.is_last(&it)) gen(", "); } gen("}"); } else{ gen_expr(node->name); gen("("); For(node->exprs){ gen_expr(it->item); if(!node->exprs.is_last(&it)) gen(", "); } gen(")"); } BREAK(); } invalid_default_case; } } function void gen_ast(Ast *ast); function void gen_block(Ast_Block *block){ gen("{"); global_indent++; For(block->stmts) { genln(""); gen_ast(it); } global_indent--; genln("}"); } function void gen_ast(Ast *ast){ switch(ast->kind){ CASE(PACKAGE, Package){ For(node->ordered) { genln(""); gen_ast(it); } BREAK(); } CASE(RETURN, Return){ gen("return"); if(node->expr){ gen(" "); gen_expr(node->expr); } gen(";"); BREAK(); } CASE(VAR, Var){ Sym *sym = resolved_get(node); gen_simple_decl(sym->type, node->name); if(node->expr){ gen(" = "); gen_expr(node->expr); } gen(";"); BREAK(); } CASE(INIT, Init){ Sym *sym = resolved_get(node); gen_simple_decl(sym->type, node->ident->intern_val); if(node->expr){ gen(" = "); gen_expr(node->expr); } gen(";"); BREAK(); } CASE(IF, If){ For(node->ifs){ if(it->init) gen_ast(it->init); if(node->ifs.is_first(&it)){ genln("if("); gen_expr(it->expr); gen(")"); gen_block(it->block); } else{ genln("else"); if(it->expr){ gen(" if("); gen_expr(it->expr); gen(")"); } gen_block(it->block); } } BREAK(); } CASE(CONST, Const){ Sym *sym = resolved_get(node); if(sym->type->kind == TYPE_LAMBDA){ if(node->value->kind == AST_LAMBDA){ Ast_Lambda *lambda = (Ast_Lambda *)node->value; gen("static "); Ast_Resolved_Type *ret = resolved_type_get(lambda->ret); gen_simple_decl(ret, node->name); gen("("); For(lambda->args){ assert(it->kind == AST_LAMBDA_ARG); Ast_Resolved_Type *type = resolved_type_get(it->typespec); gen_simple_decl(type, it->name); if(&it != (lambda->args.end() - 1)) gen(", "); } gen(")"); if(lambda->block) { gen_block(lambda->block); } else gen(";"); } else{ gen_simple_decl(sym->type, node->name); gen(" = "); gen_expr((Ast_Expr *)node->value); gen(";"); } } else if(sym->type == type_int){ gen("enum { %s = %lld };", node->name.str, sym->int_val); } else if(sym->type == type_string){ gen("String %s = LIT(\"%s\");", node->name.str, sym->intern_val.str); } else if(sym->type == type_type){ if(sym->type_val->kind == TYPE_STRUCT){ Ast_Struct *agg = (Ast_Struct *)sym->type_val->ast; if(node->value->kind == AST_STRUCT){ gen("struct %s{", node->name.str); global_indent++; For(agg->members){ genln(""); gen_ast(it); } global_indent--; genln("};"); } else{ // type alias } } else{ gen("// typedef "); gen_simple_decl(sym->type_val, node->name); gen(";"); } } else{ parsing_error(node->pos, "C_Codegen: Unhandled type of constant expression"); } BREAK(); } invalid_default_case; } } function String compile_string(String filecontent, String filename = "default_name"_s){ Scratch scratch(thread_ctx.scratch); OS_Heap heap = win32_os_heap_create(false, mib(4), 0); Parse_Ctx ctx = {}; ctx.init(scratch, &heap); pctx = &ctx; lex_restream(&ctx, filecontent, filename); Ast_Package *result = parse_file(); sym_insert_builtins(); pctx->resolving_package = result; gen(R"==(//------------------------------- #define NULL_POINTER 0 #define NULL_LAMBDA 0 //-------------------------------)=="); resolve_package(result); // eval_decl(result); gen_ast(result); exp_destroy(&heap); String string_result = string_flatten(scratch, &pctx->gen); return string_result; } function String compile_file(String filename){ Scratch scratch; String filecontent = os_read_file(scratch, filename); assert(filecontent.len); String result = compile_string(filecontent, filename); return result; }