#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; global B32 should_gen_scope_name = false; function void gen_ast(Ast *ast); function bool gen_expr(Ast_Expr *ast, Ast_Type *type_of_var = 0); function void gen_indent(){ for(S32 i = 0; i < global_indent; i++) gen(" "); } global Intern_String last_filename; function void gen_line(Ast *node){ if(emit_line_directives){ genln("#line %d", node->pos->line+1); if(node->pos->file != last_filename){ last_filename = node->pos->file; gen(" \"%Q\"", last_filename); } } } function String string_scope_name(Allocator *a, Ast_Scope *scope){ String string = {}; if(!should_gen_scope_name) return string; if(scope->parent_scope) string = string_scope_name(a, scope->parent_scope); if(scope->name.str) string = string_fmt(a, "%Q%Q_", string, scope->name); return string; } function void gen_scope_name(Ast_Scope *scope){ Scratch scratch; String string = string_scope_name(scratch, scope); gen("%.*s", (int)string.len, string.str); } function String unique_name(Allocator *allocator, Ast *ast){ Scratch scratch; B32 temp = should_gen_scope_name; should_gen_scope_name = true; String result = string_scope_name(scratch, ast->parent_scope); should_gen_scope_name = temp; assert(result.len); result = string_fmt(allocator, "%Q%d", result, ast->pos->line); return result; } // @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 String string_simple_decl_prefix(Allocator *a, Ast_Type *ast, bool scope_names){ switch(ast->kind){ case TYPE_POINTER:{ String string = string_simple_decl_prefix(a, ast->base, scope_names); string = string_fmt(a, "%Q*", string); return string; }break; case TYPE_LAMBDA: return {}; break; case TYPE_ENUM: case TYPE_ARRAY: { return string_simple_decl_prefix(a, ast->base, scope_names); }break; case TYPE_SLICE:{ String string = string_simple_decl_prefix(a, ast->base, true); string = string_fmt(a, "Slice%llu ", ast->type_id); return string; }break; case TYPE_TUPLE:{ String string = string_fmt(a, "Tuple%llu ", ast->type_id); return string; }break; case TYPE_STRUCT: { auto constant = (Ast_Decl *)ast->ast; auto name = constant->name; String string = string_fmt(a, "%Q ", name); String sc = {}; if(scope_names) sc = string_scope_name(a, constant->parent_scope); return string_fmt(a, "%Q%Q", sc, string); }break; default: { String string = string_fmt(a, "%s ", name(ast)); return string; } } return {}; } function String string_simple_decl_postfix(Allocator *a, Ast_Type *ast, bool scope_names){ switch(ast->kind){ case TYPE_POINTER: return string_simple_decl_postfix(a, ast->base, scope_names); break; case TYPE_ARRAY:{ String result = string_simple_decl_postfix(a, ast->arr.base, scope_names); String string = string_fmt(a, "[%d]%Q", ast->arr.size, result); return string; }break; case TYPE_LAMBDA:break; case TYPE_SLICE: case TYPE_ENUM: case TYPE_STRUCT:break; default:break; // default: return string_from_cstring((char *)name(ast)); } return {}; } function String string_simple_decl(Allocator *a, Ast_Type *ast, Intern_String name = {}, Ast_Scope *scope = 0, bool scope_names = true){ if(ast->kind == TYPE_LAMBDA) { String prefix = string_simple_decl_prefix(a, ast->func.ret, scope_names); String string = string_fmt(a, "%Q(*%Q)(", prefix, name); For(ast->func.args){ String prefix_arg = string_simple_decl_prefix(a, it, scope_names); string = string_fmt(a, "%Q%Q", string, prefix_arg); if(&it != ast->func.args.end() - 1) string = string_fmt(a, "%Q, ", string); } string = string_fmt(a, "%Q)", string); return string; } else{ String string = string_simple_decl_prefix(a, ast, scope_names); if(name.len) { if(scope && scope_names) string = string_fmt(a, "%Q%Q", string, string_scope_name(a, scope)); string = string_fmt(a, "%Q%Q", string, name); } String postfix = string_simple_decl_postfix(a, ast, scope_names); string = string_fmt(a, "%Q%Q", string, postfix); return string; } } function void gen_simple_decl(Ast_Type *ast, Intern_String name = {}, Ast_Scope *scope = 0, bool scope_names = true){ Scratch scratch; String string = string_simple_decl(scratch, ast, name, scope, scope_names); gen("%.*s", (int)string.len, string.str); } function String gen_string_simple_decl(Allocator *a, Ast_Type *ast, String name, Ast_Scope *scope, bool scope_names){ Scratch scratch; String string = string_simple_decl(scratch, ast, pctx->intern(name), scope, scope_names); String result = string_copy(a, string); return result; } function B32 gen_value(Value a){ B32 result = true; if(is_enum(a.type)) goto integer; switch(a.type->kind){ CASE_INT: { integer: Scratch scratch; const char *string = bigint_to_error_string(scratch, &a.big_int_val, 10); gen("%s", string); }break; CASE_STRING: if(is_pointer(a.type)){ assert(a.type == type_pointer_to_char); gen("\"%Q\"", a.intern_val); } else{ gen("LIT(\"%Q\")", a.intern_val); } break; CASE_BOOL: a.bool_val ? gen("true"):gen("false"); break; CASE_FLOAT: gen("%f", a.f64_val); break; case TYPE_TYPE: { gen("%d", a.type_val->type_id); }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(Ast_Decl *decl, B32 emit_value, B32 scope_names){ if(is_flag_set(decl->flags, AST_FOREIGN)) gen("extern "); gen_simple_decl(decl->type, decl->name, decl->parent_scope, scope_names); if(is_flag_set(decl->flags, AST_FOREIGN)) return; if(emit_value == DONT_EMIT_VALUE){ return; } if(decl->expr){ gen(" = "); gen_expr(decl->expr, decl->type); } else { // Default zero if(is_numeric(decl->type)){ gen(" = 0"); } else { gen(" = {}"); } } } function void gen_lambda(Intern_String name, Ast_Lambda *lambda, B32 generate_block = true){ bool is_foreign = is_flag_set(lambda->flags, AST_FOREIGN); if(name == pctx->intern("main"_s) || name == pctx->intern("WinMain"_s)){ is_foreign = true; } gen_simple_decl(lambda->resolved_type->func.ret, name, lambda->parent_scope, !is_foreign); gen("("); For(lambda->args){ gen_var(it, DONT_EMIT_VALUE, true); if(&it != (lambda->args.end() - 1)) gen(", "); } gen(")"); if(generate_block && lambda->scope){ gen_stmt_scope(lambda->scope); } else gen(";"); } function bool gen_expr(Ast_Expr *ast, Ast_Type *type_of_var){ switch(ast->kind){ CASE(IDENT, Atom){ if(node->resolved_decl->kind == AST_MODULE_NAMESPACE || node->resolved_decl->kind == AST_FILE_NAMESPACE) return false; B32 print_scope = true; if(node->resolved_decl->lambda){ if(is_flag_set(node->resolved_decl->lambda->flags, AST_FOREIGN)) print_scope = false; } if(type_of_var && is_slice(type_of_var) && is_array(node->resolved_decl->type)){ gen("{%d, ", (int)node->resolved_decl->type->arr.size); if(print_scope) gen_scope_name(node->resolved_decl->parent_scope); gen("%Q}", node->intern_val); } else { if(print_scope) gen_scope_name(node->resolved_decl->parent_scope); gen("%Q", node->intern_val); } BREAK(); } CASE(VALUE, Atom){ B32 written = gen_value(node->value); if(!written) { gen_scope_name(node->parent_scope); gen("%Q", node->value.intern_val); } BREAK(); } CASE(INDEX, Index){ gen("("); gen_expr(node->expr); if(is_string(node->resolved_type)) if(!(type_of_var && type_of_var == type_pointer_to_char)) gen(".str"); gen("["); gen_expr(node->index); gen("]"); gen(")"); BREAK(); } CASE(LAMBDA_EXPR, Lambda){ gen_lambda({}, node); BREAK(); } CASE(BINARY, Binary){ if(node->op == TK_Dot){ if(gen_expr(node->left)){ if(node->resolved_type && node->resolved_type->kind == TYPE_POINTER) gen("->"); else gen("."); } gen_expr(node->right); return true; } else if(node->op == TK_Arrow){ gen("("); gen("("); gen_simple_decl(node->resolved_type); gen(")"); gen_expr(node->left); gen(")"); return true; } 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(VAR, Decl){ gen_ast(node); BREAK(); } CASE(LENGTH_OF, Builtin){ gen_expr(node->expr); if(is_pointer(node->expr->resolved_type)) gen("->len"); else gen(".len"); 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->resolved_type); gen(")"); gen("{"); For(node->exprs){ if(is_struct(node->resolved_type)) gen(".%Q = ", it->resolved_name); else if(is_array(node->resolved_type)) gen("[%d] = ", (int)it->resolved_index); gen_expr(it->item); if(!node->exprs.is_last(&it)) gen(", "); } gen("}"); BREAK(); } invalid_default_case; } return true; } function void gen_ast(Ast *ast){ switch(ast->kind){ CASE(RUNTIME_ASSERT, Builtin){ if(node->assert_message.len == 0) gen("assert"); else gen("assert_msg"); gen("("); gen_expr(node->expr); if(node->assert_message.len){ gen(", \"%Q\"", node->assert_message); } gen(");"); BREAK(); } CASE(RETURN, Return){ if(is_tuple(node->resolved_type)) { Scratch scratch; Intern_String var_name = pctx->intern(unique_name(scratch, node)); gen_simple_decl(node->resolved_type, var_name); gen(";"); int i = 0; For(node->expr){ genln("memcpy(&%Q.m%d, ", var_name, i); if(!is_array(it->resolved_type)) gen("&"); gen("("); gen_expr(it); gen(")"); gen(", sizeof(%Q.m%d));", var_name, i++); } genln("return %Q;", var_name); return; } assert(node->expr.len <= 1); gen("return "); For(node->expr) gen_expr(it); gen(";"); BREAK(); } CASE(VAR, Decl){ gen_var(node, is_inside_struct ? DONT_EMIT_VALUE : ALWAYS_EMIT_VALUE, true); if(!is_flag_set(ast->flags, AST_EXPR)) gen(";"); BREAK(); } CASE(IF, If){ For(node->ifs){ if(it->init) { gen_expr(it->init); gen(";"); genln(""); } 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(BREAK, Break){ unused(node); gen("break;"); 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){ gen_line(node); genln(""); if(is_flag_set(node->expr->flags, AST_FOREIGN)){ gen("/*foreign*/"); } gen_lambda(node->name, node->lambda); BREAK(); } CASE(STRUCT, Decl){ gen("struct "); gen_scope_name(node->parent_scope); gen("%Q{", node->name); global_indent++; is_inside_struct++; For(node->scope->decls){ genln(""); gen_ast(it); } is_inside_struct--; global_indent--; genln("};"); BREAK(); } CASE(TYPE, Decl){ gen("// Type %Q = ", node->name); gen_simple_decl(node->type_val); BREAK(); } CASE(ENUM, Decl){ gen("/*enum %Q{", node->name); // @todo add typespec global_indent++; For(node->scope->decls){ genln("%Q", it->name); gen(" = "); gen_value(it->value); gen(","); } global_indent--; genln("};*/"); BREAK(); } CASE(CONST, Decl){ switch(node->type->kind){ CASE_FLOAT:{ gen("// F64 %Q = ", node->name); gen_value(node->value); } break; CASE_INT:{ gen("// constant int %Q = ", node->name); gen_value(node->value); }break; CASE_STRING:{ assert(is_pointer(node->type) ? node->type == type_pointer_to_char : 1); gen("// const String %Q = ", node->name); gen_value(node->value); }break; CASE_BOOL:{ gen("// const Bool %Q = ", node->name); gen_value(node->value); }break; case TYPE_LAMBDA:{ gen("// "); gen_lambda(node->name, node->lambda); } break; invalid_default_case; } BREAK(); } CASE(VAR_UNPACK, Var_Unpack){ For(node->vars) gen_ast(it); Scratch scratch; Intern_String var_name = pctx->intern(unique_name(scratch, node)); gen_simple_decl(node->resolved_type, var_name); gen(" = "); gen_expr(node->expr); gen(";"); int i = 0; For(node->vars){ gen("memcpy((void *)&%Q, (void *)&%Q.m%d, sizeof(%Q));", it->name, var_name, i++, it->name); } BREAK(); } case AST_CONSTANT_ASSERT: case AST_MODULE_NAMESPACE: CASE(FILE_NAMESPACE, File_Namespace){unused(node); BREAK();} default: { assert(is_flag_set(ast->flags, AST_EXPR)); gen_expr((Ast_Expr *)ast); gen(";"); } } } function void parse_file(Ast_File *file){ assert(file); Scratch scratch; file->filecontent = os_read_file(pctx->perm, file->filename.s); if(file->filecontent.len == 0){ compiler_error(file->pos, "Failed to open file \"%Q\"", file->filename); } pctx->currently_parsed_file = file; String name = string_chop_last_period(file->filename.s); file->name = pctx->intern(name); pctx->currently_parsed_scope = file; lex_restream(pctx, file->filecontent, file->filename.s); while(token_expect(SAME_SCOPE)){ if(token_match_pound(pctx->intern("load"_s))){ parse_load(true); continue; } else if(token_match_pound(pctx->intern("import"_s))){ parse_import(true); continue; } Ast_Decl *decl = parse_decl(true); if(!decl) break; set_flag(decl->flags, AST_GLOBAL); if(decl->kind == AST_STRUCT){ decl->type = type_type; decl->type_val = type_incomplete(decl); decl->state = DECL_RESOLVED; } insert_into_scope(file, decl); } pctx->currently_parsed_scope = 0; pctx->currently_parsed_file = 0; } function void insert_builtin_into_scope(Ast_Scope *p, String name, Ast_Type *type){ Intern_String string = pctx->intern(name); Ast_Decl *decl = ast_type(0, string, type); type->type_id = pctx->type_ids++; decl->parent_scope = p; decl->state = DECL_RESOLVED; insert_into_scope(p, decl); pctx->all_types.add(type); } function void insert_builtin_types_into_scope(Ast_Scope *p){ insert_builtin_into_scope(p, "void"_s , type_void); insert_builtin_into_scope(p, "Bool"_s , type_bool); insert_builtin_into_scope(p, "String"_s, type_string); insert_builtin_into_scope(p, "char"_s, type_char); insert_builtin_into_scope(p, "int"_s, type_int); insert_builtin_into_scope(p, "S8"_s, type_s8); insert_builtin_into_scope(p, "S16"_s, type_s16); insert_builtin_into_scope(p, "S32"_s, type_s32); insert_builtin_into_scope(p, "S64"_s, type_s64); insert_builtin_into_scope(p, "U8"_s, type_u8); insert_builtin_into_scope(p, "U16"_s, type_u16); insert_builtin_into_scope(p, "U32"_s, type_u32); insert_builtin_into_scope(p, "U64"_s, type_u64); insert_builtin_into_scope(p, "F32"_s, type_f32); insert_builtin_into_scope(p, "F64"_s, type_f64); insert_builtin_into_scope(p, "Any"_s, type_any); insert_builtin_into_scope(p, "Type"_s, type_type); } global F64 parsing_time_begin; global F64 parsing_time_end; function void parse_all_modules(){ parsing_time_begin = os_time(); for(S64 i = 0; i < pctx->modules.len; i++){ Ast_Module *module = pctx->modules[i]; if(module->state != MODULE_REGISTERED) continue; for(S64 j = 0; j < module->all_loaded_files.len; j++){ Ast_File *file = module->all_loaded_files.data[j]; parse_file(file); } if(module != pctx->language_base_module) module->implicit_imports.add(pctx->language_base_module); module->state = MODULE_PARSED; } parsing_time_end = os_time(); } function Ast_Module * add_module(Token *pos, Intern_String filename){ For(pctx->modules){ if(it->name == filename){ log_info("Returning registered module: %Q\n", filename); return it; } } log_info("Adding module: %Q\n", filename); Ast_Module *result = ast_module(pos, filename); register_ast_file(pos, result->name, result, true); pctx->modules.add(result); return result; } global F64 resolving_time_begin; global F64 resolving_time_end; function void resolve_everything_in_module(Ast_Module *module){ if(module->state == MODULE_RESOLVED) return; resolving_time_begin = os_time(); for(S64 i = 0; i < module->all_loaded_files.len; i++){ Ast_File *file = module->all_loaded_files[i]; For(file->decls){ resolve_name(file, it->pos, it->name); if(it->kind == AST_STRUCT){ type_complete(it->type_val); } } } module->state = MODULE_RESOLVED; resolving_time_end = os_time(); } global F64 init_ctx_time_begin; global F64 init_ctx_time_end; function void begin_compilation(){ init_ctx_time_begin = os_time(); OS_Heap *heap = exp_alloc_type(&pernament_arena, OS_Heap); *heap = win32_os_heap_create(false, mib(4), 0); Parse_Ctx *ctx = exp_alloc_type(&pernament_arena, Parse_Ctx); parse_init(ctx, &pernament_arena, heap); init_ctx_time_end = os_time(); } global F64 generating_time_begin; global F64 generating_time_end; function String get_compilation_result(){ generating_time_begin = os_time(); #if 1 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; #define true 1 #define false 0 typedef struct String{ U8 *str; S64 len; }String; #define LIT(x) (String){.str=(U8 *)x, .len=sizeof(x)-1} #define assert(x) do{if(!(x))__debugbreak();}while(0) #define assert_msg(x,...) assert(x) )=="); //*(volatile int *)0 = 0; #endif For(pctx->ordered_decls){ if(it->kind == AST_STRUCT){ genln("typedef struct %Q %Q;", it->name, it->name); } } Scratch scratch; for(S64 i = 0; i < pctx->type_map.cap; i++){ Map_Key_Value *it = pctx->type_map.data + i; if(!it->occupied) continue; Ast_Type *type = (Ast_Type *)it->value; if(type->kind == TYPE_SLICE){ genln("typedef struct Slice%llu{", type->type_id); global_indent++; genln("S64 len;"); genln(""); gen_simple_decl(type->base); gen(" data;"); global_indent--; genln("} Slice%llu;", type->type_id); } else if(type->kind == TYPE_TUPLE){ genln("typedef struct Tuple%llu{", type->type_id); global_indent++; For(type->agg.members){ genln(""); // @todo remove intern from gen Intern_String name = pctx->intern(string_fmt(scratch, "m%llu", type->agg.members.get_index(&it))); gen_simple_decl(it.type, name); gen(";"); } global_indent--; genln("} Tuple%llu;", type->type_id); } } For(pctx->ordered_decls){ if(it->kind == AST_LAMBDA){ genln(""); gen_lambda(it->name, it->lambda, false); } } for(S32 i = 0; i < pctx->base_language_ordered_decl_len; i++){ Ast_Decl *it = pctx->ordered_decls[i]; genln(""); gen_ast(it); } genln("S64 type_infos_len = %d;", pctx->all_types.len); genln("Type_Info *type_infos = (Type_Info[]){"); global_indent++; For(pctx->all_types){ genln("{/*%Q*/.kind = %d, .size = %d, .align = %d, .is_unsigned = %s, .type = %d, ", typestring(it), (S32)it->kind, (S32)it->size, (S32)it->align, it->is_unsigned ? "true" : "false", it->type_id); switch(it->kind){ case TYPE_POINTER: case TYPE_SLICE: { gen(".base_type = %d", it->base->type_id); } break; case TYPE_ARRAY: { gen(".base_type = %d, ", it->base->type_id); gen(".array_size = %d", it->arr.size); }break; case TYPE_LAMBDA: { gen(".lambda_return = %d, ", it->func.ret->type_id); gen(".lambda_argument_count = %d, ", it->func.args.len); gen(".lambda_arguments = (Type_Info[%d]){", it->func.args.len); For_Named(it->func.args, arg){ gen("{.type = %d}, ", arg->type_id); } gen("}"); } break; case TYPE_STRUCT:{ gen(".struct_member_count = %d, ", it->agg.members.len); gen(".struct_members = (Type_Info_Struct_Member[]){"); For_Named(it->agg.members, m){ gen("{.name = LIT(\"%Q\"), .type = %d, .offset = %d}, ", m.name, m.type->type_id, m.offset); } gen("}"); }break; default: {} // invalid_default_case; } gen("},"); } global_indent--; gen("};"); for(S32 i = pctx->base_language_ordered_decl_len; i < pctx->ordered_decls.len; i++){ Ast_Decl *it = pctx->ordered_decls[i]; genln(""); gen_ast(it); } String string_result = string_flatten(pctx->perm, &pctx->gen); generating_time_end = os_time(); return string_result; } function void compiler_cleanup(){ exp_destroy(pctx->heap); }