#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_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_ENUM: case TYPE_STRUCT: { auto constant = (Ast_Const *)ast->ast->parent; auto name = constant->name; gen("%s ", name.str); }break; default: gen("%s ", name(ast)); } } function void gen_simple_decl_postfix(Ast_Resolved_Type *ast){ switch(ast->kind){ 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_ENUM: case TYPE_STRUCT:break; default: name(ast); } } 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(VALUE, Atom){ if(is_int(node->type)) gen("%lld", node->int_val); else if(is_string(node->type)) gen("LIT(\"%s\")", node->intern_val.str); else if(is_bool(node->type)) node->bool_val ? gen("true"):gen("false"); else if(is_f32(node->type)) gen("%f", node->f32_val); else if(is_float(node->type)) gen("%f", node->f64_val); else invalid_codepath; BREAK(); } CASE(INDEX, Index){ gen_expr(node->expr); gen("["); gen_expr(node->index); gen("]"); BREAK(); } CASE(BINARY, Binary){ if(node->op == TK_Dot){ Sym *sym = resolved_get(node->left); gen_expr(node->left); if(sym->type->kind == TYPE_POINTER) gen("->"); else gen("."); gen_expr(node->right); } else if(node->op == TK_ColonAssign){ // @todo: I think this needs to be a stmt Sym *sym = resolved_get(node); Ast_Atom *atom = (Ast_Atom *)node->left; assert(is_atom(atom)); gen_simple_decl(sym->type, atom->intern_val); if(node->right){ gen(" = "); gen_expr(node->right); } } else{ gen("("); gen_expr(node->left); gen("%s", name(node->op)); 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(is_struct(node->type) || is_array(node->type)){ // @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(IF, If){ For(node->ifs){ if(it->init) gen_expr(it->init); if(node->ifs.is_first(&it)){ gen("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(PASS, Pass){ unused(node); gen("//pass"); BREAK(); } CASE(BINARY,Binary){ gen_expr(node); gen(";"); BREAK(); } CASE(FOR, For){ gen("for("); if(node->init) gen_expr(node->init); gen(";"); if(node->cond) gen_expr(node->cond); gen(";"); if(node->iter) gen_expr(node->iter); gen(")"); gen_block(node->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; 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 == untyped_float){ gen("// constant F64 %s = %f;", node->name.str, sym->f64_val); } else if(sym->type == untyped_int){ gen("// constant int %s = %lld;", node->name.str, sym->int_val); } else if(sym->type == untyped_string){ gen("// const String %s = LIT(\"%s\");", node->name.str, sym->intern_val.str); } else if(sym->type == untyped_bool){ gen("// const Bool %s = %d;", node->name.str, sym->bool_val); } 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); } For(agg->const_members){ genln(""); gen_ast(it); } global_indent--; genln("};"); } else{ // Type alias } } else if(sym->type_val->kind == TYPE_ENUM){ Ast_Enum *enu = (Ast_Enum *)sym->type_val->ast; assert(enu->kind == AST_ENUM); if(node->value->kind == AST_ENUM){ gen("/*enum %s{", node->name.str); // @todo add typespec global_indent++; For(enu->members){ genln("%s", it->name.str); gen(" = "); Sym *value_sym = resolved_get(it); gen("%d", value_sym->int_val); gen(","); } 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; F64 tokenize_begin = os_time(); lex_restream(&ctx, filecontent, filename); F64 tokenize_end = os_time(); F64 parse_begin = os_time(); Ast_Package *result = parse_file(); sym_insert_builtins(); pctx->resolving_package = result; F64 parse_end = os_time(); gen(R"==( #include typedef int8_t S8; typedef int16_t S16; typedef int32_t S32; typedef int64_t S64; typedef uint8_t U8; typedef uint16_t U16; typedef uint32_t U32; typedef uint64_t U64; typedef S8 B8; typedef S16 B16; typedef S32 B32; typedef S64 B64; typedef U64 SizeU; typedef S64 SizeS; typedef float F32; typedef double F64; typedef struct String{ U8 *str; S64 len; }String; #define LIT(x) (String){.str=(U8 *)x, .len=sizeof(x)-1} )=="); F64 resolve_begin = os_time(); resolve_package(result); F64 resolve_end = os_time(); F64 codegen_begin = os_time(); gen_ast(result); F64 codegen_end = os_time(); exp_destroy(&heap); F64 flattening_begin = os_time(); String string_result = string_flatten(scratch, &pctx->gen); F64 flattening_end = os_time(); printf("\n//-------------------------------"); printf("\n// Tokenization: %f", tokenize_end - tokenize_begin); printf("\n// Parsing : %f", parse_end - parse_begin); printf("\n// Resolving : %f", resolve_end - resolve_begin); printf("\n// Codegen : %f", codegen_end - codegen_begin); printf("\n// Flattening : %f", flattening_end - flattening_begin); printf("\n//-------------------------------"); 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; }