struct Incomplete_Instruction{ Instruction *instruction; Ast_Decl *decl; }; function void bc_emit_expr(Bc *b, Ast *ast, Register_Index result_index){ if(!ast) return; if(!is_flag_set(ast->flags, AST_EXPR)) compiler_error(ast->pos, "Internal compiler error: Trying to emit expression but it doesn't have appropriate flag"); switch(ast->kind){ CASE(VALUE, Atom){ emit_load_constant(b, node->pos, result_index, node->value); BREAK(); } CASE(IDENT, Atom){ emit_load_constant(b, node->pos, result_index, node->resolved_decl->value); BREAK(); } CASE(BINARY, Binary){ Register_Index left_index = allocate_register(b); Register_Index right_index = allocate_register(b); bc_emit_expr(b, node->left, left_index); bc_emit_expr(b, node->right, right_index); emit_arithmetic(b, node->pos, BC_ADD_S64, left_index, right_index, result_index); release_register(b, left_index); release_register(b, right_index); BREAK(); } invalid_default_case; } } function void emit_stmt(Bc *b, Ast *ast){ switch(ast->kind){ CASE(VAR, Decl){ node->register_index = allocate_register(b); bc_emit_expr(b, node->expr, node->register_index); BREAK(); } CASE(RETURN, Return){ emit_return(b, node->pos); BREAK(); } default:{} } } function void compile_to_bc(){ Intern_String intern_main = pctx->intern("main"_s); B32 found_main = false; Bc bc = create_bytecode_interp(); Bc *b = &bc; // Scratch scratch; // auto incomplete = array_make(scratch, 512); Register_Index main_call_register = allocate_register(b); Instruction *load_main_address = emit_load_constant(b, 0, 0, {}); emit_call(b, 0, 0); For_Named(pctx->ordered_decls, ast){ switch(ast->kind){ CASE(LAMBDA, Decl){ Ast_Lambda *lambda = node->lambda; if(!lambda->scope) break; if(node->pos->file.s == "language.kl"_s) break; node->bytecode_data_position = b->instruction_pointer; For(node->lambda->args){ it->register_index = allocate_register(b); } For(lambda->scope->stmts){ emit_stmt(b, it); } For(node->lambda->args){ release_register(b, it->register_index); } if(node->name == intern_main){ found_main = true; load_main_address->constant.pointer = (U8 *)node->bytecode_data_position; load_main_address->debug_pos = node->pos; load_main_address->debug_type_flag = TYPE_POINTER; } BREAK(); } CASE(VAR, Decl){ if(node->pos->file.s == "language.kl"_s) break; node->bytecode_data_position = exp_alloc(&b->memory, node->type->size, AF_ZeroMemory); if(is_flag_set(node->flags, AST_VAR_IS_CONST)){ switch(node->type->kind){ CASE_UINT: *(U64 *)node->bytecode_data_position = bigint_as_unsigned(&node->big_int_val); break; CASE_SINT: *(S64 *)node->bytecode_data_position = bigint_as_signed(&node->big_int_val); break; CASE_FLOAT: *(F64 *)node->bytecode_data_position = node->f64_val; break; invalid_default_case; } } else if(node->expr) compiler_error(node->pos, "Todo: Global variable with non constant expression"); BREAK(); } default: {} } } if(!found_main){ compiler_error(0, "Having a [main] function is required, it's an entry point of the application"); } release_register(b, main_call_register); emit_end(b); run_bytecode_interp(b); destroy_bytecode_interp(b); }