#define gen(...) pctx->gen.addf(__VA_ARGS__) #define genln(...) do{gen("\n"); gen_indent(); gen(__VA_ARGS__); }while(0) global S32 global_indent; global S32 is_inside_struct; 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("["); if(ast->arr.size != ARRAY_SIZE_INFERRED) gen("%d", (int)ast->arr.size); gen("]"); 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_value(Value a){ switch(a.type->kind){ CASE_INT: { Scratch scratch; const char *string = bigint_to_error_string(scratch, &a.big_int_val, 10); gen("%s", string); }break; CASE_STRING: gen("LIT(\"%s\")", a.intern_val.str); break; CASE_BOOL: a.bool_val ? gen("true"):gen("false"); break; CASE_FLOAT: gen("%f", a.f64_val); break; invalid_default_case; } } function void gen_expr(Ast_Expr *ast){ switch(ast->kind){ CASE(IDENT, Atom){ gen("%s", node->intern_val.str); BREAK(); } CASE(VALUE, Atom){ gen_value(node->value); BREAK(); } CASE(INDEX, Index){ Sym *sym = resolved_get(node); if(is_array(sym->type)){ gen("("); gen("("); gen("("); gen_simple_decl(sym->type->arr.base, {}); gen("*)"); gen_expr(node->expr); gen(".data)"); gen("["); gen_expr(node->index); gen("]"); gen(")"); } else{ gen("("); gen_expr(node->expr); gen("["); gen_expr(node->index); gen("]"); 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){ 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{ if(!token_is_assign(node->op)) gen("("); gen_expr(node->left); gen("%s", name(node->op)); gen_expr(node->right); if(!token_is_assign(node->op)) gen(")"); } BREAK(); } CASE(UNARY, Unary){ gen("("); if(node->op != TK_PostIncrement && node->op != TK_PostDecrement) gen("%s", name(node->op)); gen_expr(node->expr); if(node->op == TK_PostIncrement || node->op == TK_PostDecrement) gen("%s", name(node->op)); gen(")"); 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)){ if(is_array(node->type)){ gen("(Slice){%d, ", node->exprs.len); } 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("}"); if(is_array(node->type)){ gen("}"); } } else{ gen_expr(node->name); gen("("); auto name_for_printf = (Ast_Atom *)node->name; For(node->exprs){ // @special_case @todo in the future this should be replaced // with []Any if(intern_printf == name_for_printf->intern_val && &it == node->exprs.data){ Ast_Atom *atom = (Ast_Atom *)it->item; assert(atom->kind == AST_VALUE); assert(atom->type == untyped_string); gen("\"%s\"", atom->intern_val.str); } else gen_expr(it->item); if(!node->exprs.is_last(&it)) gen(", "); } gen(")"); } BREAK(); } invalid_default_case; } } function void gen_line(Ast *node){ if(emit_line_directives) genln("#line %d", node->pos->line+1); } function void gen_ast(Ast *ast); function void gen_block(Ast_Block *block){ gen("{"); global_indent++; For(block->stmts) { gen_line(it); genln(""); gen_ast(it); } global_indent--; genln("}"); } enum { ALWAYS_EMIT_VALUE = 0, DONT_EMIT_VALUE = 1, }; function void gen_var(Intern_String name, Ast_Resolved_Type *type, Ast_Expr *expr, B32 emit_value){ if(is_array(type)){ gen("Slice %s", name.str); } else{ gen_simple_decl(type, name); } if(emit_value == DONT_EMIT_VALUE){ return; } if(expr){ gen(" = "); gen_expr(expr); } else if(is_array(type)){ gen(" = (Slice){%d, (", type->arr.size); gen_simple_decl(type, {}); gen("){}"); gen("}"); } else { // Default zero if(is_numeric(type)){ gen(" = 0"); } else { gen(" = {}"); } } } function void gen_ast(Ast *ast){ switch(ast->kind){ CASE(PACKAGE, Package){ if(emit_line_directives) genln("#line 0 \"%s\"", node->name.str); For(node->ordered) { gen_line(it); 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_var(sym->name, sym->type, node->expr, is_inside_struct ? DONT_EMIT_VALUE : ALWAYS_EMIT_VALUE); 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); switch(sym->type->kind){ CASE_FLOAT:{ gen("// F64 %s = ", node->name.str); gen_value(sym->value); } break; CASE_INT:{ gen("// constant int %s = ", node->name.str); gen_value(sym->value); }break; CASE_STRING:{ gen("// const String %s = ", node->name.str); gen_value(sym->value); }break; CASE_BOOL:{ gen("// const Bool %s = ", node->name.str); gen_value(sym->value); }break; case TYPE_LAMBDA:{ if(node->value->kind == AST_LAMBDA){ if(is_flag_set(node->flags, AST_FOREIGN)){ return; } 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_var(it->name, type, 0, DONT_EMIT_VALUE); 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(";"); } }break; case 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("typedef struct %s{", node->name.str); global_indent++; is_inside_struct++; For(agg->members){ genln(""); gen_ast(it); } For(agg->const_members){ genln(""); gen_ast(it); } is_inside_struct--; global_indent--; genln("}%s;", node->name.str); } 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", bigint_as_signed(&value_sym->big_int_val)); gen(","); } global_indent--; genln("};*/"); } else{ // Type alias } } else{ gen("// typedef "); gen_simple_decl(sym->type_val, node->name); gen(";"); } }break; default: parsing_error(node->pos, "C_Codegen: Unhandled type %s of constant expression", docname(sym->type)); } BREAK(); } default: { assert(is_flag_set(ast->flags, AST_EXPR)); gen_expr((Ast_Expr *)ast); gen(";"); } } } function String compile_string(String filecontent, String filename = "default_name"_s){ F64 total_time = os_time(); Scratch scratch(thread_ctx.scratch); OS_Heap heap = win32_os_heap_create(false, mib(4), 0); Parse_Ctx ctx = {}; parse_init(&ctx, scratch, &heap); 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 #include #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 S32 Bool; typedef struct Slice{ S64 len; void *data; }Slice; typedef struct String{ U8 *str; S64 len; }String; #define LIT(x) (String){.str=(U8 *)x, .len=sizeof(x)-1} void entry(); int main(){ entry(); } )=="); 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// Total : %f", flattening_end - total_time); 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; } typedef struct Custom_Data{ S32 thing; }Custom_Data; typedef struct Slice{ S64 len; void *data; }Slice; Slice thing = (Slice){2, (Custom_Data []){(Custom_Data ){1}, (Custom_Data ){2}}};