#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_STRING: if(is_pointer(a.type)){ assert(a.type == type_pointer_to_char); gen("\"%s\"", a.intern_val.str); } else{ 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); if(!is_flag_set(ast->flags, AST_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_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:{ assert(is_pointer(node->type) ? node->type == type_pointer_to_char : 1); 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(); } 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){ Scratch scratch; file->filecontent = os_read_file(pctx->perm, file->filename.s); assert(file); assert(file->filecontent.len); assert(file->filename.len); pctx->currently_parsed_file = file; String name = string_chop_last_period(file->filename.s); file->name = pctx->intern(name); pctx->currently_parsed_scope = file->scope; 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; } 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->scope, decl); } pctx->currently_parsed_scope = 0; pctx->currently_parsed_file = 0; } global F64 parsing_time_begin; global F64 parsing_time_end; function void parse_files(Ast_Module *module){ parsing_time_begin = os_time(); for(S64 i = 0; i < module->files.len; i++){ auto it = module->files.data[i]; parse_file(it); } parsing_time_end = os_time(); } function void insert_type_into_file(Ast_File *p, String name, Ast_Type *type){ Intern_String string = pctx->intern(name); Ast_Decl *decl = ast_type(&null_token, string, type); decl->parent_scope = p->scope; decl->state = DECL_RESOLVED; insert_into_scope(p->scope, decl); } function void insert_builtin_types_into_file(Ast_File *p){ insert_type_into_file(p, "void"_s , type_void); insert_type_into_file(p, "Bool"_s , type_bool); insert_type_into_file(p, "String"_s, type_string); insert_type_into_file(p, "char"_s, type_char); insert_type_into_file(p, "int"_s, type_int); insert_type_into_file(p, "S8"_s, type_s8); insert_type_into_file(p, "S16"_s, type_s16); insert_type_into_file(p, "S32"_s, type_s32); insert_type_into_file(p, "S64"_s, type_s64); insert_type_into_file(p, "U8"_s, type_u8); insert_type_into_file(p, "U16"_s, type_u16); insert_type_into_file(p, "U32"_s, type_u32); insert_type_into_file(p, "U64"_s, type_u64); insert_type_into_file(p, "F32"_s, type_f32); insert_type_into_file(p, "F64"_s, type_f64); } function Ast_Module * parse_module(String filename){ Ast_Module *result = exp_alloc_type(pctx->perm, Ast_Module); result->name = pctx->intern(filename); result->files = {pctx->heap}; Ast_File *file = register_ast_file(result->name, result, true); parse_files(result); insert_builtin_types_into_file(file); 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){ resolving_time_begin = os_time(); for(S64 i = 0; i < module->files.len; i++){ Ast_File *it = module->files[i]; For_Named(it->scope->decls, jt){ resolve_name(it->scope, jt->pos, jt->name); if(jt->kind == AST_STRUCT){ type_complete(jt->type); } } } resolving_time_end = os_time(); } function void begin_compilation(){ OS_Heap *heap = exp_alloc_type(&pernament_arena, OS_Heap); *heap = win32_os_heap_create(false, mib(16), 0); Parse_Ctx *ctx = exp_alloc_type(&pernament_arena, Parse_Ctx); parse_init(ctx, &pernament_arena, heap); } global F64 generating_time_begin; global F64 generating_time_end; function String end_compilation(){ generating_time_begin = os_time(); For(pctx->ordered_decls){ genln(""); gen_ast(it); } exp_destroy(pctx->heap); String string_result = string_flatten(pctx->perm, &pctx->gen); generating_time_end = os_time(); return string_result; } #if 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; } #endif