#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_coerce(spl_sema_t *sema, spl_lang_type_id_t to, spl_lang_type_id_t from) { if (to == 0 || from == 0) return 0; spl_lang_type_node_t *to_node = spl_lang_type_node(sema->type, to); if (!to_node) return 0; if (to_node->kind == SPL_LANG_TYPE_INFER) return from; spl_lang_type_node_t *from_node = spl_lang_type_node(sema->type, from); if (!from_node) return 0; if (from_node->kind == SPL_LANG_TYPE_INT) { spl_type_id_t from_ir = spl_lang_type_get_ir_type(sema->type, from); spl_type_node_t *from_ir_node = spl_type_node(sema->type, from_ir); if (from_ir_node && from_ir_node->int_type.bits == 0 && to_node->kind == SPL_LANG_TYPE_INT) return to; } if (from_node->kind == SPL_LANG_TYPE_FLOAT) { spl_type_id_t from_ir = spl_lang_type_get_ir_type(sema->type, from); spl_type_node_t *from_ir_node = spl_type_node(sema->type, from_ir); if (from_ir_node && from_ir_node->float_type.bits == 0 && to_node->kind == SPL_LANG_TYPE_FLOAT) return to; } if (to_node->kind == SPL_LANG_TYPE_ARRAY && from_node->kind == SPL_LANG_TYPE_ARRAY) { spl_lang_type_id_t to_elem = to_node->extra.elem; spl_lang_type_id_t from_elem = from_node->extra.elem; if (sema_coerce(sema, to_elem, from_elem) != 0) return to; } if (spl_lang_type_is_subtype(sema->type, from, to)) return to; return 0; } static spl_lang_type_id_t sema_coerce_balance(spl_sema_t *sema, spl_lang_type_id_t t1, spl_lang_type_id_t t2) { if (t1 == 0 || t2 == 0) return 0; if (t1 == t2) return t1; spl_lang_type_node_t *n1 = spl_lang_type_node(sema->type, t1); spl_lang_type_node_t *n2 = spl_lang_type_node(sema->type, t2); if (!n1 || !n2) return 0; if (n1->kind == SPL_LANG_TYPE_ANY || n2->kind == SPL_LANG_TYPE_ANY) return spl_lang_make_any(sema->type); if (n1->kind == SPL_LANG_TYPE_NEVER) return t2; if (n2->kind == SPL_LANG_TYPE_NEVER) return t1; if (spl_lang_type_is_subtype(sema->type, t1, t2)) return t2; if (spl_lang_type_is_subtype(sema->type, t2, t1)) return t1; if (n1->kind == SPL_LANG_TYPE_INT && n2->kind == SPL_LANG_TYPE_INT) { // 如果一个是另一个的子类型,直接返回父类型(已在前面通用检查中处理) // 否则符号不同且无法安全提升,返回 0 return 0; } if (n1->kind == SPL_LANG_TYPE_FLOAT && n2->kind == SPL_LANG_TYPE_FLOAT) { spl_type_id_t ir1 = spl_lang_type_get_ir_type(sema->type, t1); spl_type_id_t ir2 = spl_lang_type_get_ir_type(sema->type, t2); spl_type_node_t *irn1 = spl_type_node(sema->type, ir1); spl_type_node_t *irn2 = spl_type_node(sema->type, ir2); if (irn1 && irn2) { usize bits = irn1->float_type.bits > irn2->float_type.bits ? irn1->float_type.bits : irn2->float_type.bits; return spl_lang_make_float(sema->type, bits); } } return 0; } static bool sema_coerce_for_bool(spl_sema_t *sema, spl_lang_type_id_t from) { spl_lang_type_id_t bool_tid = spl_lang_make_bool(sema->type); return sema_coerce(sema, bool_tid, from) == bool_tid; } 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: { 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_id_t root_scope = spl_scope_alloc(sema->scope); sema->scope->current_scope = root_scope; sema->scope->root_scope = root_scope; spl_scope_insert(sema->scope, root_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)); } 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_lang_type_id_t init_tid = sema_parse(sema, n->var_const_decl.init_expr); decl_tid = sema_coerce(sema, decl_tid, init_tid); if (decl_tid == 0) { SPL_ERROR(&n->dbg, "cannot infer type for variable `%s`", name); sema->error_count++; return 0; } spl_def_resolve(sema->type, n->resolved_def_id, decl_tid); n->resolved_type_id = decl_tid; // 存储 lang_id 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; } 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: if (sema_coerce(sema, lt, rt) == 0) { SPL_ERROR(&n->dbg, "assignment type mismatch"); sema->error_count++; return 0; } 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 = sema_coerce_balance(sema, lt, rt); if (balanced == 0 || balanced != lt) { SPL_ERROR(&n->dbg, "compound assignment type mismatch"); sema->error_count++; return 0; } 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 = sema_coerce_balance(sema, 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; } 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: { // FIXME 不一定合理 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 && sema_coerce_balance(sema, 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 = sema_coerce_balance(sema, 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; } 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_lang_type_id_t arg_tid = sema_parse(sema, vec_at(n->call.args, i)); spl_lang_type_id_t param_tid = vec_at(fn->extra.fn.params, i); if (sema_coerce(sema, param_tid, arg_tid) == 0) { SPL_ERROR(&n->dbg, "argument %zu type mismatch", i + 1); sema->error_count++; } } // 额外参数不进行类型检查(或可扩展为元组类型检查) } } 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_lang_type_id_t arg_tid = sema_parse(sema, vec_at(n->call.args, i)); spl_lang_type_id_t param_tid = vec_at(fn->extra.fn.params, i); if (sema_coerce(sema, param_tid, arg_tid) == 0) { SPL_ERROR(&n->dbg, "argument %zu type mismatch", i + 1); sema->error_count++; } } } } 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: { 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_lang_type_id_t et = sema_parse(sema, vec_at(n->array_literal.elems, i)); if (elem_tid == 0) elem_tid = et; else if (sema_coerce(sema, elem_tid, et) == 0) { SPL_ERROR(&n->dbg, "array element type mismatch"); sema->error_count++; } } usize len; if (n->array_literal.is_underscore_len) { len = vec_size(n->array_literal.elems); } else { len = n->array_literal.has_len ? n->array_literal.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_ANON_ARRAY_LIT: { spl_lang_type_id_t elem_tid = 0; for (usize i = 0; i < vec_size(n->anon_array_literal.elems); ++i) { spl_lang_type_id_t et = sema_parse(sema, vec_at(n->anon_array_literal.elems, i)); if (elem_tid == 0) elem_tid = et; else if (sema_coerce(sema, elem_tid, et) == 0) { SPL_ERROR(&n->dbg, "array element type mismatch"); sema->error_count++; } } usize len = vec_size(n->anon_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; if (!type_name) { SPL_ERROR(&n->dbg, "anonymous aggregate literal not supported yet"); 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); 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; spl_lang_type_id_t field_lang = 0; if (item->struct_init_item.expr) { field_lang = sema_parse(sema, item->struct_init_item.expr); } const spl_type_member_t *member = spl_type_agg_member(sema->type, agg_ir, fname); if (!member) { SPL_ERROR(&item->dbg, "no field `%s` in `%s`", fname, type_name); sema->error_count++; continue; } // 映射到底层类型对应的语言级类型 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 field type for `%s`", fname); sema->error_count++; continue; } if (sema_coerce(sema, expected_lang, field_lang) == 0) { SPL_ERROR(&item->dbg, "field `%s` type mismatch", fname); sema->error_count++; } } 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); if (!sema_coerce_for_bool(sema, cond_tid)) { SPL_ERROR(&n->dbg, "if condition must be bool"); sema->error_count++; } sema_parse(sema, n->if_expr.then_block); if (n->if_expr.else_branch) { sema_parse(sema, n->if_expr.else_branch); } return 0; } 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); if (!sema_coerce_for_bool(sema, cond_tid)) { 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_lang_type_id_t ret_tid = sema_parse(sema, n->statement_ret.expr); if (sema->current_fn_ret_tid != 0 && sema_coerce(sema, sema->current_fn_ret_tid, ret_tid) == 0) { SPL_ERROR(&n->dbg, "return type mismatch"); sema->error_count++; } } 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(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; sema_collect(sema, root->root.members); sema_parse(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"); } }