#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_ast(Ast *ast); 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_Decl *)ast->ast; 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); // } // } 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(node->after_type, {}); gen(")"); gen_expr(node->expr); gen(")"); BREAK(); } CASE(VAR, Decl){ gen_ast(node); BREAK(); } CASE(CALL, Call){ 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_line(Ast *node){ if(emit_line_directives) genln("#line %d", node->pos->line+1); } function void gen_stmt_scope(Ast_Scope *scope){ gen("{"); global_indent++; For(scope->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){ gen_simple_decl(type, name); if(emit_value == DONT_EMIT_VALUE){ return; } if(expr){ gen(" = "); gen_expr(expr); } else { // Default zero if(is_numeric(type)){ gen(" = 0"); } else { gen(" = {}"); } } } function void gen_ast(Ast *ast){ switch(ast->kind){ CASE(RETURN, Return){ gen("return"); if(node->expr){ gen(" "); gen_expr(node->expr); } gen(";"); BREAK(); } CASE(VAR, Decl){ gen_var(node->name, node->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_stmt_scope(it->scope); } else{ genln("else"); if(it->expr){ gen(" if("); gen_expr(it->expr); gen(")"); } gen_stmt_scope(it->scope); } } 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_stmt_scope(node->scope); BREAK(); } CASE(LAMBDA, Decl){ if(node->kind == AST_LAMBDA){ if(is_flag_set(node->flags, AST_FOREIGN)){ return; } Ast_Lambda *lambda = node->lambda; Ast_Resolved_Type *ret = node->type->func.ret; gen_simple_decl(ret, node->name); gen("("); For(lambda->args){ gen_var(it->name, it->type, 0, DONT_EMIT_VALUE); if(&it != (lambda->args.end() - 1)) gen(", "); } gen(")"); if(lambda->scope) { gen_stmt_scope(lambda->scope); } else gen(";"); } else{ gen_simple_decl(node->type, node->name); gen(" = "); gen_expr((Ast_Expr *)node->expr); gen(";"); } BREAK(); } CASE(STRUCT, Decl){ gen("typedef struct %s{", node->name.str); global_indent++; is_inside_struct++; For(node->scope->decls){ genln(""); gen_ast(it); } is_inside_struct--; global_indent--; genln("}%s;", node->name.str); BREAK(); } CASE(CONST, Decl){ switch(node->type->kind){ CASE_FLOAT:{ gen("// F64 %s = ", node->name.str); gen_value(node->value); } break; CASE_INT:{ gen("// constant int %s = ", node->name.str); gen_value(node->value); }break; CASE_STRING:{ gen("// const String %s = ", node->name.str); gen_value(node->value); }break; CASE_BOOL:{ gen("// const Bool %s = ", node->name.str); gen_value(node->value); }break; case TYPE_LAMBDA:{ }break; case TYPE_TYPE:{ }break; // 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: compiler_error(node->pos, "C_Codegen: Unhandled type %s of constant expression", docname(node->type)); } BREAK(); } default: { assert(is_flag_set(ast->flags, AST_EXPR)); gen_expr((Ast_Expr *)ast); gen(";"); } } } #if 0 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; } #endif function String compile_files(Array filename){ Scratch scratch(thread_ctx.scratch); Array files = {scratch}; For(filename){ String filecontent = os_read_file(scratch, it); assert(filecontent.len); files.add(ast_file(it, filecontent)); } F64 total_time = os_time(); OS_Heap heap = win32_os_heap_create(false, mib(16), 0); Parse_Ctx ctx = {}; parse_init(&ctx, scratch, &heap); F64 parse_begin = os_time(); Array packages = {&heap}; For(files){ parse_file(&it); Ast_Package *package = find_package(it.name, &packages); if(package){ package->decls.add(it.decls); } else { Ast_Package p = ast_package(&heap, it.name, it.decls); insert_builtin_types_into_package(&p); packages.add(p); } } F64 parse_end = os_time(); For(packages){ resolve_package(&it); } For(pctx->ordered_decls){ genln(""); gen_ast(it); } 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// Parse : %f", parse_end - parse_begin); printf("\n// Flattening : %f", flattening_end - flattening_begin); printf("\n// Total : %f", flattening_end - total_time); printf("\n//-------------------------------"); return string_result; }