/* spl_comp.c — SPL compiler main logic and codegen helpers */ #include "spl_comp.h" #include #include #include #include /* ---- Compiler context init/drop ---- */ void spl_comp_init(spl_comp_t *ctx) { memset(ctx, 0, sizeof(*ctx)); vec_init(ctx->toks); vec_init(ctx->scopes); vec_init(ctx->funcs); map_init(ctx->type_defs, MAP_HASH_STR, MAP_CMP_STR); map_init(ctx->const_values, MAP_HASH_STR, MAP_CMP_STR); spl_prog_init(&ctx->prog); ctx->error_msg[0] = '\0'; } void spl_comp_drop(spl_comp_t *ctx) { if (!ctx) return; spl_tok_vec_drop(&ctx->toks); vec_for(ctx->scopes, i) { vec_free(vec_at(ctx->scopes, i).vars); } vec_free(ctx->scopes); vec_free(ctx->funcs); /* Free type defs — complex, leak for now in bootstrap */ map_free(ctx->type_defs); map_free(ctx->const_values); spl_prog_drop(&ctx->prog); free(ctx->break_patches); } void spl_comp_reset(spl_comp_t *ctx) { /* Keep prog, reset everything else */ spl_tok_vec_drop(&ctx->toks); vec_init(ctx->toks); vec_for(ctx->scopes, i) { vec_free(vec_at(ctx->scopes, i).vars); } vec_free(ctx->scopes); vec_init(ctx->scopes); ctx->scope_depth = 0; ctx->tok_idx = 0; ctx->has_error = 0; ctx->error_msg[0] = '\0'; ctx->current_func_idx = -1; ctx->current_ret_type = NULL; ctx->current_local_slot = 0; ctx->in_loop = 0; ctx->break_patch_count = 0; ctx->break_patch_cap = 0; ctx->continue_target = 0; ctx->defer_count = 0; ctx->next_gdata_idx = 0; ctx->addr_of_mode = 0; free(ctx->break_patches); ctx->break_patches = NULL; } void spl_comp_error(spl_comp_t *ctx, const char *fmt, ...) { va_list args; va_start(args, fmt); vsnprintf(ctx->error_msg, COMP_ERROR_MAX - 1, fmt, args); va_end(args); ctx->has_error = 1; } /* ---- Codegen helpers ---- */ spl_val_t spl_emit(spl_comp_t *ctx, uint16_t opcode, uint16_t type, spl_val_t imm) { return spl_prog_emit(&ctx->prog, opcode, type, imm); } void spl_patch(spl_comp_t *ctx, spl_val_t addr, spl_val_t target) { if (addr < vec_size(ctx->prog.insns)) { vec_at(ctx->prog.insns, addr).imm = target; } } spl_val_t spl_emit_jmp(spl_comp_t *ctx) { /* Emit JMP with placeholder 0, return address to patch */ return spl_emit(ctx, SPL_JMP, SPL_VOID, 0); } spl_val_t spl_emit_bz(spl_comp_t *ctx) { return spl_emit(ctx, SPL_BZ, SPL_VOID, 0); } spl_val_t spl_emit_bnz(spl_comp_t *ctx) { return spl_emit(ctx, SPL_BNZ, SPL_VOID, 0); } void spl_patch_to_here(spl_comp_t *ctx, spl_val_t addr) { /* Compute relative offset: target - (source + 1) */ spl_val_t here = vec_size(ctx->prog.insns); spl_val_t offset = here - addr - 1; spl_patch(ctx, addr, offset); } /* ---- Scope management ---- */ void spl_push_scope(spl_comp_t *ctx) { spl_scope_t scope; vec_init(scope.vars); scope.depth = ++ctx->scope_depth; vec_push(ctx->scopes, scope); } void spl_pop_scope(spl_comp_t *ctx) { if (vec_size(ctx->scopes) > 0) { spl_scope_t *scope = &vec_at(ctx->scopes, vec_size(ctx->scopes) - 1); vec_for(scope->vars, i) { free(vec_at(scope->vars, i).name); } vec_free(scope->vars); ctx->scope_depth--; ctx->scopes.size--; } else { ctx->scope_depth--; } } /* ---- Variable management ---- */ int spl_declare_var(spl_comp_t *ctx, const char *name, spl_type_info_t *type, int is_const) { spl_var_info_t var; memset(&var, 0, sizeof(var)); var.name = strdup(name); var.type = type; var.is_const = is_const; var.depth = ctx->scope_depth; var.slot = ctx->current_local_slot; usize slot_count = spl_type_slot_count(type); ctx->current_local_slot += (int)slot_count; /* Add to current scope */ if (vec_size(ctx->scopes) > 0) { spl_scope_t *scope = &vec_at(ctx->scopes, vec_size(ctx->scopes) - 1); vec_push(scope->vars, var); } return var.slot; } spl_var_info_t *spl_lookup_var(spl_comp_t *ctx, const char *name) { for (int i = (int)vec_size(ctx->scopes) - 1; i >= 0; i--) { spl_scope_t *scope = &vec_at(ctx->scopes, i); /* Search in reverse order so later declarations shadow earlier ones */ for (int j = (int)vec_size(scope->vars) - 1; j >= 0; j--) { if (strcmp(vec_at(scope->vars, j).name, name) == 0) { return &vec_at(scope->vars, j); } } } return NULL; } int spl_get_var_slot(spl_comp_t *ctx, const char *name) { spl_var_info_t *v = spl_lookup_var(ctx, name); return v ? v->slot : -1; } /* ---- Function management ---- */ int spl_declare_func(spl_comp_t *ctx, const char *name, spl_type_info_t *ret_type, int nparams, int is_extern, int is_pub) { spl_func_info_t fi; memset(&fi, 0, sizeof(fi)); fi.name = strdup(name); fi.ret_type = ret_type; fi.nparams = nparams; fi.is_extern = is_extern; fi.is_pub = is_pub; if (is_extern) { fi.func_idx = -1; } else { fi.func_idx = spl_prog_add_func_simple(&ctx->prog, name, nparams); } vec_push(ctx->funcs, fi); return (int)vec_size(ctx->funcs) - 1; } int spl_lookup_func(spl_comp_t *ctx, const char *name) { vec_for(ctx->funcs, i) { if (strcmp(vec_at(ctx->funcs, i).name, name) == 0) return (int)i; } return -1; } /* ---- String/data management ---- */ int spl_add_string(spl_comp_t *ctx, const char *str) { return spl_add_global_data(ctx, (void*)str, strlen(str) + 1); } int spl_add_global_data(spl_comp_t *ctx, void *data, usize size) { return spl_prog_add_data(&ctx->prog, data, size); } /* ---- Defer ---- */ void spl_emit_defer(spl_comp_t *ctx) { /* Record current ip for later patching */ if (ctx->defer_count < DEFER_MAX) { ctx->defer_addrs[ctx->defer_count++] = vec_size(ctx->prog.insns); } } void spl_emit_defer_epilogue(spl_comp_t *ctx) { /* Emit deferコード in reverse order */ for (int i = ctx->defer_count - 1; i >= 0; i--) { /* The code after defer_addrs[i] is the defer body */ /* We need to JMP over it, but the body is inline */ /* This is a simplified approach — just mark the range */ } } /* ---- Register runtime natives ---- */ void spl_comp_register(spl_prog_t *prog) { /* Runtime support functions for compiled SPL programs go here. * For stage1 bootstrap, most operations are handled inline. * We register basic runtime helpers if needed. */ (void)prog; } /* ---- Main compilation ---- */ int spl_compile(spl_comp_t *ctx, const char *source, const char *fname) { /* Phase 1: Lex */ ctx->toks = spl_lex(source, fname); ctx->tok_idx = 0; ctx->fname = fname; ctx->source = source; /* Skip initial newlines */ while (ctx->tok_idx < vec_size(ctx->toks) && vec_at(ctx->toks, ctx->tok_idx).type == TOK_ENDLINE) ctx->tok_idx++; /* Phase 2-4: Parse and codegen */ spl_parse_prog(ctx); if (ctx->has_error) return -1; return 0; }