#include "spl_sema.h" #include "spl_type.h" void spl_scope_init(spl_scope_t *scope) { vec_init(scope->scopes); vec_push(scope->scopes, (spl_scope_node_t){0}); scope->current_scope = 0; scope->root_scope = 0; } void spl_scope_drop(spl_scope_t *scope) { for (usize i = 0; i < vec_size(scope->scopes); ++i) { map_free(vec_at(scope->scopes, i).symbols); } vec_free(scope->scopes); scope->current_scope = 0; scope->root_scope = 0; } spl_scope_id_t spl_scope_alloc(spl_scope_t *scope) { spl_scope_node_t n = {0}; n.parent = scope->current_scope; map_init(n.symbols, MAP_HASH_STR, MAP_CMP_STR); vec_push(scope->scopes, n); return vec_size(scope->scopes) - 1; } bool spl_scope_insert(spl_scope_t *scope, spl_scope_id_t id, spl_symbol_t symbol) { if (!id || id >= vec_size(scope->scopes)) { LOG_FATAL("sema scope insert error"); return false; } spl_scope_node_t *node = &vec_at(scope->scopes, id); spl_symbol_t old = {0}; if (map_get(node->symbols, symbol.name, &old)) { SPL_ERROR(&(spl_dbg_node_t){0}, "duplicate symbol `%s`", symbol.name); return false; } map_put(node->symbols, symbol.name, symbol); return true; } bool spl_scope_find(spl_scope_t *scope, const char *name, spl_symbol_t *out) { if (!scope || !name || !out) return false; for (spl_scope_id_t id = scope->current_scope; id != 0; id = vec_at(scope->scopes, id).parent) { spl_scope_node_t *s = &vec_at(scope->scopes, id); if (map_get(s->symbols, name, out)) { return true; } } return false; } static inline void sema_push_scope(spl_sema_t *sema) { spl_scope_id_t new_scope = spl_scope_alloc(sema->scope); sema->store_scope = sema->scope->current_scope; sema->scope->current_scope = new_scope; } static inline void sema_pop_scope(spl_sema_t *sema) { sema->scope->current_scope = sema->store_scope; } static spl_lang_type_id_t sema_for_elem_type(spl_sema_t *sema, spl_lang_type_id_t lang_tid) { spl_lang_type_node_t *n = spl_lang_type_node(sema->type, lang_tid); if (!n) return 0; switch (n->kind) { case SPL_LANG_TYPE_ARRAY: case SPL_LANG_TYPE_SLICE: case SPL_LANG_TYPE_RANGE: case SPL_LANG_TYPE_PTR: return n->extra.elem; default: return 0; } } static void sema_collect(spl_sema_t *sema, spl_ast_node_ref_t ref) { spl_ast_node_t *n = spl_ast_node(sema->ast, ref); if (!n) return; switch (n->kind) { case SPL_AST_CONTAINER_MEMBERS: { /* root_scope 只在第一次创建,后续 module 复用 */ if (sema->scope->root_scope == 0) { spl_scope_id_t root = spl_scope_alloc(sema->scope); sema->scope->root_scope = root; } /* 进入 root_scope,再为当前 module 开一个子 scope */ sema->scope->current_scope = sema->scope->root_scope; spl_scope_id_t mod_scope = spl_scope_alloc(sema->scope); sema->scope->current_scope = mod_scope; spl_symbol_t file_sym = {.name = "$file", .kind = SPL_SYMBOL_KIND_TYPE}; file_sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, "$file", n->dbg, ref); n->resolved_def_id = file_sym.node; spl_scope_insert(sema->scope, mod_scope, file_sym); for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) { sema_collect(sema, vec_at(n->container_members.declarations, i)); } /* 故意不恢复 current_scope 保持 mod_scope 交给随后的 sema_parse 使用。 恢复由 spl_sema_run_module 统一负责 */ break; } case SPL_AST_TYPE_DECL: { spl_symbol_t sym = {.name = n->type_decl.name, .kind = SPL_SYMBOL_KIND_TYPE}; spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr); if (!te) { SPL_ERROR(&n->dbg, "type declaration `%s` missing type expression", n->type_decl.name); sema->error_count++; return; } if (te->kind == SPL_AST_TYPE_AGGREGATE) { sym.node = spl_def_alloc(sema->type, SPL_DEF_AGG, sym.name, te->dbg, ref); n->resolved_def_id = sym.node; spl_scope_insert(sema->scope, sema->scope->current_scope, sym); spl_scope_id_t old_scope = sema->scope->current_scope; spl_scope_id_t inner_scope = spl_scope_alloc(sema->scope); sema->scope->current_scope = inner_scope; for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) { sema_collect(sema, vec_at(te->type_aggregate.members, i)); } sema->scope->current_scope = old_scope; } else { sym.node = spl_def_alloc(sema->type, SPL_DEF_SCALAR, sym.name, te->dbg, ref); n->resolved_def_id = sym.node; spl_scope_insert(sema->scope, sema->scope->current_scope, sym); } break; } case SPL_AST_FN_DECL: { spl_symbol_t sym = {.name = n->fn_decl.name, .kind = SPL_SYMBOL_KIND_FN}; sym.node = spl_def_alloc(sema->type, SPL_DEF_FN, sym.name, n->dbg, ref); n->resolved_def_id = sym.node; spl_scope_insert(sema->scope, sema->scope->current_scope, sym); break; } case SPL_AST_VAR_DECL: case SPL_AST_CONST_DECL: { spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern); if (pat && pat->kind == SPL_AST_PATTERN_IDENT) { const char *name = pat->pattern_ident.name; spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR}; sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, ref); n->resolved_def_id = sym.node; spl_scope_insert(sema->scope, sema->scope->current_scope, sym); } else { SPL_ERROR(&n->dbg, "unsupported variable pattern (only simple identifier)"); sema->error_count++; } break; } case SPL_AST_TOP_LEVEL_BLOCK: if (n->top_level_block.block) { sema_collect(sema, n->top_level_block.block); } break; default: break; } } static spl_lang_type_id_t sema_parse(spl_sema_t *sema, spl_ast_node_ref_t ref) { if (ref == 0) return 0; spl_ast_node_t *n = spl_ast_node(sema->ast, ref); if (!n) return 0; switch (n->kind) { case SPL_AST_CONTAINER_MEMBERS: for (usize i = 0; i < vec_size(n->container_members.declarations); ++i) { sema_parse(sema, vec_at(n->container_members.declarations, i)); } return 0; case SPL_AST_FN_DECL: { if (n->resolved_def_id == 0) { Panic("fn `%s` not collected", n->fn_decl.name); } spl_lang_type_id_vec_t param_types; vec_init(param_types); for (usize i = 0; i < vec_size(n->fn_decl.params); ++i) { spl_ast_node_t *pd = spl_ast_node(sema->ast, vec_at(n->fn_decl.params, i)); if (pd && pd->kind == SPL_AST_PARAM_DECL && pd->param_decl.type_expr) { vec_push(param_types, sema_parse(sema, pd->param_decl.type_expr)); } else { vec_push(param_types, spl_lang_make_varargs(sema->type)); } } spl_lang_type_id_t ret_tid = sema_parse(sema, n->fn_decl.ret_type); if (ret_tid == 0) { ret_tid = spl_lang_make_unit(sema->type); } spl_lang_type_id_t fn_tid = spl_lang_make_fn( sema->type, ret_tid, vec_unsafe_get_data(param_types), vec_size(param_types)); Assert(fn_tid != 0); vec_free(param_types); spl_def_resolve(sema->type, n->resolved_def_id, fn_tid); if (n->fn_decl.body) { sema_push_scope(sema); for (usize i = 0; i < vec_size(n->fn_decl.params); ++i) { spl_ast_node_t *pd = spl_ast_node(sema->ast, vec_at(n->fn_decl.params, i)); if (pd && pd->kind == SPL_AST_PARAM_DECL) { spl_symbol_t psym = {.name = pd->param_decl.name, .kind = SPL_SYMBOL_KIND_VAR}; psym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, psym.name, pd->dbg, vec_at(n->fn_decl.params, i)); spl_lang_type_id_t p_tid = sema_parse(sema, pd->param_decl.type_expr); spl_def_resolve(sema->type, psym.node, p_tid); pd->resolved_def_id = psym.node; spl_scope_insert(sema->scope, sema->scope->current_scope, psym); } } spl_lang_type_id_t old_ret = sema->current_fn_ret_tid; sema->current_fn_ret_tid = ret_tid; sema_parse(sema, n->fn_decl.body); sema->current_fn_ret_tid = old_ret; sema_pop_scope(sema); } return fn_tid; } case SPL_AST_TYPE_DECL: { if (!n->type_decl.type_expr) break; spl_ast_node_t *te = spl_ast_node(sema->ast, n->type_decl.type_expr); if (!te) break; if (te->kind == SPL_AST_TYPE_AGGREGATE) { spl_type_member_vec_t members; vec_init(members); for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) { spl_ast_node_t *mn = spl_ast_node(sema->ast, vec_at(te->type_aggregate.members, i)); if (mn && mn->kind == SPL_AST_MEMBER_DECL) { spl_lang_type_id_t mtid = sema_parse(sema, mn->member_decl.type_expr); spl_type_member_t m = {.name = mn->member_decl.name, .type_id = spl_lang_type_get_ir_type(sema->type, mtid), .ast_node_ref = vec_at(te->type_aggregate.members, i)}; vec_push(members, m); } } spl_type_node_kind_t tk; if (strcmp(te->type_aggregate.kind_name, "struct") == 0) tk = SPL_TYPE_STRUCT; else if (strcmp(te->type_aggregate.kind_name, "union") == 0) tk = SPL_TYPE_UNION; else if (strcmp(te->type_aggregate.kind_name, "enum") == 0) tk = SPL_TYPE_ENUM; else tk = SPL_TYPE_STRUCT; spl_type_layout_t layout = {.mode = SPL_TYPE_LAYOUT_AUTO}; spl_type_id_t agg_ir = spl_type_builder_agg( sema->type, tk, &members, spl_type_builder_int(sema->type, 32, 1), layout); vec_free(members); // 创建语言级节点 spl_lang_type_node_t lang_node = {0}; switch (tk) { case SPL_TYPE_STRUCT: lang_node.kind = SPL_LANG_TYPE_STRUCT; break; case SPL_TYPE_UNION: lang_node.kind = SPL_LANG_TYPE_UNION; break; case SPL_TYPE_ENUM: lang_node.kind = SPL_LANG_TYPE_ENUM; break; case SPL_TYPE_SHAPE: lang_node.kind = SPL_LANG_TYPE_SHAPE; break; default: break; } lang_node.ir_type_id = agg_ir; vec_push(sema->type->lang_table, lang_node); spl_lang_type_id_t agg_lang = vec_size(sema->type->lang_table) - 1; spl_def_resolve(sema->type, n->resolved_def_id, agg_lang); n->resolved_type_id = agg_lang; // 存储 lang_id // 处理聚合内部的函数声明 for (usize i = 0; i < vec_size(te->type_aggregate.members); ++i) { spl_ast_node_t *mn = spl_ast_node(sema->ast, vec_at(te->type_aggregate.members, i)); if (mn && mn->kind == SPL_AST_FN_DECL) { sema_parse(sema, vec_at(te->type_aggregate.members, i)); } } } else { spl_lang_type_id_t tid = sema_parse(sema, n->type_decl.type_expr); spl_def_resolve(sema->type, n->resolved_def_id, tid); n->resolved_type_id = tid; // 存储 lang_id } break; } case SPL_AST_VAR_DECL: case SPL_AST_CONST_DECL: { spl_ast_node_t *pat = spl_ast_node(sema->ast, n->var_const_decl.pattern); if (!pat || pat->kind != SPL_AST_PATTERN_IDENT) { SPL_ERROR(&n->dbg, "unsupported variable pattern"); sema->error_count++; return 0; } const char *name = pat->pattern_ident.name; if (n->resolved_def_id == 0) { spl_symbol_t sym = {.name = name, .kind = SPL_SYMBOL_KIND_VAR}; sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, name, n->dbg, ref); n->resolved_def_id = sym.node; spl_scope_insert(sema->scope, sema->scope->current_scope, sym); } spl_lang_type_id_t decl_tid; if (n->var_const_decl.type) { decl_tid = sema_parse(sema, n->var_const_decl.type); } else { decl_tid = spl_lang_make_infer(sema->type); } if (n->var_const_decl.init_expr == 0) { SPL_ERROR(&n->dbg, "variable `%s` must be initialized", name); sema->error_count++; return 0; } spl_ast_node_t *init_node = spl_ast_node(sema->ast, n->var_const_decl.init_expr); spl_lang_type_id_t init_tid = sema_parse(sema, n->var_const_decl.init_expr); spl_lang_type_id_t coerce_result = spl_lang_type_coerce_to(sema->type, decl_tid, init_tid); if (coerce_result == 0) { SPL_ERROR(&n->dbg, "cannot coerce initializer to declared type"); sema->error_count++; return 0; } init_node->resolved_type_id = coerce_result; decl_tid = coerce_result; spl_def_resolve(sema->type, n->resolved_def_id, decl_tid); n->resolved_type_id = decl_tid; return decl_tid; } case SPL_AST_MEMBER_DECL: { if (n->member_decl.type_expr) { return sema_parse(sema, n->member_decl.type_expr); } return 0; } case SPL_AST_PARAM_DECL: { if (n->param_decl.type_expr) { return sema_parse(sema, n->param_decl.type_expr); } return 0; } case SPL_AST_EXPR_INT_LIT: { spl_lang_type_id_t ct = spl_lang_make_int(sema->type, 0, 1); n->resolved_type_id = ct; return ct; } case SPL_AST_EXPR_FLOAT_LIT: { spl_lang_type_id_t ct = spl_lang_make_float(sema->type, 0); n->resolved_type_id = ct; return ct; } case SPL_AST_EXPR_CHAR_LIT: { spl_lang_type_id_t u8 = spl_lang_make_int(sema->type, 8, 0); n->resolved_type_id = u8; return u8; } case SPL_AST_EXPR_STRING_LIT: { spl_lang_type_id_t u8 = spl_lang_make_int(sema->type, 8, 0); spl_lang_type_id_t slice = spl_lang_make_slice(sema->type, u8); n->resolved_type_id = slice; return slice; } case SPL_AST_EXPR_BOOL_LIT: { spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); n->resolved_type_id = bt; return bt; } case SPL_AST_EXPR_NULL_LIT: { spl_lang_type_id_t never = spl_lang_make_never(sema->type); spl_lang_type_id_t ptr = spl_lang_make_ptr(sema->type, never); n->resolved_type_id = ptr; return ptr; } case SPL_AST_EXPR_UNDEFINED_LIT: { spl_lang_type_id_t t = spl_lang_make_never(sema->type); n->resolved_type_id = t; return t; } case SPL_AST_EXPR_IDENT: { const char *name = n->ident.name; spl_symbol_t sym; if (!spl_scope_find(sema->scope, name, &sym)) { SPL_ERROR(&n->dbg, "undefined identifier `%s`", name); sema->error_count++; return 0; } if (sym.node == 0) { SPL_ERROR(&n->dbg, "identifier `%s` has no definition", name); sema->error_count++; return 0; } n->resolved_def_id = sym.node; spl_def_node_t *def = spl_def_node(sema->type, sym.node); if (!def) { SPL_ERROR(&n->dbg, "definition for `%s` not found", name); sema->error_count++; return 0; } n->resolved_type_id = def->lang_id; return def->lang_id; } case SPL_AST_EXPR_UNARY: { spl_lang_type_id_t operand_tid = sema_parse(sema, n->unary.operand); if (operand_tid == 0) return 0; spl_lang_type_node_t *tn = spl_lang_type_node(sema->type, operand_tid); if (!tn) return 0; switch (n->unary.op) { case SPL_UNARY_OP_MINUS: if (tn->kind != SPL_LANG_TYPE_INT && tn->kind != SPL_LANG_TYPE_FLOAT) { SPL_ERROR(&n->dbg, "unary minus requires numeric operand"); sema->error_count++; return 0; } n->resolved_type_id = operand_tid; return operand_tid; case SPL_UNARY_OP_NOT: if (tn->kind != SPL_LANG_TYPE_BOOL) { SPL_ERROR(&n->dbg, "logical not requires bool operand"); sema->error_count++; return 0; } { spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); n->resolved_type_id = bt; return bt; } case SPL_UNARY_OP_BIT_NOT: if (tn->kind != SPL_LANG_TYPE_INT) { SPL_ERROR(&n->dbg, "bitwise not requires integer operand"); sema->error_count++; return 0; } n->resolved_type_id = operand_tid; return operand_tid; case SPL_UNARY_OP_ADDRESS: { spl_lang_type_id_t ptr_tid = spl_lang_make_ptr(sema->type, operand_tid); n->resolved_type_id = ptr_tid; return ptr_tid; } default: UNREACHABLE(); } break; } case SPL_AST_EXPR_BINARY: { spl_lang_type_id_t lt = sema_parse(sema, n->binary.left); spl_lang_type_id_t rt = sema_parse(sema, n->binary.right); spl_binary_op_t op = n->binary.op; switch (op) { case SPL_OP_ASSIGN: { spl_ast_node_t *rhs = spl_ast_node(sema->ast, n->binary.right); spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, lt, rt); if (r == 0) { SPL_ERROR(&n->dbg, "assignment type mismatch"); sema->error_count++; return 0; } rhs->resolved_type_id = r; n->resolved_type_id = lt; return lt; } case SPL_OP_ASSIGN_ADD: case SPL_OP_ASSIGN_SUB: case SPL_OP_ASSIGN_MUL: case SPL_OP_ASSIGN_DIV: case SPL_OP_ASSIGN_MOD: case SPL_OP_ASSIGN_AND: case SPL_OP_ASSIGN_OR: case SPL_OP_ASSIGN_XOR: case SPL_OP_ASSIGN_LSHIFT: case SPL_OP_ASSIGN_RSHIFT: { spl_lang_type_id_t balanced = spl_lang_type_balance(sema->type, lt, rt); if (balanced == 0 || balanced != lt) { SPL_ERROR(&n->dbg, "compound assignment type mismatch"); sema->error_count++; return 0; } spl_ast_node_t *rhs = spl_ast_node(sema->ast, n->binary.right); spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, lt, rt); if (r == 0) { SPL_ERROR(&n->dbg, "compound assignment right type mismatch"); sema->error_count++; return 0; } rhs->resolved_type_id = r; n->resolved_type_id = lt; return lt; } case SPL_OP_BOOL_OR: case SPL_OP_BOOL_AND: { spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt); spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt); if (!ln || ln->kind != SPL_LANG_TYPE_BOOL || !rn || rn->kind != SPL_LANG_TYPE_BOOL) { SPL_ERROR(&n->dbg, "logical operands must be bool"); sema->error_count++; return 0; } spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); n->resolved_type_id = bt; return bt; } case SPL_OP_BIT_OR: case SPL_OP_BIT_XOR: case SPL_OP_BIT_AND: { spl_lang_type_id_t bal = spl_lang_type_balance(sema->type, lt, rt); spl_lang_type_node_t *bn = spl_lang_type_node(sema->type, bal); if (!bn || bn->kind != SPL_LANG_TYPE_INT) { SPL_ERROR(&n->dbg, "bitwise operands must be integers"); sema->error_count++; return 0; } /* 两边都 coerce 到 bal */ if (lt != bal) { spl_ast_node_t *ln = spl_ast_node(sema->ast, n->binary.left); ln->resolved_type_id = spl_lang_type_coerce_to(sema->type, bal, lt); } if (rt != bal) { spl_ast_node_t *rn = spl_ast_node(sema->ast, n->binary.right); rn->resolved_type_id = spl_lang_type_coerce_to(sema->type, bal, rt); } n->resolved_type_id = bal; return bal; } case SPL_OP_CMP_EQ: case SPL_OP_CMP_NE: case SPL_OP_CMP_LE: case SPL_OP_CMP_GE: case SPL_OP_CMP_LT: case SPL_OP_CMP_GT: { spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt); spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt); bool numeric = (ln && (ln->kind == SPL_LANG_TYPE_INT || ln->kind == SPL_LANG_TYPE_FLOAT)) && (rn && (rn->kind == SPL_LANG_TYPE_INT || rn->kind == SPL_LANG_TYPE_FLOAT)); if (!numeric && spl_lang_type_balance(sema->type, lt, rt) == 0) { SPL_ERROR(&n->dbg, "comparison operands type mismatch"); sema->error_count++; return 0; } spl_lang_type_id_t bt = spl_lang_make_bool(sema->type); n->resolved_type_id = bt; return bt; } case SPL_OP_LSHIFT: case SPL_OP_RSHIFT: { spl_lang_type_node_t *ln = spl_lang_type_node(sema->type, lt); spl_lang_type_node_t *rn = spl_lang_type_node(sema->type, rt); if (!ln || ln->kind != SPL_LANG_TYPE_INT || !rn || rn->kind != SPL_LANG_TYPE_INT) { SPL_ERROR(&n->dbg, "shift operands must be integers"); sema->error_count++; return 0; } n->resolved_type_id = lt; return lt; } case SPL_OP_ADD: case SPL_OP_SUB: case SPL_OP_MUL: case SPL_OP_DIV: case SPL_OP_MOD: { spl_lang_type_id_t bal = spl_lang_type_balance(sema->type, lt, rt); spl_lang_type_node_t *bn = spl_lang_type_node(sema->type, bal); if (!bn || (bn->kind != SPL_LANG_TYPE_INT && bn->kind != SPL_LANG_TYPE_FLOAT)) { SPL_ERROR(&n->dbg, "arithmetic operands type mismatch"); sema->error_count++; return 0; } if (lt != bal) { spl_ast_node_t *ln = spl_ast_node(sema->ast, n->binary.left); ln->resolved_type_id = spl_lang_type_coerce_to(sema->type, bal, lt); } if (rt != bal) { spl_ast_node_t *rn = spl_ast_node(sema->ast, n->binary.right); rn->resolved_type_id = spl_lang_type_coerce_to(sema->type, bal, rt); } n->resolved_type_id = bal; return bal; } case SPL_OP_RANGE: { spl_lang_type_id_t i64 = spl_lang_make_int(sema->type, 64, 1); spl_lang_type_id_t range = spl_lang_make_range(sema->type, i64); n->resolved_type_id = range; return range; } default: break; } break; } case SPL_AST_EXPR_CALL: { spl_lang_type_id_t callee_tid = sema_parse(sema, n->call.callee); spl_lang_type_node_t *fn = spl_lang_type_node(sema->type, callee_tid); if (!fn || fn->kind != SPL_LANG_TYPE_FN) { SPL_ERROR(&n->dbg, "callee is not a function"); sema->error_count++; return 0; } // 检查函数是否可变参数:最后一个参数是否为 VARARGS bool has_varargs = false; usize fixed_param_count = vec_size(fn->extra.fn.params); if (fixed_param_count > 0) { spl_lang_type_id_t last_param = vec_at(fn->extra.fn.params, fixed_param_count - 1); spl_lang_type_node_t *last_node = spl_lang_type_node(sema->type, last_param); if (last_node && last_node->kind == SPL_LANG_TYPE_VARARGS) { has_varargs = true; fixed_param_count--; // 排除 VARARGS 参数 } } if (has_varargs) { if (vec_size(n->call.args) < fixed_param_count) { SPL_ERROR(&n->dbg, "too few arguments (expected at least %zu)", fixed_param_count); sema->error_count++; } else { for (usize i = 0; i < fixed_param_count; ++i) { spl_ast_node_ref_t arg_ref = vec_at(n->call.args, i); spl_ast_node_t *arg_node = spl_ast_node(sema->ast, arg_ref); spl_lang_type_id_t arg_tid = sema_parse(sema, arg_ref); spl_lang_type_id_t param_tid = vec_at(fn->extra.fn.params, i); spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, param_tid, arg_tid); if (r == 0) { SPL_ERROR(&n->dbg, "argument %zu type mismatch", i + 1); sema->error_count++; } else { arg_node->resolved_type_id = r; } } } } else { if (vec_size(n->call.args) != vec_size(fn->extra.fn.params)) { SPL_ERROR(&n->dbg, "argument count mismatch (expected %zu, got %zu)", vec_size(fn->extra.fn.params), vec_size(n->call.args)); sema->error_count++; } else { for (usize i = 0; i < vec_size(n->call.args); ++i) { spl_ast_node_ref_t arg_ref = vec_at(n->call.args, i); spl_ast_node_t *arg_node = spl_ast_node(sema->ast, arg_ref); spl_lang_type_id_t arg_tid = sema_parse(sema, arg_ref); spl_lang_type_id_t param_tid = vec_at(fn->extra.fn.params, i); spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, param_tid, arg_tid); if (r == 0) { SPL_ERROR(&n->dbg, "argument %zu type mismatch", i + 1); sema->error_count++; } else { arg_node->resolved_type_id = r; } } } } spl_lang_type_id_t ret_tid = fn->extra.fn.ret; n->resolved_type_id = ret_tid; return ret_tid; } case SPL_AST_EXPR_FIELD: { spl_lang_type_id_t obj_tid = sema_parse(sema, n->field.obj); spl_lang_type_node_t *obj_node = spl_lang_type_node(sema->type, obj_tid); if (!obj_node) return 0; // 内建字段:数组/切片的 len if ((obj_node->kind == SPL_LANG_TYPE_ARRAY || obj_node->kind == SPL_LANG_TYPE_SLICE) && strcmp(n->field.field, "len") == 0) { spl_lang_type_id_t usize_tid = spl_lang_make_int(sema->type, sizeof(void *) * 8, 0); n->resolved_type_id = usize_tid; return usize_tid; } // 自动解引用 spl_lang_type_id_t agg_lang = obj_tid; if (obj_node->kind == SPL_LANG_TYPE_PTR) { agg_lang = obj_node->extra.elem; } spl_lang_type_node_t *agg_node = spl_lang_type_node(sema->type, agg_lang); if (!agg_node || (agg_node->kind != SPL_LANG_TYPE_STRUCT && agg_node->kind != SPL_LANG_TYPE_UNION)) { SPL_ERROR(&n->dbg, "field access on non-aggregate type"); sema->error_count++; return 0; } spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg_lang); const spl_type_member_t *member = spl_type_agg_member(sema->type, agg_ir, n->field.field); if (!member) { SPL_ERROR(&n->dbg, "no field `%s`", n->field.field); sema->error_count++; return 0; } // 将底层字段类型映射回语言级类型 spl_lang_type_id_t field_lang = 0; for (usize i = 1; i < vec_size(sema->type->lang_table); ++i) { spl_lang_type_node_t *ln = &vec_at(sema->type->lang_table, i); if (ln->ir_type_id == member->type_id) { field_lang = i; break; } } if (!field_lang) { SPL_ERROR(&n->dbg, "cannot resolve field type for `%s`", n->field.field); sema->error_count++; return 0; } n->resolved_type_id = field_lang; return field_lang; } case SPL_AST_EXPR_INDEX: { spl_lang_type_id_t obj_tid = sema_parse(sema, n->index.obj); spl_lang_type_id_t idx_tid = sema_parse(sema, n->index.index); spl_lang_type_node_t *obj_node = spl_lang_type_node(sema->type, obj_tid); if (!obj_node) return 0; spl_lang_type_id_t elem_lang = 0; switch (obj_node->kind) { case SPL_LANG_TYPE_ARRAY: case SPL_LANG_TYPE_SLICE: case SPL_LANG_TYPE_RANGE: case SPL_LANG_TYPE_PTR: elem_lang = obj_node->extra.elem; break; case SPL_LANG_TYPE_TUPLE: if (vec_size(obj_node->extra.elems) > 0) elem_lang = vec_at(obj_node->extra.elems, 0); else { SPL_ERROR(&n->dbg, "empty tuple"); sema->error_count++; return 0; } break; default: SPL_ERROR(&n->dbg, "index base must be array, pointer, slice, or tuple"); sema->error_count++; return 0; } (void)idx_tid; n->resolved_type_id = elem_lang; return elem_lang; } case SPL_AST_EXPR_SLICE: { spl_lang_type_id_t obj_tid = sema_parse(sema, n->slice.obj); if (n->slice.begin) sema_parse(sema, n->slice.begin); if (n->slice.end) sema_parse(sema, n->slice.end); spl_lang_type_node_t *obj_node = spl_lang_type_node(sema->type, obj_tid); if (!obj_node) return 0; spl_lang_type_id_t elem_lang = 0; if (obj_node->kind == SPL_LANG_TYPE_ARRAY || obj_node->kind == SPL_LANG_TYPE_PTR || obj_node->kind == SPL_LANG_TYPE_SLICE) { elem_lang = obj_node->extra.elem; } else { SPL_ERROR(&n->dbg, "slice base must be array, pointer, or slice"); sema->error_count++; return 0; } spl_lang_type_id_t slice_tid = spl_lang_make_slice(sema->type, elem_lang); n->resolved_type_id = slice_tid; return slice_tid; } case SPL_AST_EXPR_CAST: { spl_lang_type_id_t src_tid = sema_parse(sema, n->cast.expr); spl_lang_type_id_t dst_tid = sema_parse(sema, n->cast.type); spl_lang_type_node_t *src_node = spl_lang_type_node(sema->type, src_tid); if (!src_node) return 0; if (src_node->kind != SPL_LANG_TYPE_INT && src_node->kind != SPL_LANG_TYPE_FLOAT && src_node->kind != SPL_LANG_TYPE_BOOL) { SPL_ERROR(&n->dbg, "invalid cast from non-primitive type"); sema->error_count++; return 0; } n->resolved_type_id = dst_tid; return dst_tid; } case SPL_AST_EXPR_TUPLE: { spl_lang_type_id_vec_t elems; vec_init(elems); for (usize i = 0; i < vec_size(n->tuple.elems); ++i) { vec_push(elems, sema_parse(sema, vec_at(n->tuple.elems, i))); } spl_lang_type_id_t tuple = spl_lang_make_tuple(sema->type, vec_unsafe_get_data(elems), vec_size(elems)); vec_free(elems); n->resolved_type_id = tuple; return tuple; } case SPL_AST_EXPR_ARRAY_LIT: { /* elem_type 可空:匿名 .[...] 时从元素推导 */ spl_lang_type_id_t elem_tid = 0; if (n->array_literal.elem_type) { elem_tid = sema_parse(sema, n->array_literal.elem_type); } for (usize i = 0; i < vec_size(n->array_literal.elems); ++i) { spl_ast_node_ref_t elem_ref = vec_at(n->array_literal.elems, i); spl_ast_node_t *elem_node = spl_ast_node(sema->ast, elem_ref); spl_lang_type_id_t et = sema_parse(sema, elem_ref); if (elem_tid == 0) { elem_tid = et; } else { spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, elem_tid, et); if (r == 0) { SPL_ERROR(&n->dbg, "array element type mismatch"); sema->error_count++; } else { elem_node->resolved_type_id = r; } } } if (elem_tid == 0) { SPL_ERROR(&n->dbg, "cannot infer array element type " "(empty literal without element type annotation)"); sema->error_count++; return 0; } usize len; if (n->array_literal.is_underscore_len) { len = vec_size(n->array_literal.elems); } else if (n->array_literal.has_len) { len = (usize)n->array_literal.len; if (len != vec_size(n->array_literal.elems)) { SPL_ERROR(&n->dbg, "array literal length mismatch: declared %zu, got %zu", len, vec_size(n->array_literal.elems)); sema->error_count++; } } else { len = vec_size(n->array_literal.elems); } spl_lang_type_id_t arr_tid = spl_lang_make_array(sema->type, elem_tid, len); n->resolved_type_id = arr_tid; return arr_tid; } case SPL_AST_EXPR_AGGREGATE_LIT: { const char *type_name = n->aggregate_literal.name; /* 匿名 .{...}:需要类型上下文。 SEMA 当前为自底向上,尚无"预期类型"传播机制; 待上层注解散布到 init_expr 之前时启用。 结构上已统一,只需在这里读取 n->resolved_type_id 即可。 */ if (!type_name) { SPL_ERROR(&n->dbg, "anonymous aggregate literal requires expected type context " "(not yet supported)"); sema->error_count++; return 0; } spl_symbol_t sym; if (!spl_scope_find(sema->scope, type_name, &sym)) { SPL_ERROR(&n->dbg, "unknown type `%s`", type_name); sema->error_count++; return 0; } spl_def_node_t *def = spl_def_node(sema->type, sym.node); if (!def || !def->lang_id) { SPL_ERROR(&n->dbg, "type `%s` not resolved", type_name); sema->error_count++; return 0; } spl_lang_type_id_t agg_lang = def->lang_id; spl_lang_type_node_t *agg_node = spl_lang_type_node(sema->type, agg_lang); if (!agg_node || (agg_node->kind != SPL_LANG_TYPE_STRUCT && agg_node->kind != SPL_LANG_TYPE_UNION)) { SPL_ERROR(&n->dbg, "`%s` is not a struct/union", type_name); sema->error_count++; return 0; } spl_type_id_t agg_ir = spl_lang_type_get_ir_type(sema->type, agg_lang); spl_type_node_t *agg_ir_node = spl_type_node(sema->type, agg_ir); if (!agg_ir_node) { SPL_ERROR(&n->dbg, "aggregate IR type `%s` not found", type_name); sema->error_count++; return 0; } usize total_fields = vec_size(agg_ir_node->agg_type.variants); /* 记录每个字段是否被初始化,最后检查缺省 */ bool *seen = calloc(total_fields, sizeof(bool)); if (!seen) { SPL_ERROR(&n->dbg, "out of memory"); sema->error_count++; return 0; } for (usize i = 0; i < vec_size(n->aggregate_literal.fields); ++i) { spl_ast_node_t *item = spl_ast_node(sema->ast, vec_at(n->aggregate_literal.fields, i)); if (!item || item->kind != SPL_AST_STRUCT_INIT_ITEM) continue; const char *fname = item->struct_init_item.name; usize field_idx = 0; if (!spl_type_agg_member_idx(sema->type, agg_ir, fname, &field_idx)) { SPL_ERROR(&item->dbg, "no field `%s` in `%s`", fname, type_name); sema->error_count++; continue; } if (seen[field_idx]) { SPL_ERROR(&item->dbg, "duplicate field `%s` in `%s`", fname, type_name); sema->error_count++; continue; } seen[field_idx] = true; const spl_type_member_t *member = &vec_at(agg_ir_node->agg_type.variants, field_idx); /* 通过字段的 ir 类型反查 lang 类型 */ spl_lang_type_id_t expected_lang = 0; for (usize j = 1; j < vec_size(sema->type->lang_table); ++j) { spl_lang_type_node_t *ln = &vec_at(sema->type->lang_table, j); if (ln->ir_type_id == member->type_id) { expected_lang = j; break; } } if (!expected_lang) { SPL_ERROR(&item->dbg, "cannot resolve lang type for field `%s`", fname); sema->error_count++; continue; } if (!item->struct_init_item.expr) { SPL_ERROR(&item->dbg, "field `%s` requires an initializer", fname); sema->error_count++; continue; } spl_ast_node_t *fv = spl_ast_node(sema->ast, item->struct_init_item.expr); spl_lang_type_id_t field_lang = sema_parse(sema, item->struct_init_item.expr); spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, expected_lang, field_lang); if (r == 0) { SPL_ERROR(&item->dbg, "field `%s` type mismatch", fname); sema->error_count++; } else { fv->resolved_type_id = r; } } /* 检查缺省字段 */ for (usize i = 0; i < total_fields; ++i) { if (!seen[i]) { const spl_type_member_t *m = &vec_at(agg_ir_node->agg_type.variants, i); SPL_ERROR(&n->dbg, "missing field `%s` in `%s`", m->name, type_name); sema->error_count++; } } free(seen); n->resolved_type_id = agg_lang; return agg_lang; } case SPL_AST_EXPR_COMPTIME_CALL: return 0; case SPL_AST_EXPR_BLOCK: { for (usize i = 0; i < vec_size(n->block.stmts); ++i) { sema_parse(sema, vec_at(n->block.stmts, i)); } if (n->block.tail_expr) { return sema_parse(sema, n->block.tail_expr); } return 0; } case SPL_AST_EXPR_IF: { spl_lang_type_id_t cond_tid = sema_parse(sema, n->if_expr.cond); spl_lang_type_id_t bool_tid = spl_lang_make_bool(sema->type); if (spl_lang_type_coerce_to(sema->type, bool_tid, cond_tid) == 0) { SPL_ERROR(&n->dbg, "if condition must be bool"); sema->error_count++; } spl_lang_type_id_t then_t = n->if_expr.then_block ? sema_parse(sema, n->if_expr.then_block) : 0; spl_lang_type_id_t else_t = n->if_expr.else_branch ? sema_parse(sema, n->if_expr.else_branch) : 0; spl_lang_type_id_t result_t = 0; if (then_t && else_t) { result_t = spl_lang_type_balance(sema->type, then_t, else_t); if (result_t == 0) { SPL_ERROR(&n->dbg, "if branches type mismatch"); sema->error_count++; } else { if (then_t != result_t) { spl_ast_node_t *tn = spl_ast_node(sema->ast, n->if_expr.then_block); spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, result_t, then_t); if (r) tn->resolved_type_id = r; } if (else_t != result_t) { spl_ast_node_t *en = spl_ast_node(sema->ast, n->if_expr.else_branch); spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, result_t, else_t); if (r) en->resolved_type_id = r; } } } else { result_t = then_t ? then_t : else_t; } n->resolved_type_id = result_t; return result_t; } case SPL_AST_EXPR_IFVAR: { sema_parse(sema, n->ifvar_expr.var_decl); sema_parse(sema, n->ifvar_expr.then_block); if (n->ifvar_expr.else_branch) { sema_parse(sema, n->ifvar_expr.else_branch); } return 0; } case SPL_AST_EXPR_WHILE: { spl_lang_type_id_t cond_tid = sema_parse(sema, n->while_expr.cond); spl_lang_type_id_t bool_tid = spl_lang_make_bool(sema->type); if (spl_lang_type_coerce_to(sema->type, bool_tid, cond_tid) == 0) { SPL_ERROR(&n->dbg, "while condition must be bool"); sema->error_count++; } sema_parse(sema, n->while_expr.body); if (n->while_expr.else_branch) { sema_parse(sema, n->while_expr.else_branch); } return 0; } case SPL_AST_EXPR_LOOP: { sema_parse(sema, n->loop_expr.body); return 0; } case SPL_AST_EXPR_FOR: { sema_push_scope(sema); for (usize i = 0; i < vec_size(n->for_expr.iter_exprs); ++i) { spl_lang_type_id_t container_tid = sema_parse(sema, vec_at(n->for_expr.iter_exprs, i)); spl_lang_type_id_t elem_tid = sema_for_elem_type(sema, container_tid); if (i < vec_size(n->for_expr.idents)) { spl_ast_node_t *id_node = spl_ast_node(sema->ast, vec_at(n->for_expr.idents, i)); if (id_node && id_node->kind == SPL_AST_EXPR_IDENT) { const char *var_name = id_node->ident.name; if (strcmp(var_name, "_") != 0) { spl_symbol_t sym = {.name = var_name, .kind = SPL_SYMBOL_KIND_VAR}; sym.node = spl_def_alloc(sema->type, SPL_DEF_VAR, var_name, id_node->dbg, vec_at(n->for_expr.idents, i)); spl_def_resolve(sema->type, sym.node, elem_tid); spl_scope_insert(sema->scope, sema->scope->current_scope, sym); id_node->resolved_def_id = sym.node; } } } } sema_parse(sema, n->for_expr.body); if (n->for_expr.else_branch) { sema_parse(sema, n->for_expr.else_branch); } sema_pop_scope(sema); return 0; } case SPL_AST_EXPR_MATCH: { sema_parse(sema, n->match_expr.matched_expr); for (usize i = 0; i < vec_size(n->match_expr.arms); ++i) { spl_ast_node_t *arm = spl_ast_node(sema->ast, vec_at(n->match_expr.arms, i)); if (arm && arm->kind == SPL_AST_MATCH_ARM) { sema_parse(sema, arm->match_arm.pattern); sema_parse(sema, arm->match_arm.body); } } return 0; } case SPL_AST_EXPR_FN_TYPE: { spl_lang_type_id_vec_t params; vec_init(params); for (usize i = 0; i < vec_size(n->fn_type.params); ++i) { vec_push(params, sema_parse(sema, vec_at(n->fn_type.params, i))); } spl_lang_type_id_t ret_tid = sema_parse(sema, n->fn_type.ret_type); spl_lang_type_id_t fn_tid = spl_lang_make_fn(sema->type, ret_tid, vec_unsafe_get_data(params), vec_size(params)); vec_free(params); n->resolved_type_id = fn_tid; return fn_tid; } case SPL_AST_TYPE_PATH: { const char *name = n->type_path.name; spl_lang_type_id_t builtin = spl_type_lookup_builtin(sema->type, name); if (builtin != 0) { n->resolved_type_id = builtin; return builtin; } spl_symbol_t sym; if (!spl_scope_find(sema->scope, name, &sym)) { SPL_ERROR(&n->dbg, "type `%s` not found", name); sema->error_count++; return 0; } spl_def_node_t *def = spl_def_node(sema->type, sym.node); if (!def || !def->lang_id) return 0; n->resolved_type_id = def->lang_id; return def->lang_id; } case SPL_AST_TYPE_POINTER: { spl_lang_type_id_t pointee_tid = sema_parse(sema, n->type_pointer.pointee); spl_lang_type_id_t ptr_tid = spl_lang_make_ptr(sema->type, pointee_tid); n->resolved_type_id = ptr_tid; return ptr_tid; } case SPL_AST_TYPE_ARRAY: { spl_lang_type_id_t elem_tid = sema_parse(sema, n->type_array.elem_type); usize len = n->type_array.has_len ? (usize)n->type_array.len : 0; spl_lang_type_id_t arr_tid = spl_lang_make_array(sema->type, elem_tid, len); n->resolved_type_id = arr_tid; return arr_tid; } case SPL_AST_TYPE_SLICE: { spl_lang_type_id_t elem_tid = sema_parse(sema, n->type_slice.elem_type); spl_lang_type_id_t slice_tid = spl_lang_make_slice(sema->type, elem_tid); n->resolved_type_id = slice_tid; return slice_tid; } case SPL_AST_TYPE_FN: { spl_lang_type_id_vec_t params; vec_init(params); for (usize i = 0; i < vec_size(n->type_fn.params); ++i) { vec_push(params, sema_parse(sema, vec_at(n->type_fn.params, i))); } spl_lang_type_id_t ret_tid = sema_parse(sema, n->type_fn.ret_type); spl_lang_type_id_t fn_tid = spl_lang_make_fn(sema->type, ret_tid, vec_unsafe_get_data(params), vec_size(params)); vec_free(params); n->resolved_type_id = fn_tid; return fn_tid; } case SPL_AST_TYPE_PAREN: { usize count = vec_size(n->type_paren.types); if (count == 0) { spl_lang_type_id_t unit = spl_lang_make_unit(sema->type); n->resolved_type_id = unit; return unit; } if (count == 1) { return sema_parse(sema, vec_at(n->type_paren.types, 0)); } spl_lang_type_id_vec_t elems; vec_init(elems); for (usize i = 0; i < count; ++i) { vec_push(elems, sema_parse(sema, vec_at(n->type_paren.types, i))); } spl_lang_type_id_t tuple = spl_lang_make_tuple(sema->type, vec_unsafe_get_data(elems), vec_size(elems)); vec_free(elems); n->resolved_type_id = tuple; return tuple; } case SPL_AST_TYPE_AGGREGATE: { return 0; } case SPL_AST_TYPE_COMPTIME_CALL: return 0; case SPL_AST_STATEMENT_RET: { if (n->statement_ret.expr) { spl_ast_node_t *en = spl_ast_node(sema->ast, n->statement_ret.expr); spl_lang_type_id_t ret_tid = sema_parse(sema, n->statement_ret.expr); if (sema->current_fn_ret_tid != 0) { spl_lang_type_id_t r = spl_lang_type_coerce_to(sema->type, sema->current_fn_ret_tid, ret_tid); if (r == 0) { SPL_ERROR(&n->dbg, "return type mismatch"); sema->error_count++; } else { en->resolved_type_id = r; } } } return 0; } case SPL_AST_STATEMENT_BREAK: case SPL_AST_STATEMENT_CONTINUE: return 0; case SPL_AST_STATEMENT_DEFER: if (n->statement_defer.body) { sema_parse(sema, n->statement_defer.body); } return 0; case SPL_AST_STATEMENT_COMPTIME: if (n->statement_comptime.body) { sema_parse(sema, n->statement_comptime.body); } return 0; case SPL_AST_STATEMENT_DECL: if (n->statement_decl.decl) { sema_parse(sema, n->statement_decl.decl); } return 0; case SPL_AST_STATEMENT_EXPR: if (n->statement_expr.expr) { sema_parse(sema, n->statement_expr.expr); } return 0; default: return 0; } return 0; } void spl_sema_init(spl_sema_t *sema, spl_ast_t *ast, spl_type_t *type, spl_scope_t *scope) { sema->ast = ast; sema->type = type; sema->scope = scope; sema->error_count = 0; sema->current_fn_ret_tid = 0; sema->root = (spl_symbol_t){0}; sema->store_scope = 0; } void spl_sema_drop(spl_sema_t *sema) { (void)sema; } void spl_sema_run_module(spl_sema_t *sema, spl_ast_node_ref_t module_ref) { if (!sema->ast || !module_ref) return; spl_ast_node_t *mod = spl_ast_node(sema->ast, module_ref); if (!mod || mod->kind != SPL_AST_CONTAINER_MEMBERS) return; spl_scope_id_t saved = sema->scope->current_scope; sema_collect(sema, module_ref); /* 此时 current_scope == 该 module 的 mod_scope */ sema_parse(sema, module_ref); sema->scope->current_scope = saved; } void spl_sema_run(spl_sema_t *sema) { if (!sema->ast || !sema->ast->root) return; spl_ast_node_t *root = spl_ast_node(sema->ast, sema->ast->root); if (!root || root->kind != SPL_AST_ROOT) return; spl_sema_run_module(sema, root->root.members); } void spl_sema_dump(spl_sema_t *sema) { printf("Scopes:\n"); for (usize i = 1; i < vec_size(sema->scope->scopes); ++i) { spl_scope_node_t *scope = &vec_at(sema->scope->scopes, i); printf("scope[%zu] parent=%zu\n", i, scope->parent); map_for(scope->symbols, j) { spl_symbol_t *symbol = &unsafe_map_at(scope->symbols, j).val; printf(" %s -> def`%s`#%zu\n", unsafe_map_at(scope->symbols, j).key, symbol->name, symbol->node); } } printf("LangTypeTable:\n"); for (usize i = 1; i < vec_size(sema->type->lang_table); ++i) { printf(" lang_id#%zu ", i); spl_lang_type_dump(sema->type, i); printf("\n"); } printf("TypeTable:\n"); for (usize i = 1; i < vec_size(sema->type->type_table); ++i) { printf(" type_id#%zu ", i); spl_type_pure_dump(sema->type, i); printf("\n"); } printf("DefTable:\n"); for (usize i = 1; i < vec_size(sema->type->def_table); ++i) { printf(" def#%zu ", i); spl_type_def_dump(sema->type, i); printf("\n"); } }