#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_expr(Ast_Expr *ast); function void gen_indent(){ for(S32 i = 0; i < global_indent; i++) gen(" "); } function void gen_line(Ast *node){ if(emit_line_directives) genln("#line %d", node->pos->line+1); } // @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_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:{ gen_simple_decl_prefix(ast->base); break; }break; 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_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_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 B32 gen_value(Value a){ B32 result = true; 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 TYPE_CHAR: gen("\"%s\"", a.intern_val.str); break; case TYPE_STRING: case TYPE_UNTYPED_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; default: result = false; } return result; } 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_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_lambda(Intern_String name, Ast_Lambda *lambda){ gen_simple_decl(lambda->type->func.ret, 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(";"); } function void gen_expr(Ast_Expr *ast){ switch(ast->kind){ CASE(IDENT, Atom){ gen("%s", node->intern_val.str); BREAK(); } CASE(VALUE, Atom){ B32 written = gen_value(node->value); if(!written) gen("%s", node->value.intern_val.str); BREAK(); } CASE(INDEX, Index){ gen("("); gen_expr(node->expr); gen("["); gen_expr(node->index); gen("]"); gen(")"); BREAK(); } CASE(LAMBDA_EXPR, Lambda){ gen_lambda({}, node); BREAK(); } CASE(BINARY, Binary){ if(node->op == TK_Dot){ gen_expr(node->left); if(!node->type) gen("__"); else if(node->type->kind == TYPE_POINTER) gen("->"); else gen("."); gen_expr(node->right); return; } 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(); } CASE(COMPOUND, Call){ gen("("); gen_simple_decl(node->type); gen(")"); 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){ 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(is_flag_set(node->flags, AST_FOREIGN)){ gen("/*foreign*/"); } gen_lambda(node->name, node->lambda); 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(TYPE, Decl){ gen("// Type %s = ", node->name.str); gen_expr(node->expr); BREAK(); } CASE(ENUM, Decl){ gen("/*enum %s{", node->name.str); // @todo add typespec global_indent++; For(node->scope->decls){ genln("%s", it->name.str); if(it->expr){ gen(" = "); gen_expr(it->expr); } gen(","); } global_indent--; genln("};*/"); 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:{ gen("// "); gen_lambda(node->name, node->lambda); } break; invalid_default_case; } BREAK(); } default: { assert(is_flag_set(ast->flags, AST_EXPR)); gen_expr((Ast_Expr *)ast); gen(";"); } } } 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(); pctx->packages = {&heap}; For(files){ Scratch file_scratch; lex_restream(pctx, it.filecontent, it.filename); // Figure out package name // by default it's name of the file // but if you add [package name] then it's overwritten Token *token = token_get(); String filename_without_ext = {}; if(string_find(token->file.s, "."_s, MatchFlag_None, &filename_without_ext.len)){ filename_without_ext.str = token->file.str; } else filename_without_ext = token->file.s; it.name = pctx->intern(filename_without_ext); if(token_is(SAME_SCOPE) && token_is_keyword(keyword_package, 1)){ token_next(); token_next(); Token *package_token = token_expect(TK_Identifier); it.name = package_token->intern_val; } Ast_Package *package = find_package(it.name, &pctx->packages); if(package){ package->decls.add(it.decls); } else { package = ast_package(token, &heap, it.name); insert_builtin_types_into_package(package); pctx->packages.add(package); } pctx->currently_parsed_scope = package; while(token_expect(SAME_SCOPE)){ Ast_Decl *decl = parse_decl(true); if(!decl) break; set_flag(decl->flags, AST_PACKAGE_LEVEL); if(decl->kind == AST_STRUCT){ decl->type = type_type; decl->type_val = type_incomplete(decl); decl->state = DECL_RESOLVED; } insert_into_scope(package, decl); } pctx->currently_parsed_scope = 0; } F64 parse_end = os_time(); For(pctx->packages){ resolve_package(it); } #if 0 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(); } )=="); #endif 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; }